import curses colors = {} _colors = [] _pairs = {} index = 1 attributes = { 'bold': curses.A_BOLD, 'reverse': curses.A_REVERSE, 'normal': curses.A_NORMAL, 'underline': curses.A_UNDERLINE, 'dim': curses.A_DIM, 'standout': curses.A_STANDOUT, } inited = False default_color = True ascii_map = { '*': 'bold', } rev_ascii_map = { 'bold': '*', } def add_color(name, value, abbrev): colors[name] = value ascii_map[abbrev] = name rev_ascii_map[name] = abbrev def iter256(): for r in range(0, 6): for g in range(0, 6): for b in range(0, 6): if r >= g and g > b: name = 'yellow' elif r >= b and b - g > 1: name = 'magenta' elif b >= g and g - r > 2: name = 'cyan' elif b >= r and r > g: name = 'magenta' elif g >= r and r - b > 2: name = 'yellow' elif g >= b and b - r > 1: name = 'cyan' elif r > b and r > g: name = 'red' elif g > b and g > r: name = 'green' elif b > r and b > g: name = 'blue' else: continue yield (name, r, g, b) raise StopIteration def color256(name, fallback, abbrev, r, g, b): name2 = '%s%d%d%d' % (name, r, g, b) abbrev2 = '%s%d%d%d' % (abbrev, r, g, b) if curses.COLORS == 256: value = 16 + r * 36 + g * 6 + b if curses.can_change_color(): try: curses.init_color(value, r * 200, g * 200, b* 200) except: raise Exception("arghh: %d, %d, %d, %d", value, r * 200, g * 200, b * 200) else: value = fallback add_color(name2, value, abbrev2) # PUBLIC METHODS def init(): global _pairs, inited if inited: return add_color('cyan', curses.COLOR_CYAN, 'c') add_color('blue', curses.COLOR_BLUE, 'b') add_color('green', curses.COLOR_GREEN, 'g') add_color('red', curses.COLOR_RED, 'r') add_color('yellow', curses.COLOR_YELLOW, 'y') add_color('magenta', curses.COLOR_MAGENTA, 'm') add_color('black', curses.COLOR_BLACK, 'B') add_color('white', curses.COLOR_WHITE, 'w') if default_color: colors['default'] = -1 ascii_map['d'] = 'default' rev_ascii_map['default'] = 'd' inited = True for i in range(0, 256): name = 'f%02x' % i abbrev = 'f%02x' % i add_color(name, i, abbrev) # GREY for i in range(0, 24): name2 = 'grey%d' % i abbrev2 = 'G%d' % i if curses.COLORS == 256: value = 232 + i if curses.can_change_color(): try: curses.init_color(value, i * 41, i * 41, i * 41) except: raise Exception("arghh: %d, %d, %d, %d", value, i * 41, i * 41, i * 41) else: value = curses.COLOR_WHITE add_color(name2, value, abbrev2) for name, r, g, b in iter256(): color256(name, colors[name], rev_ascii_map[name], r, g, b) def build(fg, bg, *attr): v = curses.A_NORMAL | pairs(fg, bg) for x in attr: if type(x) == type(''): x = attributes[x] v = v | x return v return build_attr(cattr, *attr) # PRIVATE METHODS def pairs(fg, bg): if not curses.has_colors(): return curses.color_pair(0) global index fgi = colors.get(fg, colors['white']) bgi = colors.get(bg, colors['black']) key = (fgi, bgi) if key not in _pairs: assert index < curses.COLOR_PAIRS, "too many colors" assert type(fgi) == type(0), "illegal fgi: %r" % fgi assert type(bgi) == type(0), "illegal bgi: %r" % bgi try: curses.init_pair(index, fgi, bgi) except: raise Exception('failed to init %d,%d,%d' % (index, fgi, bgi)) _pairs[key] = curses.color_pair(index) _colors.append(key) index = len(_colors) + 1 return _pairs[key]