# HG changeset patch # User Adrian Buehlmann # Date 1299838461 -3600 # Node ID 2420cb1ea1d6d7f46739eead1e3d7f9c399120a4 # Parent 4bfff063aed6fb4b3c8abe8a9ec51fe1e55725bf color: port to using ctypes (issue2687) replacing usage of pywin32, which was removed for Mercurial 1.8 diff -r 4bfff063aed6 -r 2420cb1ea1d6 hgext/color.py --- a/hgext/color.py Sun Mar 13 17:39:33 2011 -0500 +++ b/hgext/color.py Fri Mar 11 11:14:21 2011 +0100 @@ -203,7 +203,7 @@ if mode == 'win32': if w32effects is None: # only warn if color.mode is explicitly set to win32 - ui.warn(_('win32console not found, please install pywin32\n')) + ui.warn(_('warning: failed to set color mode to %s\n') % mode) return _effects.update(w32effects) elif mode != 'ansi': @@ -231,52 +231,96 @@ _("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() - ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)', re.MULTILINE | re.DOTALL) + stdout = _kernel32.GetStdHandle( + _STD_OUTPUT_HANDLE) # don't close the handle returned + if stdout is None or stdout == _INVALID_HANDLE_VALUE: + w32effects = None + else: + csbi = _CONSOLE_SCREEN_BUFFER_INFO() + if not _kernel32.GetConsoleScreenBufferInfo( + stdout, ctypes.byref(csbi)): + # stdout may not support GetConsoleScreenBufferInfo() + # when called from subprocess or redirected + w32effects = None + else: + origattr = csbi.wAttributes + ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)', + re.MULTILINE | re.DOTALL) def win32print(text, orig, **opts): label = opts.get('label', '') @@ -308,12 +352,9 @@ 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)