[PATCH 2 of 4] color: stop mutating the default effects map

Matt Harbison mharbison72 at gmail.com
Sun Mar 26 00:41:05 EDT 2017


# HG changeset patch
# User Matt Harbison <matt_harbison at yahoo.com>
# Date 1490464217 14400
#      Sat Mar 25 13:50:17 2017 -0400
# Node ID a263702b064a5a3ce1ca74b227e8e624e4b05874
# Parent  22533c3af63d5a67d9210596eafd4b99ab9c7904
color: stop mutating the default effects map

A future change will make color.setup() callable a second time when the pager is
spawned, in order to honor the 'color.pagermode' setting.  The problem was that
when 'color.mode=auto' was resolved to 'win32' in the first pass, the default
ANSI effects were overwritten, making it impossible to honor 'pagermode=ansi'.
Also, the two separate maps didn't have the same keys.  The symmetric difference
is 'dim' and 'italic' (from ANSI), and 'bold_background' (from win32).  Thus,
the update left entries that didn't belong for the current mode.

As an added bonus, this now correctly enables color with MSYS `less` for a
command like this, where pager is forced on:

    $ hg log --config color.pagermode=ansi --pager=yes

Previously, the output was corrupted.  The raw output, as seen through the ANSI
blind `more.com` was:

    <-[-1;6mchangeset:   34840:50bcb95d40f5<-[-1m
    ...

which MSYS `less -FRX` rendered as:

    1;6mchangeset:   34840:50bcb95d40f51m
    ...

(The two '<-' instances were actually an arrow character that TortoiseHg warned
couldn't be encoded, and notepad++ translated to a single '?'.)

diff --git a/mercurial/color.py b/mercurial/color.py
--- a/mercurial/color.py
+++ b/mercurial/color.py
@@ -233,12 +233,14 @@
         if mode == realmode and ui.formatted():
             ui.warn(_('warning: failed to set color mode to %s\n') % mode)
 
+    ui._coloreffects = _effects.copy()
+
     if realmode == 'win32':
         ui._terminfoparams.clear()
         if not w32effects:
             modewarn()
             return None
-        _effects.update(w32effects)
+        ui._coloreffects = w32effects.copy()
     elif realmode == 'ansi':
         ui._terminfoparams.clear()
     elif realmode == 'terminfo':
@@ -273,7 +275,7 @@
 
 def valideffect(ui, effect):
     'Determine if the effect is valid or not.'
-    return ((not ui._terminfoparams and effect in _effects)
+    return ((not ui._terminfoparams and effect in ui._coloreffects)
              or (effect in ui._terminfoparams
                  or effect[:-11] in ui._terminfoparams))
 
@@ -324,9 +326,9 @@
                         for effect in ['none'] + effects.split())
         stop = _effect_str(ui, 'none')
     else:
-        start = [str(_effects[e]) for e in ['none'] + effects.split()]
+        start = [str(ui._coloreffects[e]) for e in ['none'] + effects.split()]
         start = '\033[' + ';'.join(start) + 'm'
-        stop = '\033[' + str(_effects['none']) + 'm'
+        stop = '\033[' + str(ui._coloreffects['none']) + 'm'
     return _mergeeffects(text, start, stop)
 
 _ansieffectre = re.compile(br'\x1b\[[0-9;]*m')
diff --git a/mercurial/ui.py b/mercurial/ui.py
--- a/mercurial/ui.py
+++ b/mercurial/ui.py
@@ -157,6 +157,7 @@
         # Blocked time
         self.logblockedtimes = False
         # color mode: see mercurial/color.py for possible value
+        self._coloreffects = {}
         self._colormode = None
         self._terminfoparams = {}
         self._styles = {}
@@ -176,6 +177,7 @@
             self.environ = src.environ
             self.callhooks = src.callhooks
             self.insecureconnections = src.insecureconnections
+            self._coloreffects = src._coloreffects.copy()
             self._colormode = src._colormode
             self._terminfoparams = src._terminfoparams.copy()
             self._styles = src._styles.copy()


More information about the Mercurial-devel mailing list