[PATCH] color: add support for terminfo-based attributes and color

Danek Duvall duvall at comfychair.org
Sun Aug 23 03:06:00 CDT 2009


I really wanted to be able to use specific colors on my 256-color xterm, so
I whipped up some changes to allow you to use any color terminfo can
address for a terminal.  The attached patch allows you to turn off "ecma48"
to use the new code.  It also allows you to define color names, like

    [color]
    ecma48 = False
    color.pink = 207
    diff.hunk = pink

If there's interest, I can make the appropriate changes to the module
docstring, too.

Thanks,
Danek
-------------- next part --------------
# HG changeset patch
# User Danek Duvall <danek.duvall at sun.com>
# Date 1251013866 25200
# Node ID 767457cb517c9fd3176422f2d8f1c2c584e95427
# Parent  37042e8b3b342b2e380d8be3e3f7692584c92d33
color: add support for terminfo-based attributes and color

diff --git a/hgext/color.py b/hgext/color.py
--- a/hgext/color.py
+++ b/hgext/color.py
@@ -63,6 +63,7 @@ import itertools
 
 from mercurial import cmdutil, commands, extensions, error
 from mercurial.i18n import _
+import curses
 
 # start and stop parameters for effects
 _effect_params = {'none': 0,
@@ -87,11 +88,51 @@ _effect_params = {'none': 0,
                   'cyan_background': 46,
                   'white_background': 47}
 
+# Mapping from effect name to terminfo attribute name or color number
+_terminfo_params = {'none': (True, 'sgr0'),
+                    'standout': (True, 'smso'),
+                    'underline': (True, 'smul'),
+                    'reverse': (True, 'rev'),
+                    'blink': (True, 'blink'),
+                    'dim': (True, 'dim'),
+                    'bold': (True, 'bold'),
+                    'invisible': (True, 'invis'),
+                    'black': (False, curses.COLOR_BLACK),
+                    'red': (False, curses.COLOR_RED),
+                    'green': (False, curses.COLOR_GREEN),
+                    'yellow': (False, curses.COLOR_YELLOW),
+                    'blue': (False, curses.COLOR_BLUE),
+                    'magenta': (False, curses.COLOR_MAGENTA),
+                    'cyan': (False, curses.COLOR_CYAN),
+                    'white': (False, curses.COLOR_WHITE)}
+
+# If True, use ECMA-48 codes directly; if False, use terminfo
+_ecma48 = True
+
 def render_effects(text, effects):
     'Wrap text in commands to turn on each effect.'
-    start = [str(_effect_params[e]) for e in ['none'] + effects]
-    start = '\033[' + ';'.join(start) + 'm'
-    stop = '\033[' + str(_effect_params['none']) + 'm'
+    if _ecma48:
+        start = [str(_effect_params[e]) for e in ['none'] + effects]
+        start = '\033[' + ';'.join(start) + 'm'
+        stop = '\033[' + str(_effect_params['none']) + 'm'
+    else:
+        def effect_str(effect):
+            bg = False
+            if effect.endswith('_background'):
+                bg = True
+                effect = effect[:-11]
+            attr, val = _terminfo_params[effect]
+            if attr:
+                return curses.tigetstr(val)
+            elif bg:
+                return curses.tparm(curses.tigetstr('setab'), val)
+            else:
+                return curses.tparm(curses.tigetstr('setaf'), val)
+        start = ''.join([
+            effect_str(effect)
+            for effect in ['none'] + effects
+        ])
+        stop = effect_str('none')
     return ''.join([start, text, stop])
 
 def colorstatus(orig, ui, repo, *pats, **opts):
@@ -225,6 +266,28 @@ def uisetup(ui):
     '''Initialize the extension.'''
     global _ui
     _ui = ui
+
+    _terminfo_params.update(dict((
+        (key[6:], (False, int(val)))
+        for key, val in ui.configitems('color')
+        if key.startswith('color.')
+    )))
+    global _ecma48
+    _ecma48 = ui.configbool('color', 'ecma48')
+    if not _ecma48:
+        curses.setupterm()
+        for key, (b, e) in _terminfo_params.items():
+            if not b:
+                continue
+            if not curses.tigetstr(e):
+                # Most terminals don't support dim, invis, etc, so don't be
+                # noisy.
+                ui.debug(_("No terminfo entry for %s\n") % e)
+                del _terminfo_params[key]
+        if not curses.tigetstr('setaf') or not curses.tigetstr('setab'):
+            ui.warn(_("No terminfo entry for setab/setaf: reverting to ECMA-48 color\n"))
+            _ecma48 = True
+
     _setupcmd(ui, 'diff', commands.table, colordiff, _diff_effects)
     _setupcmd(ui, 'incoming', commands.table, None, _diff_effects)
     _setupcmd(ui, 'log', commands.table, None, _diff_effects)
@@ -277,7 +340,10 @@ def _setupcmd(ui, cmd, table, func, effe
         if effects:
             good = []
             for e in effects:
-                if e in _effect_params:
+                if _ecma48 and e in _effect_params:
+                    good.append(e)
+                elif not _ecma48 and (e in _terminfo_params or
+                                      e[:-11] in _terminfo_params):
                     good.append(e)
                 else:
                     ui.warn(_("ignoring unknown color/effect %r "


More information about the Mercurial-devel mailing list