##// END OF EJS Templates
win32mbcs: fix a `str` type conditional for py3...
win32mbcs: fix a `str` type conditional for py3 Differential Revision: https://phab.mercurial-scm.org/D7535

File last commit:

r43812:2fe6121c default
r44181:66210a20 stable
Show More
color.py
574 lines | 18.2 KiB | text/x-python | PythonLexer
Pierre-Yves David
color: move hgext.color._styles to mercurial.color.style...
r30652 # utility for color output for Mercurial commands
#
# Copyright (C) 2007 Kevin Christen <kevin.christen@gmail.com> and other
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
Yuya Nishihara
templater: make pad() strip color codes before computing width (issue5416)...
r31521 import re
Pierre-Yves David
color: move configstyles into the core module...
r30971 from .i18n import _
Gregory Szorc
py3: manually import getattr where it is needed...
r43359 from .pycompat import getattr
Pierre-Yves David
color: move configstyles into the core module...
r30971
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101 from . import (
encoding,
pycompat,
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 )
Augie Fackler
formatting: blacken the codebase...
r43346 from .utils import stringutil
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067
Pierre-Yves David
color: move '_terminfo_params' into the core 'color' module...
r30968 try:
import curses
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
color: move '_terminfo_params' into the core 'color' module...
r30968 # Mapping from effect name to terminfo attribute name (or raw code) or
# color number. This will also force-load the curses module.
Pierre-Yves David
color: move the dict with terminfo parameters on the ui object...
r31113 _baseterminfoparams = {
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'none': (True, b'sgr0', b''),
b'standout': (True, b'smso', b''),
b'underline': (True, b'smul', b''),
b'reverse': (True, b'rev', b''),
b'inverse': (True, b'rev', b''),
b'blink': (True, b'blink', b''),
b'dim': (True, b'dim', b''),
b'bold': (True, b'bold', b''),
b'invisible': (True, b'invis', b''),
b'italic': (True, b'sitm', b''),
b'black': (False, curses.COLOR_BLACK, b''),
b'red': (False, curses.COLOR_RED, b''),
b'green': (False, curses.COLOR_GREEN, b''),
b'yellow': (False, curses.COLOR_YELLOW, b''),
b'blue': (False, curses.COLOR_BLUE, b''),
b'magenta': (False, curses.COLOR_MAGENTA, b''),
b'cyan': (False, curses.COLOR_CYAN, b''),
b'white': (False, curses.COLOR_WHITE, b''),
Pierre-Yves David
color: reinvent dictionary...
r31109 }
Pierre-Yves David
color: move '_terminfo_params' into the core 'color' module...
r30968 except ImportError:
curses = None
Pierre-Yves David
color: move the dict with terminfo parameters on the ui object...
r31113 _baseterminfoparams = {}
Pierre-Yves David
color: move '_terminfo_params' into the core 'color' module...
r30968
Pierre-Yves David
color: move '_effect' mapping into core...
r30967 # start and stop parameters for effects
Pierre-Yves David
color: reinvent dictionary...
r31109 _effects = {
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'none': 0,
b'black': 30,
b'red': 31,
b'green': 32,
b'yellow': 33,
b'blue': 34,
b'magenta': 35,
b'cyan': 36,
b'white': 37,
b'bold': 1,
b'italic': 3,
b'underline': 4,
b'inverse': 7,
b'dim': 2,
b'black_background': 40,
b'red_background': 41,
b'green_background': 42,
b'yellow_background': 43,
b'blue_background': 44,
b'purple_background': 45,
b'cyan_background': 46,
b'white_background': 47,
Augie Fackler
formatting: blacken the codebase...
r43346 }
Pierre-Yves David
color: move '_effect' mapping into core...
r30967
Pierre-Yves David
color: rename '_styles' to '_defaultstyles' for clarity...
r31116 _defaultstyles = {
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'grep.match': b'red bold',
b'grep.linenumber': b'green',
b'grep.rev': b'blue',
b'grep.sep': b'cyan',
b'grep.filename': b'magenta',
b'grep.user': b'magenta',
b'grep.date': b'magenta',
b'grep.inserted': b'green bold',
b'grep.deleted': b'red bold',
b'bookmarks.active': b'green',
b'branches.active': b'none',
b'branches.closed': b'black bold',
b'branches.current': b'green',
b'branches.inactive': b'none',
b'diff.changed': b'white',
b'diff.deleted': b'red',
b'diff.deleted.changed': b'red bold underline',
b'diff.deleted.unchanged': b'red',
b'diff.diffline': b'bold',
b'diff.extended': b'cyan bold',
b'diff.file_a': b'red bold',
b'diff.file_b': b'green bold',
b'diff.hunk': b'magenta',
b'diff.inserted': b'green',
b'diff.inserted.changed': b'green bold underline',
b'diff.inserted.unchanged': b'green',
b'diff.tab': b'',
b'diff.trailingwhitespace': b'bold red_background',
b'changeset.public': b'',
b'changeset.draft': b'',
b'changeset.secret': b'',
b'diffstat.deleted': b'red',
b'diffstat.inserted': b'green',
b'formatvariant.name.mismatchconfig': b'red',
b'formatvariant.name.mismatchdefault': b'yellow',
b'formatvariant.name.uptodate': b'green',
b'formatvariant.repo.mismatchconfig': b'red',
b'formatvariant.repo.mismatchdefault': b'yellow',
b'formatvariant.repo.uptodate': b'green',
b'formatvariant.config.special': b'yellow',
b'formatvariant.config.default': b'green',
b'formatvariant.default': b'',
b'histedit.remaining': b'red bold',
b'ui.addremove.added': b'green',
b'ui.addremove.removed': b'red',
b'ui.error': b'red',
b'ui.prompt': b'yellow',
b'log.changeset': b'yellow',
b'patchbomb.finalsummary': b'',
b'patchbomb.from': b'magenta',
b'patchbomb.to': b'cyan',
b'patchbomb.subject': b'green',
b'patchbomb.diffstats': b'',
b'rebase.rebased': b'blue',
b'rebase.remaining': b'red bold',
b'resolve.resolved': b'green bold',
b'resolve.unresolved': b'red bold',
b'shelve.age': b'cyan',
b'shelve.newest': b'green bold',
b'shelve.name': b'blue bold',
b'status.added': b'green bold',
b'status.clean': b'none',
b'status.copied': b'none',
b'status.deleted': b'cyan bold underline',
b'status.ignored': b'black bold',
b'status.modified': b'blue bold',
b'status.removed': b'red bold',
b'status.unknown': b'magenta bold underline',
b'tags.normal': b'green',
b'tags.local': b'black bold',
Pierre-Yves David
color: reinvent dictionary...
r31109 }
Pierre-Yves David
color: load 'colortable' from extension using an 'extraloader'...
r30653
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
color: load 'colortable' from extension using an 'extraloader'...
r30653 def loadcolortable(ui, extname, colortable):
Pierre-Yves David
color: rename '_styles' to '_defaultstyles' for clarity...
r31116 _defaultstyles.update(colortable)
Pierre-Yves David
color: move 'valideffect' function into the core module
r30969
Augie Fackler
formatting: blacken the codebase...
r43346
Kyle Lippincott
color: remove warnings if term is not formatted (==dumb or !ui.formatted())...
r33643 def _terminfosetup(ui, mode, formatted):
Pierre-Yves David
color: move 'terminfosetup' into the core module...
r31100 '''Initialize terminfo data and the terminal if we're in terminfo mode.'''
# If we failed to load curses, we go ahead and return.
if curses is None:
return
# Otherwise, see what the config file says.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if mode not in (b'auto', b'terminfo'):
Pierre-Yves David
color: move 'terminfosetup' into the core module...
r31100 return
Pierre-Yves David
color: move the dict with terminfo parameters on the ui object...
r31113 ui._terminfoparams.update(_baseterminfoparams)
Pierre-Yves David
color: move 'terminfosetup' into the core module...
r31100
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for key, val in ui.configitems(b'color'):
if key.startswith(b'color.'):
newval = (False, int(val), b'')
Pierre-Yves David
color: move the dict with terminfo parameters on the ui object...
r31113 ui._terminfoparams[key[6:]] = newval
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif key.startswith(b'terminfo.'):
newval = (True, b'', val.replace(b'\\E', b'\x1b'))
Pierre-Yves David
color: move the dict with terminfo parameters on the ui object...
r31113 ui._terminfoparams[key[9:]] = newval
Pierre-Yves David
color: move 'terminfosetup' into the core module...
r31100 try:
curses.setupterm()
Martin von Zweigbergk
cleanup: delete lots of unused local variables...
r41401 except curses.error:
Pierre-Yves David
color: move the dict with terminfo parameters on the ui object...
r31113 ui._terminfoparams.clear()
Pierre-Yves David
color: move 'terminfosetup' into the core module...
r31100 return
Pulkit Goyal
py3: iterate over a copy of dict while changing it...
r37680 for key, (b, e, c) in ui._terminfoparams.copy().items():
Pierre-Yves David
color: move 'terminfosetup' into the core module...
r31100 if not b:
continue
Pulkit Goyal
py3: make sure curses.tigetstr() first argument is a str...
r37682 if not c and not curses.tigetstr(pycompat.sysstr(e)):
Pierre-Yves David
color: move 'terminfosetup' into the core module...
r31100 # Most terminals don't support dim, invis, etc, so don't be
# noisy and use ui.debug().
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.debug(b"no terminfo entry for %s\n" % e)
Pierre-Yves David
color: move the dict with terminfo parameters on the ui object...
r31113 del ui._terminfoparams[key]
Pulkit Goyal
py3: make sure curses.tigetstr() first argument is a str...
r37682 if not curses.tigetstr(r'setaf') or not curses.tigetstr(r'setab'):
Pierre-Yves David
color: move 'terminfosetup' into the core module...
r31100 # Only warn about missing terminfo entries if we explicitly asked for
Kyle Lippincott
color: remove warnings if term is not formatted (==dumb or !ui.formatted())...
r33643 # terminfo mode and we're in a formatted terminal.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if mode == b"terminfo" and formatted:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.warn(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"no terminfo entry for setab/setaf: reverting to "
b"ECMA-48 color\n"
Augie Fackler
formatting: blacken the codebase...
r43346 )
)
Pierre-Yves David
color: move the dict with terminfo parameters on the ui object...
r31113 ui._terminfoparams.clear()
Pierre-Yves David
color: move 'terminfosetup' into the core module...
r31100
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
color: add a 'ui.color' option to control color behavior...
r31110 def setup(ui):
Pierre-Yves David
color: move triggering of the initialisation logic in core...
r31105 """configure color on a ui
Pierre-Yves David
color: add a 'ui.color' option to control color behavior...
r31110 That function both set the colormode for the ui object and read
Pierre-Yves David
color: move triggering of the initialisation logic in core...
r31105 the configuration looking for custom colors and effect definitions."""
Pierre-Yves David
color: add a 'ui.color' option to control color behavior...
r31110 mode = _modesetup(ui)
Pierre-Yves David
color: have the 'ui' object carry the '_colormode' directly...
r31106 ui._colormode = mode
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if mode and mode != b'debug':
Pierre-Yves David
color: move triggering of the initialisation logic in core...
r31105 configstyles(ui)
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
color: add a 'ui.color' option to control color behavior...
r31110 def _modesetup(ui):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if ui.plain(b'color'):
Pierre-Yves David
color: handle 'ui.plain()' directly in mode setup...
r31103 return None
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 config = ui.config(b'ui', b'color')
if config == b'debug':
return b'debug'
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 auto = config == b'auto'
Pierre-Yves David
color: turn 'ui.color' into a boolean (auto or off)...
r32103 always = False
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 if not auto and stringutil.parsebool(config):
Pierre-Yves David
color: special case 'always' in 'ui.color'...
r32104 # We want the config to behave like a boolean, "on" is actually auto,
# but "always" value is treated as a special case to reduce confusion.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if (
ui.configsource(b'ui', b'color') == b'--color'
or config == b'always'
):
Pierre-Yves David
color: turn 'ui.color' into a boolean (auto or off)...
r32103 always = True
else:
auto = True
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101 if not always and not auto:
return None
Augie Fackler
formatting: blacken the codebase...
r43346 formatted = always or (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 encoding.environ.get(b'TERM') != b'dumb' and ui.formatted()
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 mode = ui.config(b'color', b'mode')
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101
# If pager is active, color.pagermode overrides color.mode.
if getattr(ui, 'pageractive', False):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 mode = ui.config(b'color', b'pagermode', mode)
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101
realmode = mode
Jun Wu
codemod: use pycompat.iswindows...
r34646 if pycompat.iswindows:
Matt Harbison
color: enable ANSI support on Windows 10...
r32665 from . import win32
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 term = encoding.environ.get(b'TERM')
Matt Harbison
color: enable ANSI support on Windows 10...
r32665 # TERM won't be defined in a vanilla cmd.exe environment.
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101
Matt Harbison
color: enable ANSI support on Windows 10...
r32665 # UNIX-like environments on Windows such as Cygwin and MSYS will
# set TERM. They appear to make a best effort attempt at setting it
# to something appropriate. However, not all environments with TERM
# defined support ANSI.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ansienviron = term and b'xterm' in term
Matt Harbison
color: enable ANSI support on Windows 10...
r32665
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if mode == b'auto':
Matt Harbison
color: enable ANSI support on Windows 10...
r32665 # Since "ansi" could result in terminal gibberish, we error on the
# side of selecting "win32". However, if w32effects is not defined,
# we almost certainly don't support "win32", so don't even try.
Matt Harbison
color: fix a documentation typo
r41006 # w32effects is not populated when stdout is redirected, so checking
Matt Harbison
color: enable ANSI support on Windows 10...
r32665 # it first avoids win32 calls in a state known to error out.
if ansienviron or not w32effects or win32.enablevtmode():
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 realmode = b'ansi'
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 realmode = b'win32'
Matt Harbison
color: enable ANSI support on Windows 10...
r32665 # An empty w32effects is a clue that stdout is redirected, and thus
# cannot enable VT mode.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif mode == b'ansi' and w32effects and not ansienviron:
Matt Harbison
color: enable ANSI support on Windows 10...
r32665 win32.enablevtmode()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif mode == b'auto':
realmode = b'ansi'
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101
def modewarn():
# only warn if color.mode was explicitly set and we're in
# a formatted terminal
Kyle Lippincott
color: remove warnings if term is not formatted (==dumb or !ui.formatted())...
r33643 if mode == realmode and formatted:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.warn(_(b'warning: failed to set color mode to %s\n') % mode)
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if realmode == b'win32':
Pierre-Yves David
color: move the dict with terminfo parameters on the ui object...
r31113 ui._terminfoparams.clear()
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101 if not w32effects:
modewarn()
return None
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif realmode == b'ansi':
Pierre-Yves David
color: move the dict with terminfo parameters on the ui object...
r31113 ui._terminfoparams.clear()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif realmode == b'terminfo':
Kyle Lippincott
color: remove warnings if term is not formatted (==dumb or !ui.formatted())...
r33643 _terminfosetup(ui, mode, formatted)
Pierre-Yves David
color: move the dict with terminfo parameters on the ui object...
r31113 if not ui._terminfoparams:
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101 ## FIXME Shouldn't we return None in this case too?
modewarn()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 realmode = b'ansi'
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101 else:
return None
if always or (auto and formatted):
return realmode
return None
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
color: move configstyles into the core module...
r30971 def configstyles(ui):
Pierre-Yves David
color: rename '_styles' to '_defaultstyles' for clarity...
r31116 ui._styles.update(_defaultstyles)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for status, cfgeffects in ui.configitems(b'color'):
if b'.' not in status or status.startswith((b'color.', b'terminfo.')):
Pierre-Yves David
color: move configstyles into the core module...
r30971 continue
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cfgeffects = ui.configlist(b'color', status)
Pierre-Yves David
color: move configstyles into the core module...
r30971 if cfgeffects:
good = []
for e in cfgeffects:
Pierre-Yves David
color: add ui to effect rendering...
r31112 if valideffect(ui, e):
Pierre-Yves David
color: move configstyles into the core module...
r30971 good.append(e)
else:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.warn(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"ignoring unknown color/effect %s "
b"(configured in color.%s)\n"
Augie Fackler
formatting: blacken the codebase...
r43346 )
% (stringutil.pprint(e), status)
)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui._styles[status] = b' '.join(good)
Pierre-Yves David
color: move configstyles into the core module...
r30971
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
color: stop mutating the default effects map...
r31689 def _activeeffects(ui):
'''Return the effects map for the color mode set on the ui.'''
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if ui._colormode == b'win32':
Matt Harbison
color: stop mutating the default effects map...
r31689 return w32effects
elif ui._colormode is not None:
return _effects
return {}
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
color: add ui to effect rendering...
r31112 def valideffect(ui, effect):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'Determine if the effect is valid or not.'
Augie Fackler
formatting: blacken the codebase...
r43346 return (not ui._terminfoparams and effect in _activeeffects(ui)) or (
effect in ui._terminfoparams or effect[:-11] in ui._terminfoparams
)
Pierre-Yves David
color: move '_effect_str' function into the core module
r30972
Pierre-Yves David
color: add ui to effect rendering...
r31112 def _effect_str(ui, effect):
Pierre-Yves David
color: move '_effect_str' function into the core module
r30972 '''Helper function for render_effects().'''
bg = False
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if effect.endswith(b'_background'):
Pierre-Yves David
color: move '_effect_str' function into the core module
r30972 bg = True
effect = effect[:-11]
try:
Pierre-Yves David
color: move the dict with terminfo parameters on the ui object...
r31113 attr, val, termcode = ui._terminfoparams[effect]
Pierre-Yves David
color: move '_effect_str' function into the core module
r30972 except KeyError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b''
Pierre-Yves David
color: move '_effect_str' function into the core module
r30972 if attr:
if termcode:
return termcode
else:
Pulkit Goyal
py3: make sure curses.tigetstr() first argument is a str...
r37682 return curses.tigetstr(pycompat.sysstr(val))
Pierre-Yves David
color: move '_effect_str' function into the core module
r30972 elif bg:
Pulkit Goyal
py3: make sure curses.tigetstr() first argument is a str...
r37682 return curses.tparm(curses.tigetstr(r'setab'), val)
Pierre-Yves David
color: move '_effect_str' function into the core module
r30972 else:
Pulkit Goyal
py3: make sure curses.tigetstr() first argument is a str...
r37682 return curses.tparm(curses.tigetstr(r'setaf'), val)
Pierre-Yves David
color: move the '_render_effects' function to the core module
r30973
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
color: insert color code after every "\e[0m" (issue5413)...
r31518 def _mergeeffects(text, start, stop):
"""Insert start sequence at every occurrence of stop sequence
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> s = _mergeeffects(b'cyan', b'[C]', b'|')
>>> s = _mergeeffects(s + b'yellow', b'[Y]', b'|')
>>> s = _mergeeffects(b'ma' + s + b'genta', b'[M]', b'|')
>>> s = _mergeeffects(b'red' + s, b'[R]', b'|')
Yuya Nishihara
color: insert color code after every "\e[0m" (issue5413)...
r31518 >>> s
'[R]red[M]ma[Y][C]cyan|[R][M][Y]yellow|[R][M]genta|'
"""
parts = []
for t in text.split(stop):
if not t:
continue
parts.extend([start, t, stop])
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b''.join(parts)
Yuya Nishihara
color: insert color code after every "\e[0m" (issue5413)...
r31518
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
color: add ui to effect rendering...
r31112 def _render_effects(ui, text, effects):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'Wrap text in commands to turn on each effect.'
Pierre-Yves David
color: move the '_render_effects' function to the core module
r30973 if not text:
return text
Pierre-Yves David
color: move the dict with terminfo parameters on the ui object...
r31113 if ui._terminfoparams:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 start = b''.join(
_effect_str(ui, effect) for effect in [b'none'] + effects.split()
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 stop = _effect_str(ui, b'none')
Pierre-Yves David
color: minor reversal of two conditional clause for clarity...
r31071 else:
Matt Harbison
color: stop mutating the default effects map...
r31689 activeeffects = _activeeffects(ui)
Augie Fackler
formatting: blacken the codebase...
r43346 start = [
pycompat.bytestr(activeeffects[e])
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for e in [b'none'] + effects.split()
Augie Fackler
formatting: blacken the codebase...
r43346 ]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 start = b'\033[' + b';'.join(start) + b'm'
stop = b'\033[' + pycompat.bytestr(activeeffects[b'none']) + b'm'
Yuya Nishihara
color: insert color code after every "\e[0m" (issue5413)...
r31518 return _mergeeffects(text, start, stop)
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
templater: make pad() strip color codes before computing width (issue5416)...
r31521 _ansieffectre = re.compile(br'\x1b\[[0-9;]*m')
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
templater: make pad() strip color codes before computing width (issue5416)...
r31521 def stripeffects(text):
"""Strip ANSI control codes which could be inserted by colorlabel()"""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return _ansieffectre.sub(b'', text)
Yuya Nishihara
templater: make pad() strip color codes before computing width (issue5416)...
r31521
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
color: move the 'colorlabel' function in the core module...
r31086 def colorlabel(ui, msg, label):
"""add color control code according to the mode"""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if ui._colormode == b'debug':
Pierre-Yves David
color: move the 'colorlabel' function in the core module...
r31086 if label and msg:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if msg.endswith(b'\n'):
msg = b"[%s|%s]\n" % (label, msg[:-1])
Pierre-Yves David
color: move the 'colorlabel' function in the core module...
r31086 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = b"[%s|%s]" % (label, msg)
Pierre-Yves David
color: move the 'colorlabel' function in the core module...
r31086 elif ui._colormode is not None:
effects = []
for l in label.split():
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s = ui._styles.get(l, b'')
Pierre-Yves David
color: move the 'colorlabel' function in the core module...
r31086 if s:
effects.append(s)
Pierre-Yves David
color: add ui to effect rendering...
r31112 elif valideffect(ui, l):
Pierre-Yves David
color: move the 'colorlabel' function in the core module...
r31086 effects.append(l)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 effects = b' '.join(effects)
Pierre-Yves David
color: move the 'colorlabel' function in the core module...
r31086 if effects:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = b'\n'.join(
[
_render_effects(ui, line, effects)
for line in msg.split(b'\n')
]
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pierre-Yves David
color: move the 'colorlabel' function in the core module...
r31086 return msg
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067 w32effects = None
Jun Wu
codemod: use pycompat.iswindows...
r34646 if pycompat.iswindows:
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067 import ctypes
_kernel32 = ctypes.windll.kernel32
_WORD = ctypes.c_ushort
_INVALID_HANDLE_VALUE = -1
class _COORD(ctypes.Structure):
Augie Fackler
formatting: blacken the codebase...
r43346 _fields_ = [(r'X', ctypes.c_short), (r'Y', ctypes.c_short)]
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067
class _SMALL_RECT(ctypes.Structure):
Augie Fackler
formatting: blacken the codebase...
r43346 _fields_ = [
(r'Left', ctypes.c_short),
(r'Top', ctypes.c_short),
(r'Right', ctypes.c_short),
(r'Bottom', ctypes.c_short),
]
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067
class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
Augie Fackler
formatting: blacken the codebase...
r43346 _fields_ = [
(r'dwSize', _COORD),
(r'dwCursorPosition', _COORD),
(r'wAttributes', _WORD),
(r'srWindow', _SMALL_RECT),
(r'dwMaximumWindowSize', _COORD),
]
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067
Augie Fackler
formatting: blacken the codebase...
r43346 _STD_OUTPUT_HANDLE = 0xFFFFFFF5 # (DWORD)-11
_STD_ERROR_HANDLE = 0xFFFFFFF4 # (DWORD)-12
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067
_FOREGROUND_BLUE = 0x0001
_FOREGROUND_GREEN = 0x0002
_FOREGROUND_RED = 0x0004
_FOREGROUND_INTENSITY = 0x0008
_BACKGROUND_BLUE = 0x0010
_BACKGROUND_GREEN = 0x0020
_BACKGROUND_RED = 0x0040
_BACKGROUND_INTENSITY = 0x0080
_COMMON_LVB_REVERSE_VIDEO = 0x4000
_COMMON_LVB_UNDERSCORE = 0x8000
# http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
w32effects = {
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'none': -1,
b'black': 0,
b'red': _FOREGROUND_RED,
b'green': _FOREGROUND_GREEN,
b'yellow': _FOREGROUND_RED | _FOREGROUND_GREEN,
b'blue': _FOREGROUND_BLUE,
b'magenta': _FOREGROUND_BLUE | _FOREGROUND_RED,
b'cyan': _FOREGROUND_BLUE | _FOREGROUND_GREEN,
b'white': _FOREGROUND_RED | _FOREGROUND_GREEN | _FOREGROUND_BLUE,
b'bold': _FOREGROUND_INTENSITY,
b'black_background': 0x100, # unused value > 0x0f
b'red_background': _BACKGROUND_RED,
b'green_background': _BACKGROUND_GREEN,
b'yellow_background': _BACKGROUND_RED | _BACKGROUND_GREEN,
b'blue_background': _BACKGROUND_BLUE,
b'purple_background': _BACKGROUND_BLUE | _BACKGROUND_RED,
b'cyan_background': _BACKGROUND_BLUE | _BACKGROUND_GREEN,
b'white_background': (
Augie Fackler
formatting: blacken the codebase...
r43346 _BACKGROUND_RED | _BACKGROUND_GREEN | _BACKGROUND_BLUE
),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'bold_background': _BACKGROUND_INTENSITY,
b'underline': _COMMON_LVB_UNDERSCORE, # double-byte charsets only
b'inverse': _COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067 }
Augie Fackler
formatting: blacken the codebase...
r43346 passthrough = {
_FOREGROUND_INTENSITY,
_BACKGROUND_INTENSITY,
_COMMON_LVB_UNDERSCORE,
_COMMON_LVB_REVERSE_VIDEO,
}
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067
stdout = _kernel32.GetStdHandle(
Augie Fackler
formatting: blacken the codebase...
r43346 _STD_OUTPUT_HANDLE
) # don't close the handle returned
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067 if stdout is None or stdout == _INVALID_HANDLE_VALUE:
w32effects = None
else:
csbi = _CONSOLE_SCREEN_BUFFER_INFO()
Augie Fackler
formatting: blacken the codebase...
r43346 if not _kernel32.GetConsoleScreenBufferInfo(stdout, ctypes.byref(csbi)):
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067 # stdout may not support GetConsoleScreenBufferInfo()
# when called from subprocess or redirected
w32effects = None
else:
origattr = csbi.wAttributes
Augie Fackler
formatting: blacken the codebase...
r43346 ansire = re.compile(
br'\033\[([^m]*)m([^\033]*)(.*)', re.MULTILINE | re.DOTALL
)
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067
Yuya Nishihara
ui: simply concatenate messages before applying color labels...
r40557 def win32print(ui, writefunc, text, **opts):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 label = opts.get(r'label', b'')
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067 attr = origattr
def mapcolor(val, attr):
if val == -1:
return origattr
elif val in passthrough:
return attr | val
Augie Fackler
formatting: blacken the codebase...
r43346 elif val > 0x0F:
return (val & 0x70) | (attr & 0x8F)
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067 else:
Augie Fackler
formatting: blacken the codebase...
r43346 return (val & 0x07) | (attr & 0xF8)
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067
# determine console attributes based on labels
for l in label.split():
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 style = ui._styles.get(l, b'')
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067 for effect in style.split():
try:
attr = mapcolor(w32effects[effect], attr)
except KeyError:
# w32effects could not have certain attributes so we skip
# them if not found
pass
# hack to ensure regexp finds data
Matt Harbison
py3: fix str vs bytes in enough places to run `hg version` on Windows...
r39680 if not text.startswith(b'\033['):
text = b'\033[m' + text
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067
# Look for ANSI-like codes embedded in text
m = re.match(ansire, text)
try:
while m:
Matt Harbison
py3: fix str vs bytes in enough places to run `hg version` on Windows...
r39680 for sattr in m.group(1).split(b';'):
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067 if sattr:
attr = mapcolor(int(sattr), attr)
Matt Harbison
color: sync text attributes and buffered text output on Windows (issue5508)...
r31499 ui.flush()
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067 _kernel32.SetConsoleTextAttribute(stdout, attr)
Yuya Nishihara
ui: simplify interface of low-level write() functions...
r40556 writefunc(m.group(2))
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067 m = re.match(ansire, m.group(3))
finally:
# Explicitly reset original attributes
Matt Harbison
color: sync text attributes and buffered text output on Windows (issue5508)...
r31499 ui.flush()
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067 _kernel32.SetConsoleTextAttribute(stdout, origattr)