After a seemingly-fabulous start, I almost immediately hit a stumbling block which has stoppered me since my last post. The problem: awesome, soothing colors in an actual xterm; angry fruit salad fail in iTerm. I have just now worked out the problem.
The problem was not that iTerm didn’t have its terminal mode set to xterm-256color. The problem was also not that I didn’t have TERM set to xterm-256color. The problem was that, unlike xterm itself, iTerm is not capable of redefining colors.
A digression on color in curses programming: you can’t just say “make this text blue”, even though the standard curses libraries define a constant COLOR_BLUE for you to use as a handle on things you want to be blue. You must define foreground/background pairs of colors, and then say “make this text be drawn with this pair”.
Dropping down a level, the predefined color constants simply evaluate to color numbers, and so, of course, you can define a pair by using bare color numbers as well. In fact, if you want to work in high-color mode, you’ll have to do so because there are only 8 constants defined. This is where my problems begin. Well, actually, they start here:
curses.init_color(color_number, r, g, b)
- Changes the definition of a color, taking the number of the color to be changed followed by three RGB values (for the amounts of red, green, and blue components). The value of color_number must be between 0 and COLORS. Each of r, g, b, must be a value between 0 and 1000. When init_color() is used, all occurrences of that color on the screen immediately change to the new definition. This function is a no-op on most terminals; it is active only if can_change_color() returns 1.
Since I knew I wanted to play with high-color, so after asking xterm if can_change_color() was true in the REPL, I blithely started defining my own colors, starting with a color_number of 1. I then completely forgot about this part:
This function is a no-op on most terminals
I never asked iTerm about can_change_color(). It can’t. And since it can’t, it turns out that it predefines 256 colors for you, laid out along a standard color cube with a grayscale ramp at the end. I had also expected init_color() to fail loudly (because most things do), even though the docs clearly define it as a no-op. So it happily no-opped away, and all my “custom” color pairs were set up using the predefined colors.
And since I was defining a big gradient grid using 11 colors, every one of the color numbers in my pair definitions fell within the standard 16 color gamut.
The lesson: if you’re going to play with not only high-color, but custom colors, be sure to test for can_change_color() in your code, and have an alternate set of color pairs set up for terminals which can’t define custom colors.