[PATCH 1 of 1 STABLE] color: port to using ctypes (issue2687)

Adrian Buehlmann adrian at cadifra.com
Thu Mar 10 18:35:48 CST 2011


On 2011-03-11 01:16, Adrian Buehlmann wrote:
> # HG changeset patch
> # User Adrian Buehlmann <adrian at cadifra.com>
> # Date 1299801144 -3600
> # Branch stable
> # Node ID 131f8aa592d8977c0a3d686d83113be6bfef3cc6
> # Parent  8e94a1b4e9a48ec37c54eea39b4076ba302d085f
> color: port to using ctypes (issue2687)
> 
> replacing usage of pywin32, which was removed
> for Mercurial 1.8
> 
> diff --git a/hgext/color.py b/hgext/color.py
> --- a/hgext/color.py
> +++ b/hgext/color.py
> @@ -232,51 +232,89 @@ def extsetup(ui):
>           _("when to colorize (boolean, always, auto, or never)"),
>           _('TYPE')))
>  
> -try:
> -    import re, pywintypes, win32console as win32c
> +if os.name != 'nt':
> +    w32effects = None
> +else:
> +    import re, ctypes
> +
> +    _kernel32 = ctypes.windll.kernel32
> +
> +    _WORD = ctypes.c_ushort
> +
> +    _INVALID_HANDLE_VALUE = -1
> +
> +    class _COORD(ctypes.Structure):
> +        _fields_ = [('X', ctypes.c_short),
> +                    ('Y', ctypes.c_short)]
> +
> +    class _SMALL_RECT(ctypes.Structure):
> +        _fields_ = [('Left', ctypes.c_short),
> +                    ('Top', ctypes.c_short),
> +                    ('Right', ctypes.c_short),
> +                    ('Bottom', ctypes.c_short)]
> +
> +    class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
> +        _fields_ = [('dwSize', _COORD),
> +                    ('dwCursorPosition', _COORD),
> +                    ('wAttributes', _WORD),
> +                    ('srWindow', _SMALL_RECT),
> +                    ('dwMaximumWindowSize', _COORD)]
> +
> +    _STD_OUTPUT_HANDLE = 0xfffffff5L # (DWORD)-11
> +    _STD_ERROR_HANDLE = 0xfffffff4L  # (DWORD)-12
> +
> +    _FOREGROUND_BLUE = 0x0001
> +    _FOREGROUND_GREEN = 0x0002
> +    _FOREGROUND_RED = 0x0004
> +    _FOREGROUND_INTENSITY = 0x0008
> +
> +    _BACKGROUND_BLUE = 0x0010
> +    _BACKGROUND_GREEN = 0x0020
> +    _BACKGROUND_RED = 0x0040
> +    _BACKGROUND_INTENSITY = 0x0080
> +
> +    _COMMON_LVB_REVERSE_VIDEO = 0x4000
> +    _COMMON_LVB_UNDERSCORE = 0x8000
>  
>      # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
>      w32effects = {
>          'none': -1,
>          'black': 0,
> -        'red': win32c.FOREGROUND_RED,
> -        'green': win32c.FOREGROUND_GREEN,
> -        'yellow': win32c.FOREGROUND_RED | win32c.FOREGROUND_GREEN,
> -        'blue': win32c.FOREGROUND_BLUE,
> -        'magenta': win32c.FOREGROUND_BLUE | win32c.FOREGROUND_RED,
> -        'cyan': win32c.FOREGROUND_BLUE | win32c.FOREGROUND_GREEN,
> -        'white': (win32c.FOREGROUND_RED | win32c.FOREGROUND_GREEN |
> -                  win32c.FOREGROUND_BLUE),
> -        'bold': win32c.FOREGROUND_INTENSITY,
> +        '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': 0x100,                  # unused value > 0x0f
> -        'red_background': win32c.BACKGROUND_RED,
> -        'green_background': win32c.BACKGROUND_GREEN,
> -        'yellow_background': win32c.BACKGROUND_RED | win32c.BACKGROUND_GREEN,
> -        'blue_background': win32c.BACKGROUND_BLUE,
> -        'purple_background': win32c.BACKGROUND_BLUE | win32c.BACKGROUND_RED,
> -        'cyan_background': win32c.BACKGROUND_BLUE | win32c.BACKGROUND_GREEN,
> -        'white_background': (win32c.BACKGROUND_RED | win32c.BACKGROUND_GREEN |
> -                             win32c.BACKGROUND_BLUE),
> -        'bold_background': win32c.BACKGROUND_INTENSITY,
> -        'underline': win32c.COMMON_LVB_UNDERSCORE,  # double-byte charsets only
> -        'inverse': win32c.COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
> +        'red_background': _BACKGROUND_RED,
> +        'green_background': _BACKGROUND_GREEN,
> +        'yellow_background': _BACKGROUND_RED | _BACKGROUND_GREEN,
> +        'blue_background': _BACKGROUND_BLUE,
> +        'purple_background': _BACKGROUND_BLUE | _BACKGROUND_RED,
> +        'cyan_background': _BACKGROUND_BLUE | _BACKGROUND_GREEN,
> +        'white_background': (_BACKGROUND_RED | _BACKGROUND_GREEN |
> +                             _BACKGROUND_BLUE),
> +        'bold_background': _BACKGROUND_INTENSITY,
> +        'underline': _COMMON_LVB_UNDERSCORE,  # double-byte charsets only
> +        'inverse': _COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
>      }
>  
> -    passthrough = set([win32c.FOREGROUND_INTENSITY,
> -                       win32c.BACKGROUND_INTENSITY,
> -                       win32c.COMMON_LVB_UNDERSCORE,
> -                       win32c.COMMON_LVB_REVERSE_VIDEO])
> +    passthrough = set([_FOREGROUND_INTENSITY,
> +                       _BACKGROUND_INTENSITY,
> +                       _COMMON_LVB_UNDERSCORE,
> +                       _COMMON_LVB_REVERSE_VIDEO])
>  
> -    try:
> -        stdout = win32c.GetStdHandle(win32c.STD_OUTPUT_HANDLE)
> -        if stdout is None:
> -            raise ImportError()
> -        origattr = stdout.GetConsoleScreenBufferInfo()['Attributes']
> -    except pywintypes.error:
> -        # stdout may be defined but not support
> -        # GetConsoleScreenBufferInfo(), when called from subprocess or
> -        # redirected.
> -        raise ImportError()
> +    stdout = _kernel32.GetStdHandle(
> +                  _STD_OUTPUT_HANDLE)  # don't close the handle returned
> +    if stdout is None or stdout == _INVALID_HANDLE_VALUE:
> +        raise ctypes.WinError()
> +    csbi = _CONSOLE_SCREEN_BUFFER_INFO()
> +    if not _kernel32.GetConsoleScreenBufferInfo(stdout, ctypes.byref(csbi)):
> +        raise ctypes.WinError()
> +    origattr = csbi.wAttributes

