[PATCH 3 of 4] color: automatically define 16 and 256 colors if supported

Kyle Lippincott spectral at pewpew.net
Mon Jul 10 22:44:23 EDT 2017


On Mon, Jul 10, 2017 at 5:26 PM, Gregory Szorc <gregory.szorc at gmail.com>
wrote:

> On Mon, Jul 10, 2017 at 4:32 PM, Kyle Lippincott <spectral at pewpew.net>
> wrote:
>
>>
>>
>> On Sun, Jul 9, 2017 at 4:46 PM, Gregory Szorc <gregory.szorc at gmail.com>
>> wrote:
>>
>>> # HG changeset patch
>>> # User Gregory Szorc <gregory.szorc at gmail.com>
>>> # Date 1499641339 25200
>>> #      Sun Jul 09 16:02:19 2017 -0700
>>> # Node ID fa6223b9e2a0d9fbfa81329b83c0512417cee713
>>> # Parent  98c54db9407a7e0ba94a632aafdbbec3fc76fa8b
>>> color: automatically define 16 and 256 colors if supported
>>>
>>> The "colors" terminfo capability returns the number of colors
>>> supported by the terminal profile.
>>>
>>> But with terminals, nothing is straightforward. The "colors"
>>> capability only returns what the current terminal profile (likely
>>> defined by $TERM) supports. The current terminal type or its profile
>>> may be wrong (most likely the former). So, any consumer of this
>>> capability needs to take this scenario into account.
>>>
>>> This commit adds code for querying the "colors" terminfo capability
>>> and for defining additional colors if 16 or 256 color support is
>>> present. Because of the aforementioned limitations with capability
>>> accuracy, a config option is introduced that allows the color count
>>> to be limited. If the extra colors cause any problems, once can simply
>>> set this option to restore existing 8 color behavior.
>>>
>>> As part of this feature, a dictionary containing cherry-picked colors
>>> from the 256 color spectrum was created. Choices are very subjective
>>> and can and should be adjusted, as appropriate.
>>>
>>> The help documentation for color support has been significantly
>>> overhauled as part of this commit.
>>>
>>> diff --git a/mercurial/color.py b/mercurial/color.py
>>> --- a/mercurial/color.py
>>> +++ b/mercurial/color.py
>>> @@ -45,10 +45,43 @@ try:
>>>          'white': curses.COLOR_WHITE,
>>>      }
>>>
>>> +    # Bright versions of the built-in colors are colors 8-15, in the
>>> same order.
>>> +    TERMINFO_COLOR_16 = {
>>> +        'brightblack': 8,
>>> +        'brightred': 9,
>>> +        'brightgreen': 10,
>>> +        'brightyellow': 11,
>>> +        'brightblue': 12,
>>> +        'brightmagenta': 13,
>>> +        'brightcyan': 14,
>>> +        'brightwhite': 15,
>>> +    }
>>> +
>>> +    # 6x6x6 color cube is 16-231. We define some common ones.
>>> +    TERMINFO_COLOR_256 = {
>>> +        'darkgreen': 28,
>>> +        'turquoise': 45,
>>> +        'lightgreen': 70,
>>> +        'bluegreen': 73,
>>> +        'deeppurple': 89,
>>> +        'purple': 129,
>>> +        'lightpurple': 177,
>>> +        'lightorange': 178,
>>> +        'lightyellow': 191,
>>> +        'pink': 201,
>>> +        'darkorange': 208,
>>> +    }
>>> +
>>> +    # 232-255 is a continuous spectrum of grey.
>>> +    for i, value in enumerate(range(232, 256)):
>>> +        TERMINFO_COLOR_256['grey%02d' % (i + 1)] = value
>>> +
>>>  except ImportError:
>>>      curses = None
>>>      _baseterminfoparams = {}
>>>      TERMINFO_COLOR_8 = {}
>>> +    TERMINFO_COLOR_16 = {}
>>> +    TERMINFO_COLOR_256 = {}
>>>
>>>  _enabledbydefault = True
>>>
>>> @@ -146,6 +179,43 @@ def _terminfocolors(ui):
>>>      for color, value in TERMINFO_COLOR_8.items():
>>>          colors[color] = (value, False)
>>>
>>> +    # Add 16 and 256 bit colors if supported and allowed by config
>>> policy.
>>> +    #
>>> +    # There's no reliable way to detect if the extra colors will
>>> actually work.
>>> +    # The terminfo database just reports what the current terminal is
>>> +    # advertising. Some terminals support querying the value of a color
>>> via
>>> +    # e.g. \e]4;%d;?\a. However, this isn't universally supported. So
>>> set
>>> +    # colors based purely on terminfo and provide users a way to
>>> disable in
>>> +    # case it doesn't work.
>>> +
>>> +    # Will likely return -1 on failure.
>>> +    termcolors = curses.tigetnum('colors')
>>> +    if termcolors < 8:
>>> +        termcolors = 8
>>> +
>>> +    # Default is to allow as many colors as the terminal supports.
>>> +    colorlimit = ui.configint('color', 'colorlimit', 256)
>>> +
>>> +    if colorlimit not in (8, 16, 256):
>>> +        ui.warn(_('unsupported color.colorlimit value %d; use 8, 16, '
>>> +                  'or 256\n') % colorlimit)
>>> +        colorlimit = 8
>>> +
>>> +    usecolors = min(termcolors, colorlimit)
>>>
>>
>> Considering how often TERM is incorrect and/or terminfo is incorrect or
>> minimizing/lowest-common-denominator (great example for both: TERM=xterm
>> vs xterm-256color), are we sure we want to min()?  Can we have some config
>> option to override the colors setting?
>>
>> Every single terminal I support handles \033[38;5;##m colors where ## is
>> max(88) or max(256), regardless of what their terminfo says.  I'm fine with
>> ignoring the few 88-color rxvt-unicode users and telling them to use the
>> 256-color version.  It would be nice to be able to put something like:
>>
>> [color]
>> mode=terminfo
>> colorlimit=256   # Ignore terminfo's stated limit
>>
>> into our config file to get this all corrected.
>>
>>
> I was also considering a config option (either the same or a different
> one) to force setting color support. After all, inaccurate TERM+terminfo is
> a thing. My worry about that is it may need to be conditional depending on
> the terminal type. If you e.g. have a shared hgrc that is accessed by
> different terminals, a forced setting could be bad. It's definitely safer
> to use TERM+terminfo to drive the setting.
>

Having a color.overrides.xterm.colorlimit=256, where 'xterm' is $TERM would
also work for me, but since "everything" claims to be xterm (I'm looking at
you, gnome-terminal), I don't know that it'd really end up any different
than just forcing it for all cases. :)

