Patchwork [1,of,6] color: move 'win32' declaration to the core module

login
register
mail settings
Submitter Pierre-Yves David
Date Feb. 21, 2017, 10:17 p.m.
Message ID <60a489f0531abbafc7f5.1487715477@nodosa.octopoid.net>
Download mbox | patch
Permalink /patch/18701/
State Accepted
Headers show

Comments

Pierre-Yves David - Feb. 21, 2017, 10:17 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@ens-lyon.org>
# Date 1482372679 -3600
#      Thu Dec 22 03:11:19 2016 +0100
# Node ID 60a489f0531abbafc7f53a3dd4bad50f13b38015
# Parent  e5363cb96233861fc99f7e9b85d7884d3121558c
# EXP-Topic color
color: move 'win32' declaration to the core module

This is another part of moving color implementation into core. before we can
move the advance logic, we need to move the basic definition and building
bricks. This is one more step on that road.
Yuya Nishihara - Feb. 22, 2017, 3:11 p.m.
On Tue, 21 Feb 2017 23:17:57 +0100, Pierre-Yves David wrote:
> # HG changeset patch
> # User Pierre-Yves David <pierre-yves.david@ens-lyon.org>
> # Date 1482372679 -3600
> #      Thu Dec 22 03:11:19 2016 +0100
> # Node ID 60a489f0531abbafc7f53a3dd4bad50f13b38015
> # Parent  e5363cb96233861fc99f7e9b85d7884d3121558c
> # EXP-Topic color
> color: move 'win32' declaration to the core module

The series looks good. Queued, thanks.

> +if pycompat.osname == 'nt':
> +    import ctypes
> +    import re
> +
> +    _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 = 0xfffffff5 # (DWORD)-11
> +    _STD_ERROR_HANDLE = 0xfffffff4  # (DWORD)-12

[...]

> +        try:
> +            while m:
> +                for sattr in m.group(1).split(';'):
> +                    if sattr:
> +                        attr = mapcolor(int(sattr), attr)
> +                _kernel32.SetConsoleTextAttribute(stdout, attr)
> +                orig(m.group(2), **opts)
> +                m = re.match(ansire, m.group(3))
> +        finally:
> +            # Explicitly reset original attributes
> +            _kernel32.SetConsoleTextAttribute(stdout, origattr)

I wonder if some parts of these Win32API stuff could be moved to win32.py, but
that wouldn't be simple.
Pierre-Yves David - Feb. 22, 2017, 5:06 p.m.
On 02/22/2017 04:11 PM, Yuya Nishihara wrote:
> On Tue, 21 Feb 2017 23:17:57 +0100, Pierre-Yves David wrote:
>> # HG changeset patch
>> # User Pierre-Yves David <pierre-yves.david@ens-lyon.org>
>> # Date 1482372679 -3600
>> #      Thu Dec 22 03:11:19 2016 +0100
>> # Node ID 60a489f0531abbafc7f53a3dd4bad50f13b38015
>> # Parent  e5363cb96233861fc99f7e9b85d7884d3121558c
>> # EXP-Topic color
>> color: move 'win32' declaration to the core module
>
> The series looks good. Queued, thanks.
>
>> +if pycompat.osname == 'nt':
>> +    import ctypes
>> +    import re
>> +
>> +    _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 = 0xfffffff5 # (DWORD)-11
>> +    _STD_ERROR_HANDLE = 0xfffffff4  # (DWORD)-12
>
> [...]
>
>> +        try:
>> +            while m:
>> +                for sattr in m.group(1).split(';'):
>> +                    if sattr:
>> +                        attr = mapcolor(int(sattr), attr)
>> +                _kernel32.SetConsoleTextAttribute(stdout, attr)
>> +                orig(m.group(2), **opts)
>> +                m = re.match(ansire, m.group(3))
>> +        finally:
>> +            # Explicitly reset original attributes
>> +            _kernel32.SetConsoleTextAttribute(stdout, origattr)
>
> I wonder if some parts of these Win32API stuff could be moved to win32.py, but
> that wouldn't be simple.

Hum, interresting. I'm adding this the stack of "clean up we might do 
once color is in core". There is about 25 more patches to go before we 
can get into clean up territory.

Cheers,

Patch

diff -r e5363cb96233 -r 60a489f0531a hgext/color.py
--- a/hgext/color.py	Thu Dec 22 02:38:53 2016 +0100
+++ b/hgext/color.py	Thu Dec 22 03:11:19 2016 +0100
@@ -263,7 +263,7 @@  def _modesetup(ui, coloropt):
             # gibberish, we error on the side of selecting "win32". However, if
             # w32effects is not defined, we almost certainly don't support
             # "win32", so don't even try.
-            if (term and 'xterm' in term) or not w32effects:
+            if (term and 'xterm' in term) or not color.w32effects:
                 realmode = 'ansi'
             else:
                 realmode = 'win32'
@@ -278,10 +278,10 @@  def _modesetup(ui, coloropt):
 
     if realmode == 'win32':
         color._terminfo_params.clear()
-        if not w32effects:
+        if not color.w32effects:
             modewarn()
             return None