Gah. I'm too restrictive here:

$ hg --traceback log -r 28 -p > foo
*** failed to import extension color: [Error 6] The handle is invalid.
Traceback (most recent call last):
  File "C:\Users\adi\hgrepos\hg-crew\mercurial\extensions.py", line 82, in loadall
    load(ui, name, path)
  File "C:\Users\adi\hgrepos\hg-crew\mercurial\extensions.py", line 67, in load
    mod = importh("hgext.%s" % name)
  File "C:\Users\adi\hgrepos\hg-crew\mercurial\extensions.py", line 61, in importh
    mod = __import__(name)
  File "C:\Users\adi\hgrepos\hg-crew\mercurial\demandimport.py", line 85, in _demandimport
    return _origimport(name, globals, locals, fromlist)
  File "C:\Users\adi\hgrepos\hg-crew\hgext\color.py", line 316, in <module>
    raise ctypes.WinError()
WindowsError: [Error 6] The handle is invalid.

I should have read the original comment there more closely.

I'll send a corrected version.

>      ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)', re.MULTILINE | re.DOTALL)
>  
>      def win32print(text, orig, **opts):
> @@ -309,12 +347,9 @@ try:
>              for sattr in m.group(1).split(';'):
>                  if sattr:
>                      attr = mapcolor(int(sattr), attr)
> -            stdout.SetConsoleTextAttribute(attr)
> +            _kernel32.SetConsoleTextAttribute(stdout, attr)
>              orig(m.group(2), **opts)
>              m = re.match(ansire, m.group(3))
>  
>          # Explicity reset original attributes
> -        stdout.SetConsoleTextAttribute(origattr)
> -
> -except ImportError:
> -    w32effects = None
> +        _kernel32.SetConsoleTextAttribute(stdout, origattr)


More information about the Mercurial-devel mailing list