5

I'm writing a program in Python using the curses module in the standard library.

I want my program to just exit if it can't use custom colors I specify with RGB triples.

So I have some starter code that looks like:

import curses

def main(stdscr):
  if not curses.can_change_color():
    raise Exception('Cannot change color')

  curses.init_color(curses.COLOR_BLACK, 999,   0,   0)
  curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE)
  curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_BLACK)
  stdscr.addstr('hello', curses.color_pair(1))
  stdscr.addstr(' world', curses.color_pair(2))
  stdscr.getch()

curses.wrapper(main)

And the result I get is:

enter image description here

I expected the black to be replaced by red.

Am I misunderstanding the docs? How can I get curses to respect custom RGB colors I want to use? Or at least fail and tell me that the terminal doesn't support it?

The docs for curses here seem to suggest that on failure it will return an error, and the CPython source seems to propagate curses errors pretty faithfully.

In case it is relevant, I'm on OS X 10.11, and I'm testing on Python3 I installed with Homebrew. But I get the same effect with OS X's builtin Python interpreter as well.

EDIT:

Slightly modified sample code to display color content:

import curses

def main(stdscr):
  if not curses.can_change_color():
    raise Exception('Cannot change color')

  stdscr.addstr(1, 0, repr(curses.color_content(curses.COLOR_BLACK)))
  curses.init_color(curses.COLOR_BLACK, 999,   0,   0)
  curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE)
  curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_BLACK)
  stdscr.addstr(0, 0, 'hello', curses.color_pair(1))
  stdscr.addstr(' world', curses.color_pair(2))
  stdscr.addstr(2, 0, repr(curses.color_content(curses.COLOR_BLACK)))
  stdscr.getch()

curses.wrapper(main)

The result this time is: enter image description here

math4tots
  • 8,540
  • 14
  • 58
  • 95
  • Can you check a before/after with [`curses.color_content`](https://docs.python.org/3/library/curses.html#curses.color_content)? – Jongware Apr 22 '16 at 20:37
  • 1
    @RadLexus The color content seems to be updated, it's set to (0, 0, 0) before, and when checked again is set to (999, 0, 0) – math4tots Apr 22 '16 at 20:40
  • Isn't `curses` supposed to only support, like, 16 basic colors like terminals did when it was designed? – ivan_pozdeev Apr 22 '16 at 20:45
  • @ivan_pozdeev: `curses` is just a wrapper around ncurses these days, which is much more capable. – Ignacio Vazquez-Abrams Apr 22 '16 at 20:46
  • Related: http://stackoverflow.com/questions/18341685/defining-a-new-color-in-ncurses – ivan_pozdeev Apr 22 '16 at 20:49
  • @ivan_pozdeev: that answer suggests changing a default `TERM`, but mine is already set to `TERM=xterm-256color` and it doesn't work. – Jongware Apr 22 '16 at 20:59
  • @math4tots which `curses` wrapper package are you using? In PyPI, there's at least a dozen. – ivan_pozdeev Apr 22 '16 at 21:13
  • 1
    @ivan_pozdeev Im using the default one that comes installed when you install Python on a Mac. The source for it lives in the CPython repo. Not sure if every standard lib module comes by default in Linux distros tho – math4tots Apr 22 '16 at 21:15

1 Answers1

1

The screenshot may be of Terminal.app; in a quick check it does not honor the escape sequences used for changing color. On the other hand, iTerm2 does use those escape sequences.

If you're using Terminal.app, setting TERM to xterm-256color is pointless, due to the large number of differences versus xterm. There's discussion in the terminal database as commentary that you may find interesting.

The relevant features which curses uses to decide if the terminal can change color are ccc and initc. Those capabilities are not defined in the nsterm terminal descriptions. The terminal descriptions use the xterm+256setaf building block rather than xterm+256color, which infocmp shows are different:

    comparing xterm+256setaf to xterm+256color.
        comparing booleans.
            ccc: F:T.
        comparing numbers.
        comparing strings.
            initc: NULL, '\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\'.
            oc: NULL, '\E]104\007'.
            op: '\E[39;49m', NULL.
Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
  • 1
    I'm outside at the moment so will test it when I get back, but if I remember the docs right, I think wrapper calls start_color if it is supported in the current env – math4tots Apr 22 '16 at 21:17