-        color._effects.update(w32effects)
+        color._effects.update(color.w32effects)
     elif realmode == 'ansi':
         color._terminfo_params.clear()
     elif realmode == 'terminfo':
@@ -311,7 +311,7 @@  class colorui(uimod.ui):
                 self._buffers[-1].extend(args)
         elif self._colormode == 'win32':
             for a in args:
-                win32print(a, super(colorui, self).write, **opts)
+                color.win32print(a, super(colorui, self).write, **opts)
         else:
             return super(colorui, self).write(
                 *[self.label(a, label) for a in args], **opts)
@@ -325,7 +325,7 @@  class colorui(uimod.ui):
             return self.write(*args, **opts)
         if self._colormode == 'win32':
             for a in args:
-                win32print(a, super(colorui, self).write_err, **opts)
+                color.win32print(a, super(colorui, self).write_err, **opts)
         else:
             return super(colorui, self).write_err(
                 *[self.label(a, label) for a in args], **opts)
@@ -432,138 +432,3 @@  def _debugdisplaystyle(ui):
             ui.write(' ' * (max(0, width - len(label))))
             ui.write(', '.join(ui.label(e, e) for e in effects.split()))
         ui.write('\n')
-
-if pycompat.osname != 'nt':
-    w32effects = None
-else:
-    import ctypes
-    import re
-
-    _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 = 0xfffffff5 # (DWORD)-11
-    _STD_ERROR_HANDLE = 0xfffffff4  # (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': _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': _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([_FOREGROUND_INTENSITY,
-                       _BACKGROUND_INTENSITY,
-                       _COMMON_LVB_UNDERSCORE,
-                       _COMMON_LVB_REVERSE_VIDEO])
-
-    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', '')
-        attr = origattr
-
-        def mapcolor(val, attr):
-            if val == -1:
-                return origattr
-            elif val in passthrough:
-                return attr | val
-            elif val > 0x0f:
-                return (val & 0x70) | (attr & 0x8f)
-            else:
-                return (val & 0x07) | (attr & 0xf8)
-
-        # determine console attributes based on labels
-        for l in label.split():
-            style = color._styles.get(l, '')
-            for effect in style.split():
-                try:
-                    attr = mapcolor(w32effects[effect], attr)
-                except KeyError:
-                    # w32effects could not have certain attributes so we skip
-                    # them if not found
-                    pass
-        # 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)
-
-        try:
-            while m:
-                for sattr in m.group(1).split(';'):
-                    if sattr:
-                        attr = mapcolor(int(sattr), attr)
-                _kernel32.SetConsoleTextAttribute(stdout, attr)
-                orig(m.group(2), **opts)
-                m = re.match(ansire, m.group(3))
-        finally:
-            # Explicitly reset original attributes
-            _kernel32.SetConsoleTextAttribute(stdout, origattr)
diff -r e5363cb96233 -r 60a489f0531a mercurial/color.py
--- a/mercurial/color.py	Thu Dec 22 02:38:53 2016 +0100
+++ b/mercurial/color.py	Thu Dec 22 03:11:19 2016 +0100
@@ -9,6 +9,8 @@  from __future__ import absolute_import
 
 from .i18n import _
 
+from . import pycompat
+
 try:
     import curses
     # Mapping from effect name to terminfo attribute name (or raw code) or
@@ -172,3 +174,137 @@  def _render_effects(text, effects):
                         for effect in ['none'] + effects.split())
         stop = _effect_str('none')
     return ''.join([start, text, stop])
+
+w32effects = None
+if pycompat.osname == 'nt':
+    import ctypes
+    import re
+
+    _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 = 0xfffffff5 # (DWORD)-11
+    _STD_ERROR_HANDLE = 0xfffffff4  # (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': _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': _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([_FOREGROUND_INTENSITY,
+                       _BACKGROUND_INTENSITY,
+                       _COMMON_LVB_UNDERSCORE,
+                       _COMMON_LVB_REVERSE_VIDEO])
+
+    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', '')
+        attr = origattr
+
+        def mapcolor(val, attr):
+            if val == -1:
+                return origattr
+            elif val in passthrough:
+                return attr | val
+            elif val > 0x0f:
+                return (val & 0x70) | (attr & 0x8f)
+            else:
+                return (val & 0x07) | (attr & 0xf8)
+
+        # determine console attributes based on labels
+        for l in label.split():
+            style = _styles.get(l, '')
+            for effect in style.split():
+                try:
+                    attr = mapcolor(w32effects[effect], attr)
+                except KeyError:
+                    # w32effects could not have certain attributes so we skip
+                    # them if not found
+                    pass
+        # 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)
+
+        try:
+            while m:
+                for sattr in m.group(1).split(';'):
+                    if sattr:
+                        attr = mapcolor(int(sattr), attr)
+                _kernel32.SetConsoleTextAttribute(stdout, attr)
+                orig(m.group(2), **opts)
+                m = re.match(ansire, m.group(3))
+        finally:
+            # Explicitly reset original attributes
+            _kernel32.SetConsoleTextAttribute(stdout, origattr)