[PATCH 1 of 1 RESEND] color: add support for Windows consoles

Brodie Rao dackze at gmail.com
Tue Apr 6 10:52:42 CDT 2010


On Apr 6, 2010, at 10:47 AM, steve at borho.org wrote:

> # HG changeset patch
> # User Steve Borho <steve at borho.org>
> # Date 1270561759 18000
> # Node ID 89c4c895bddc709c3f680dc0e07a73449608e2c8
> # Parent  06ede55eb9b0f0df9775b15291fd64d7b3255f76
> color: add support for Windows consoles
> 
> Introduces ui.color configurable with values 'auto', 'ansi', or 'win32'.  Any
> other value disables coloring.  When 'auto' is selected, the win32 console
> method will be used if the win32console Python module is detected (requires
> pywin32 to be installed).

Why ui.color? Why not color.mode or color.format?

It also seems a little confusing considering there's also --color which takes auto, always, and never, but doesn't have anything to do with the output format.

> 
> diff --git a/hgext/color.py b/hgext/color.py
> --- a/hgext/color.py
> +++ b/hgext/color.py
> @@ -150,19 +150,35 @@
>         return ''.join(style(a, label) for a, label in _buffers.pop())
>     return ''.join(a for a, label in _buffers.pop())
> 
> +mode = 'ansi'
> def write(orig, *args, **opts):
>     label = opts.get('label', '')
>     global _buffers
>     if _buffers:
>         _buffers[-1].extend([(str(a), label) for a in args])
> +    elif mode == 'win32':
> +        for a in args:
> +            win32print(a, orig, **opts)
>     else:
>         return orig(*[style(str(a), label) for a in args], **opts)
> 
> def write_err(orig, *args, **opts):
>     label = opts.get('label', '')
> -    return orig(*[style(str(a), label) for a in args], **opts)
> +    if mode == 'win32':
> +        for a in args:
> +            win32print(a, orig, **opts)
> +    else:
> +        return orig(*[style(str(a), label) for a in args], **opts)
> 
> def uisetup(ui):
> +    global mode
> +    mode = ui.config('ui', 'color', 'auto')
> +    if mode == 'auto':
> +        mode = _w32effects and 'win32' or 'ansi'

What if someone's on win32 but is using an ANSI terminal?

> +    if mode == 'win32':
> +        _effects.update(_w32effects)
> +    elif mode != 'ansi':
> +        return
>     def colorcmd(orig, ui_, opts, cmd, cmdfunc):
>         if (opts['color'] == 'always' or
>             (opts['color'] == 'auto' and (os.environ.get('TERM') != 'dumb'
> @@ -180,3 +196,64 @@
> 
> commands.globalopts.append(('', 'color', 'auto',
>                             _("when to colorize (always, auto, or never)")))
> +
> +try:
> +    import re
> +    from win32console import *
> +
> +    # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
> +    _w32effects = {
> +        'none': 0,
> +        'black': 0,
> +        'red': FOREGROUND_RED,
> +        'green': FOREGROUND_GREEN,
> +        'yellow': FOREGROUND_RED | FOREGROUND_GREEN,
> +        'blue': FOREGROUND_BLUE,
> +        'magenta': FOREGROUND_BLUE | FOREGROUND_RED,
> +        'cyan': FOREGROUND_BLUE | FOREGROUND_GREEN,
> +        'white': FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
> +        'bold': FOREGROUND_INTENSITY,
> +        'black_background': 0,
> +        'red_background': BACKGROUND_RED,
> +        'green_background': BACKGROUND_GREEN,
> +        'blue_background': BACKGROUND_BLUE,
> +        'cyan_background': BACKGROUND_BLUE | BACKGROUND_GREEN,
> +        'bold_background': FOREGROUND_INTENSITY,
> +        'underline': COMMON_LVB_UNDERSCORE,     # double-byte charsets only
> +        'inverse': COMMON_LVB_REVERSE_VIDEO,    # double-byte charsets only
> +    }
> +
> +    stdout = GetStdHandle(STD_OUTPUT_HANDLE)
> +    origattr = stdout.GetConsoleScreenBufferInfo()['Attributes']
> +    ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)', re.MULTILINE | re.DOTALL)
> +
> +    def win32print(text, orig, **opts):
> +        label = opts.get('label', '')
> +        attr = 0
> +
> +        # determine console attributes based on labels
> +        for l in label.split():
> +            style = _styles.get(l, '')
> +            for effect in style.split():
> +                attr |= _w32effects[effect]
> +
> +        # hack to ensure regexp finds data
> +        if not text.startswith('\033['):
> +            text = '\033[m' + text
> +
> +        # Look for ANSI-like codes embedded in text
> +        m = re.match(ansire, text)
> +        while m:
> +            for sattr in m.group(1).split(';'):
> +                if sattr:
> +                    val = int(sattr)
> +                    attr = val and attr|val or 0
> +            stdout.SetConsoleTextAttribute(attr or origattr)
> +            orig(m.group(2), **opts)
> +            m = re.match(ansire, m.group(3))
> +
> +        # Explicity reset original attributes
> +        stdout.SetConsoleTextAttribute(origattr)
> +
> +except ImportError:
> +    _w32effects = None
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel



More information about the Mercurial-devel mailing list