Since the likelihood of a sysadmin setting colorlimit=256 *and* preventing
users from having a ~/.hgrc where they could work around it is very low, I
don't see a downside to just respecting the config value without making it
the minimum of the config value or the terminfo value.  If there's a
(personal) shared hgrc file that needs to handle multiple different
terminals, the user can just not set this config value to let the terminfo
take effect (or set it to the minimum of all the terminals they personally
user), unless I'm missing something?


>
> Terminals are scary and I'm really hesitant to make *any* change that uses
> more powerful terminal features that can't easily be reverted via simple
> config file muckery.
>

>
>> +
>>> +    if usecolors >= 16:
>>> +        for color, value in TERMINFO_COLOR_16.items():
>>> +            colors[color] = (value, False)
>>> +
>>> +    if usecolors >= 256:
>>> +        for color, value in TERMINFO_COLOR_256.items():
>>> +            colors[color] = (value, False)
>>> +
>>> +    # TODO consider filtering color values by usecolors. This has 2
>>> +    # implications: 1) users can't force colors beyond the supported
>>> +    # color range (this arguably makes sense but is BC) 2)
>>> configstyles()
>>> +    # emits a warning if there is a reference to this discarded color
>>> +    # (it may be desirable to suppress that warning).
>>>      for key, value in ui.configitems('color'):
>>>          if key.startswith('color.'):
>>>              colors[key[6:]] = (int(value), True)
>>> @@ -186,6 +256,7 @@ def _terminfosetup(ui, mode):
>>>              # noisy and use ui.debug().
>>>              ui.debug("no terminfo entry for %s\n" % e)
>>>              del ui._terminfoparams[key]
>>> +
>>>      if not curses.tigetstr('setaf') or not curses.tigetstr('setab'):
>>>          # Only warn about missing terminfo entries if we explicitly
>>> asked for
>>>          # terminfo mode.
>>> diff --git a/mercurial/help/color.txt b/mercurial/help/color.txt
>>> --- a/mercurial/help/color.txt
>>> +++ b/mercurial/help/color.txt
>>> @@ -131,19 +131,38 @@ effects may be overridden from your conf
>>>
>>>    histedit.remaining = red bold
>>>
>>> +Supported Colors
>>> +================
>>> +
>>> +There are 8 standard colors: ``black``, ``red``, ``green``, ``yellow``,
>>> +``blue``, ``magenta``, ``cyan``, and ``white``.
>>> +
>>> +If the ``terminfo`` color mode is being used and the terminfo database
>>> +reports that the current terminal supports more colors, additional
>>> colors
>>> +will be defined.
>>> +
>>> +If 16 colors are supported, the 8 additional colors are the 8 standard
>>> +colors prefixed with "bright". e.g. ``brightred`` and ``brightyellow``.
>>> +
>>> +If 256 colors are supported, an assortment of additional colors are
>>> +available. These include ``darkgreen``, ``turquoise``, ``purple``, and
>>> +``pink``. For the list of all defined colors, run :hg:`debugcolor`.
>>> +
>>> +In some cases, not all colors will render properly. See
>>> +:hg:`help config.color.colorlimit` for how to limit Mercurial to a
>>> smaller
>>> +set of colors.
>>> +
>>>  Custom colors
>>>  =============
>>>
>>> -Because there are only eight standard colors, Mercurial allows you
>>> -to define color names for other color slots which might be available
>>> -for your terminal type, assuming terminfo mode.  For instance::
>>> +When using ``terminfo`` mode, Mercurial supports defining colors via
>>> +config options. You can either declare new colors or change the value
>>> +for a built-in color. e.g.::
>>>
>>> -  color.brightblue = 12
>>> +  [color]
>>> +  color.mydarkblue = 18
>>>    color.pink = 207
>>>    color.orange = 202
>>>
>>> -to set 'brightblue' to color slot 12 (useful for 16 color terminals
>>> -that have brighter colors defined in the upper eight) and, 'pink' and
>>> -'orange' to colors in 256-color xterm's default color cube.  These
>>> -defined colors may then be used as any of the pre-defined eight,
>>> -including appending '_background' to set the background to that color.
>>> +To see what color values are supported and how they render, perform
>>> +an Internet search for "xterm color cube."
>>> diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
>>> --- a/mercurial/help/config.txt
>>> +++ b/mercurial/help/config.txt
>>> @@ -432,6 +432,22 @@ effect and style see :hg:`help color`.
>>>      On some systems (such as MSYS in Windows), the terminal may support
>>>      a different color mode than the pager program.
>>>
>>> +``colorlimit``
>>> +    Limits how many colors will be defined and used.
>>> +
>>> +    Most terminals support 8 standard colors. Mercurial will detect
>>> +    and use additional colors if the terminal indicates support for
>>> them.
>>> +
>>> +    In some cases, the terminal advertises support for additional colors
>>> +    but doesn't actually support them. This can lead to poor formatting
>>> +    or even gibberish being printed.
>>> +
>>> +    Setting this option to a value of ``8``, ``16``, or ``256`` will
>>> +    explicitly limit Mercurial to a maximum of that many colors.
>>> +
>>> +    This option has no effect unless the ``terminfo`` color mode is
>>> being
>>> +    used.
>>> +
>>>  ``commands``
>>>  ------------
>>>
>>> diff --git a/tests/hgterm.ti b/tests/hgterm16.ti
>>> copy from tests/hgterm.ti
>>> copy to tests/hgterm16.ti
>>> --- a/tests/hgterm.ti
>>> +++ b/tests/hgterm16.ti
>>> @@ -1,6 +1,6 @@
>>> -hgterm,
>>> +hgterm-16color,
>>>         am, km, mir, msgr, xenl,
>>> -       colors#8, cols#80, it#8, lines#24, pairs#64,
>>> +       colors#16, cols#80, it#8, lines#24, pairs#64,
>>>         acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
>>>         bel=^G, bold=\E[1m, clear=\E[H\E[2J, cr=\r,
>>>         csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=\b,
>>> diff --git a/tests/hgterm.ti b/tests/hgterm256.ti
>>> copy from tests/hgterm.ti
>>> copy to tests/hgterm256.ti
>>> --- a/tests/hgterm.ti
>>> +++ b/tests/hgterm256.ti
>>> @@ -1,6 +1,6 @@
>>> -hgterm,
>>> +hgterm-256color,
>>>         am, km, mir, msgr, xenl,
>>> -       colors#8, cols#80, it#8, lines#24, pairs#64,
>>> +       colors#256, cols#80, it#8, lines#24, pairs#64,
>>>         acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
>>>         bel=^G, bold=\E[1m, clear=\E[H\E[2J, cr=\r,
>>>         csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=\b,
>>> diff --git a/tests/test-status-color.t b/tests/test-status-color.t
>>> --- a/tests/test-status-color.t
>>> +++ b/tests/test-status-color.t
>>> @@ -226,6 +226,9 @@ hg status -A (with terminfo color):
>>>
>>>    $ mkdir "$TESTTMP/terminfo"
>>>    $ TERMINFO="$TESTTMP/terminfo" tic "$TESTDIR/hgterm.ti"
>>> +  $ TERMINFO="$TESTTMP/terminfo" tic "$TESTDIR/hgterm16.ti"
>>> +  $ TERMINFO="$TESTTMP/terminfo" tic "$TESTDIR/hgterm256.ti"
>>> +
>>>    $ TERM=hgterm TERMINFO="$TESTTMP/terminfo" hg status --config
>>> color.mode=terminfo -A
>>>    \x1b[30m\x1b[32m\x1b[1mA \x1b[30m\x1b[30m\x1b[32m\x1b[1madded\x1b[30m
>>> (esc)
>>>    \x1b[30m\x1b[32m\x1b[1mA \x1b[30m\x1b[30m\x1b[32m\x1b[1mcopied\x1b[30m
>>> (esc)
>>> @@ -256,6 +259,58 @@ The user can define effects with raw ter
>>>    \x1b[30m\x1b[88mC \x1b[30m\x1b[30m\x1b[88m.hgignore\x1b[30m (esc)
>>>    \x1b[30m\x1b[88mC \x1b[30m\x1b[30m\x1b[88mmodified\x1b[30m (esc)
>>>
>>> +A 16 and 256 colors won't be used if the terminal doesn't advertise
>>> support
>>> +
>>> +  $ TERM=hgterm TERMINFO="$TESTTMP/terminfo" hg status -a --config
>>> color.mode=terminfo --config color.status.added=brightred
>>> +  ignoring unknown color/effect 'brightred' (configured in
>>> color.status.added)
>>> +  ignoring unknown color/effect 'brightred' (configured in
>>> color.status.added)
>>> +  ignoring unknown color/effect 'brightred' (configured in
>>> color.status.added)
>>> +  A added
>>> +  A copied
>>> +
>>> +  $ TERM=hgterm TERMINFO="$TESTTMP/terminfo" hg status -a --config
>>> color.mode=terminfo --config color.status.added=purple
>>> +  ignoring unknown color/effect 'purple' (configured in
>>> color.status.added)
>>> +  ignoring unknown color/effect 'purple' (configured in
>>> color.status.added)
>>> +  ignoring unknown color/effect 'purple' (configured in
>>> color.status.added)
>>> +  A added
>>> +  A copied
>>> +
>>> +A 16 color can be used if terminal advertises 16 color support
>>> +
>>> +  $ TERM=hgterm-16color TERMINFO="$TESTTMP/terminfo" hg status -a
>>> --config color.mode=terminfo --config color.status.added=brightred
>>> +  \x1b[30m\x1b[39mA \x1b[30m\x1b[30m\x1b[39madded\x1b[30m (esc)
>>> +  \x1b[30m\x1b[39mA \x1b[30m\x1b[30m\x1b[39mcopied\x1b[30m (esc)
>>> +
>>> +A 256 color can be used if terminal advertises 256 color support
>>> +
>>> +  $ TERM=hgterm-256color TERMINFO="$TESTTMP/terminfo" hg status -a
>>> --config color.mode=terminfo --config color.status.added=purple
>>> +  \x1b[30m\x1b[3129mA \x1b[30m\x1b[30m\x1b[3129madded\x1b[30m (esc)
>>> +  \x1b[30m\x1b[3129mA \x1b[30m\x1b[30m\x1b[3129mcopied\x1b[30m (esc)
>>> +
>>> +color.colorlimit can narrow allowed color range
>>> +
>>> +  $ TERM=hgterm-256color TERMINFO="$TESTTMP/terminfo" hg status -a
>>> --config color.mode=terminfo --config color.status.added=purple --config
>>> color.colorlimit=8
>>> +  ignoring unknown color/effect 'purple' (configured in
>>> color.status.added)
>>> +  ignoring unknown color/effect 'purple' (configured in
>>> color.status.added)
>>> +  ignoring unknown color/effect 'purple' (configured in
>>> color.status.added)
>>> +  A added
>>> +  A copied
>>> +  $ TERM=hgterm-256color TERMINFO="$TESTTMP/terminfo" hg status -a
>>> --config color.mode=terminfo --config color.status.added=purple --config
>>> color.colorlimit=16
>>> +  ignoring unknown color/effect 'purple' (configured in
>>> color.status.added)
>>> +  ignoring unknown color/effect 'purple' (configured in
>>> color.status.added)
>>> +  ignoring unknown color/effect 'purple' (configured in
>>> color.status.added)
>>> +  A added
>>> +  A copied
>>> +
>>> +Invalid color.colorlimit is normalized to 8
>>> +
>>> +  $ TERM=hgterm-256color TERMINFO="$TESTTMP/terminfo" hg status -a
>>> --config color.mode=terminfo --config color.colorlimit=128
>>> +  unsupported color.colorlimit value 128; use 8, 16, or 256
>>> +  unsupported color.colorlimit value 128; use 8, 16, or 256
>>> +  unsupported color.colorlimit value 128; use 8, 16, or 256
>>> +  \x1b[30m\x1b[32m\x1b[2mA \x1b[30m\x1b[30m\x1b[32m\x1b[2madded\x1b[30m
>>> (esc)
>>> +  \x1b[30m\x1b[32m\x1b[2mA \x1b[30m\x1b[30m\x1b[32m\x1b[2mcopied\x1b[30m
>>> (esc)
>>> +
>>>  #endif
>>>
>>>
>>> _______________________________________________
>>> Mercurial-devel mailing list
>>> Mercurial-devel at mercurial-scm.org
>>> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.mercurial-scm.org/pipermail/mercurial-devel/attachments/20170710/b75b0c9b/attachment.html>


More information about the Mercurial-devel mailing list