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

Kyle Lippincott spectral at pewpew.net
Mon Jul 10 19:32:56 EDT 2017


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.

+
> +    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/f8805629/attachment-0001.html>


More information about the Mercurial-devel mailing list