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

login
register
mail settings
Submitter Gregory Szorc
Date July 9, 2017, 11:46 p.m.
Message ID <fa6223b9e2a0d9fbfa81.1499643976@ubuntu-vm-main>
Download mbox | patch
Permalink /patch/22195/
State Accepted
Headers show

Comments

Gregory Szorc - July 9, 2017, 11:46 p.m.
# HG changeset patch
# User Gregory Szorc <gregory.szorc@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.
Jun Wu - July 10, 2017, 4:21 a.m.
Excerpts from Gregory Szorc's message of 2017-07-09 16:46:16 -0700:
> [...]
> @@ -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')

Should we check if curses is None here? It seems "debugcolor" will call this
and could be problematic on Windows.
Gregory Szorc - July 10, 2017, 4:27 a.m.
On Sun, Jul 9, 2017 at 9:21 PM, Jun Wu <quark@fb.com> wrote:

> Excerpts from Gregory Szorc's message of 2017-07-09 16:46:16 -0700:
> > [...]
> > @@ -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')
>
> Should we check if curses is None here? It seems "debugcolor" will call
> this
> and could be problematic on Windows.
>

Yes.
Kyle Lippincott - July 10, 2017, 11:32 p.m.
On Sun, Jul 9, 2017 at 4:46 PM, Gregory Szorc <gregory.szorc@gmail.com>
wrote:

> # HG changeset patch
> # User Gregory Szorc <gregory.szorc@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.

+
> +    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@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>
Gregory Szorc - July 11, 2017, 12:26 a.m.
On Mon, Jul 10, 2017 at 4:32 PM, Kyle Lippincott <spectral@pewpew.net>
wrote:

>
>
> On Sun, Jul 9, 2017 at 4:46 PM, Gregory Szorc <gregory.szorc@gmail.com>
> wrote:
>
>> # HG changeset patch
>> # User Gregory Szorc <gregory.szorc@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.

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@mercurial-scm.org
>> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>>
>
>
Kyle Lippincott - July 11, 2017, 2:44 a.m.
On Mon, Jul 10, 2017 at 5:26 PM, Gregory Szorc <gregory.szorc@gmail.com>
wrote:

> On Mon, Jul 10, 2017 at 4:32 PM, Kyle Lippincott <spectral@pewpew.net>
> wrote:
>
>>
>>
>> On Sun, Jul 9, 2017 at 4:46 PM, Gregory Szorc <gregory.szorc@gmail.com>
>> wrote:
>>
>>> # HG changeset patch
>>> # User Gregory Szorc <gregory.szorc@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@mercurial-scm.org
>>> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>>>
>>
>>
>
Gregory Szorc - July 11, 2017, 4:23 a.m.
On Mon, Jul 10, 2017 at 7:44 PM, Kyle Lippincott <spectral@pewpew.net>
wrote:

>
>
> On Mon, Jul 10, 2017 at 5:26 PM, Gregory Szorc <gregory.szorc@gmail.com>
> wrote:
>
>> On Mon, Jul 10, 2017 at 4:32 PM, Kyle Lippincott <spectral@pewpew.net>
>> wrote:
>>
>>>
>>>
>>> On Sun, Jul 9, 2017 at 4:46 PM, Gregory Szorc <gregory.szorc@gmail.com>
>>> wrote:
>>>
>>>> # HG changeset patch
>>>> # User Gregory Szorc <gregory.szorc@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?
>

I want to believe simplicity is sufficient here. I really do. However, I've
broken random tools and workflows as part of adding terminal magic to the
Firefox build system a handful of times. I've learned the hard way that no
matter how hard you try to make things "just work," someone will come up
with a valid use case where they need fine control over terminal behavior
or at the very least a kill switch to revert to plain ascii. For example:

* User calls out to Mercurial from both a normal terminal and Emacs.
Because reasons, the Emacs environment is configured very differently from
a normal terminal. Hilarity ensues.
* You use a shared Mercurial config from cmd.exe, an msys shell, and WSL on
the same machine. Each have vastly different terminal profiles.

Because the Mercurial UX can be greatly enriched by proper use of color,
I'd like to strive for preserving maximum color support in as many
scenarios as possible. Unfortunately, I think that means a bit of extra
flexibility and complexity at the config layer :/


>
>
>>
>> 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@mercurial-scm.org
>>>> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>>>>
>>>
>>>
>>
>

Patch

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)
+
+    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