mercurial/color.py
changeset 31067 a0bde5ec3a46
parent 30973 e5363cb96233
child 31071 350d737e059d
equal deleted inserted replaced
31066:c962bb6af909 31067:a0bde5ec3a46
     6 # GNU General Public License version 2 or any later version.
     6 # GNU General Public License version 2 or any later version.
     7 
     7 
     8 from __future__ import absolute_import
     8 from __future__ import absolute_import
     9 
     9 
    10 from .i18n import _
    10 from .i18n import _
       
    11 
       
    12 from . import pycompat
    11 
    13 
    12 try:
    14 try:
    13     import curses
    15     import curses
    14     # Mapping from effect name to terminfo attribute name (or raw code) or
    16     # Mapping from effect name to terminfo attribute name (or raw code) or
    15     # color number.  This will also force-load the curses module.
    17     # color number.  This will also force-load the curses module.
   170     else:
   172     else:
   171         start = ''.join(_effect_str(effect)
   173         start = ''.join(_effect_str(effect)
   172                         for effect in ['none'] + effects.split())
   174                         for effect in ['none'] + effects.split())
   173         stop = _effect_str('none')
   175         stop = _effect_str('none')
   174     return ''.join([start, text, stop])
   176     return ''.join([start, text, stop])
       
   177 
       
   178 w32effects = None
       
   179 if pycompat.osname == 'nt':
       
   180     import ctypes
       
   181     import re
       
   182 
       
   183     _kernel32 = ctypes.windll.kernel32
       
   184 
       
   185     _WORD = ctypes.c_ushort
       
   186 
       
   187     _INVALID_HANDLE_VALUE = -1
       
   188 
       
   189     class _COORD(ctypes.Structure):
       
   190         _fields_ = [('X', ctypes.c_short),
       
   191                     ('Y', ctypes.c_short)]
       
   192 
       
   193     class _SMALL_RECT(ctypes.Structure):
       
   194         _fields_ = [('Left', ctypes.c_short),
       
   195                     ('Top', ctypes.c_short),
       
   196                     ('Right', ctypes.c_short),
       
   197                     ('Bottom', ctypes.c_short)]
       
   198 
       
   199     class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
       
   200         _fields_ = [('dwSize', _COORD),
       
   201                     ('dwCursorPosition', _COORD),
       
   202                     ('wAttributes', _WORD),
       
   203                     ('srWindow', _SMALL_RECT),
       
   204                     ('dwMaximumWindowSize', _COORD)]
       
   205 
       
   206     _STD_OUTPUT_HANDLE = 0xfffffff5 # (DWORD)-11
       
   207     _STD_ERROR_HANDLE = 0xfffffff4  # (DWORD)-12
       
   208 
       
   209     _FOREGROUND_BLUE = 0x0001
       
   210     _FOREGROUND_GREEN = 0x0002
       
   211     _FOREGROUND_RED = 0x0004
       
   212     _FOREGROUND_INTENSITY = 0x0008
       
   213 
       
   214     _BACKGROUND_BLUE = 0x0010
       
   215     _BACKGROUND_GREEN = 0x0020
       
   216     _BACKGROUND_RED = 0x0040
       
   217     _BACKGROUND_INTENSITY = 0x0080
       
   218 
       
   219     _COMMON_LVB_REVERSE_VIDEO = 0x4000
       
   220     _COMMON_LVB_UNDERSCORE = 0x8000
       
   221 
       
   222     # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
       
   223     w32effects = {
       
   224         'none': -1,
       
   225         'black': 0,
       
   226         'red': _FOREGROUND_RED,
       
   227         'green': _FOREGROUND_GREEN,
       
   228         'yellow': _FOREGROUND_RED | _FOREGROUND_GREEN,
       
   229         'blue': _FOREGROUND_BLUE,
       
   230         'magenta': _FOREGROUND_BLUE | _FOREGROUND_RED,
       
   231         'cyan': _FOREGROUND_BLUE | _FOREGROUND_GREEN,
       
   232         'white': _FOREGROUND_RED | _FOREGROUND_GREEN | _FOREGROUND_BLUE,
       
   233         'bold': _FOREGROUND_INTENSITY,
       
   234         'black_background': 0x100,                  # unused value > 0x0f
       
   235         'red_background': _BACKGROUND_RED,
       
   236         'green_background': _BACKGROUND_GREEN,
       
   237         'yellow_background': _BACKGROUND_RED | _BACKGROUND_GREEN,
       
   238         'blue_background': _BACKGROUND_BLUE,
       
   239         'purple_background': _BACKGROUND_BLUE | _BACKGROUND_RED,
       
   240         'cyan_background': _BACKGROUND_BLUE | _BACKGROUND_GREEN,
       
   241         'white_background': (_BACKGROUND_RED | _BACKGROUND_GREEN |
       
   242                              _BACKGROUND_BLUE),
       
   243         'bold_background': _BACKGROUND_INTENSITY,
       
   244         'underline': _COMMON_LVB_UNDERSCORE,  # double-byte charsets only
       
   245         'inverse': _COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
       
   246     }
       
   247 
       
   248     passthrough = set([_FOREGROUND_INTENSITY,
       
   249                        _BACKGROUND_INTENSITY,
       
   250                        _COMMON_LVB_UNDERSCORE,
       
   251                        _COMMON_LVB_REVERSE_VIDEO])
       
   252 
       
   253     stdout = _kernel32.GetStdHandle(
       
   254                   _STD_OUTPUT_HANDLE)  # don't close the handle returned
       
   255     if stdout is None or stdout == _INVALID_HANDLE_VALUE:
       
   256         w32effects = None
       
   257     else:
       
   258         csbi = _CONSOLE_SCREEN_BUFFER_INFO()
       
   259         if not _kernel32.GetConsoleScreenBufferInfo(
       
   260                     stdout, ctypes.byref(csbi)):
       
   261             # stdout may not support GetConsoleScreenBufferInfo()
       
   262             # when called from subprocess or redirected
       
   263             w32effects = None
       
   264         else:
       
   265             origattr = csbi.wAttributes
       
   266             ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)',
       
   267                                 re.MULTILINE | re.DOTALL)
       
   268 
       
   269     def win32print(text, orig, **opts):
       
   270         label = opts.get('label', '')
       
   271         attr = origattr
       
   272 
       
   273         def mapcolor(val, attr):
       
   274             if val == -1:
       
   275                 return origattr
       
   276             elif val in passthrough:
       
   277                 return attr | val
       
   278             elif val > 0x0f:
       
   279                 return (val & 0x70) | (attr & 0x8f)
       
   280             else:
       
   281                 return (val & 0x07) | (attr & 0xf8)
       
   282 
       
   283         # determine console attributes based on labels
       
   284         for l in label.split():
       
   285             style = _styles.get(l, '')
       
   286             for effect in style.split():
       
   287                 try:
       
   288                     attr = mapcolor(w32effects[effect], attr)
       
   289                 except KeyError:
       
   290                     # w32effects could not have certain attributes so we skip
       
   291                     # them if not found
       
   292                     pass
       
   293         # hack to ensure regexp finds data
       
   294         if not text.startswith('\033['):
       
   295             text = '\033[m' + text
       
   296 
       
   297         # Look for ANSI-like codes embedded in text
       
   298         m = re.match(ansire, text)
       
   299 
       
   300         try:
       
   301             while m:
       
   302                 for sattr in m.group(1).split(';'):
       
   303                     if sattr:
       
   304                         attr = mapcolor(int(sattr), attr)
       
   305                 _kernel32.SetConsoleTextAttribute(stdout, attr)
       
   306                 orig(m.group(2), **opts)
       
   307                 m = re.match(ansire, m.group(3))
       
   308         finally:
       
   309             # Explicitly reset original attributes
       
   310             _kernel32.SetConsoleTextAttribute(stdout, origattr)