##// END OF EJS Templates
merge with stable
merge with stable

File last commit:

r41888:c3c942c8 default
r42614:381d8fa5 merge default
Show More
color.py
534 lines | 17.7 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 _
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 )
from .utils import (
stringutil,
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101 )
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
# 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 = {
Pierre-Yves David
color: reinvent dictionary...
r31109 'none': (True, 'sgr0', ''),
'standout': (True, 'smso', ''),
'underline': (True, 'smul', ''),
'reverse': (True, 'rev', ''),
'inverse': (True, 'rev', ''),
'blink': (True, 'blink', ''),
'dim': (True, 'dim', ''),
'bold': (True, 'bold', ''),
'invisible': (True, 'invis', ''),
'italic': (True, 'sitm', ''),
'black': (False, curses.COLOR_BLACK, ''),
'red': (False, curses.COLOR_RED, ''),
'green': (False, curses.COLOR_GREEN, ''),
'yellow': (False, curses.COLOR_YELLOW, ''),
'blue': (False, curses.COLOR_BLUE, ''),
'magenta': (False, curses.COLOR_MAGENTA, ''),
'cyan': (False, curses.COLOR_CYAN, ''),
'white': (False, curses.COLOR_WHITE, ''),
}
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 = {
'none': 0,
'black': 30,
'red': 31,
'green': 32,
'yellow': 33,
'blue': 34,
'magenta': 35,
'cyan': 36,
'white': 37,
'bold': 1,
'italic': 3,
'underline': 4,
'inverse': 7,
'dim': 2,
'black_background': 40,
'red_background': 41,
'green_background': 42,
'yellow_background': 43,
'blue_background': 44,
'purple_background': 45,
'cyan_background': 46,
'white_background': 47,
}
Pierre-Yves David
color: move '_effect' mapping into core...
r30967
Pierre-Yves David
color: rename '_styles' to '_defaultstyles' for clarity...
r31116 _defaultstyles = {
Pierre-Yves David
color: reinvent dictionary...
r31109 'grep.match': 'red bold',
'grep.linenumber': 'green',
Jordi GutiƩrrez Hermoso
color: change color of grep.rev label (BC)...
r41889 'grep.rev': 'blue',
Pierre-Yves David
color: reinvent dictionary...
r31109 'grep.sep': 'cyan',
'grep.filename': 'magenta',
'grep.user': 'magenta',
'grep.date': 'magenta',
Jordi GutiƩrrez Hermoso
color: give colours to the grep.inserted and grep.deleted labels...
r41887 'grep.inserted': 'green bold',
'grep.deleted': 'red bold',
Pierre-Yves David
color: reinvent dictionary...
r31109 'bookmarks.active': 'green',
'branches.active': 'none',
'branches.closed': 'black bold',
'branches.current': 'green',
'branches.inactive': 'none',
'diff.changed': 'white',
'diff.deleted': 'red',
Yuya Nishihara
diff: restore original color scheme for worddiff...
r37817 'diff.deleted.changed': 'red bold underline',
'diff.deleted.unchanged': 'red',
Pierre-Yves David
color: reinvent dictionary...
r31109 'diff.diffline': 'bold',
'diff.extended': 'cyan bold',
'diff.file_a': 'red bold',
'diff.file_b': 'green bold',
'diff.hunk': 'magenta',
'diff.inserted': 'green',
Yuya Nishihara
diff: restore original color scheme for worddiff...
r37817 'diff.inserted.changed': 'green bold underline',
'diff.inserted.unchanged': 'green',
Pierre-Yves David
color: reinvent dictionary...
r31109 'diff.tab': '',
'diff.trailingwhitespace': 'bold red_background',
Alex Gaynor
style: never use a space before a colon or comma...
r34487 'changeset.public': '',
'changeset.draft': '',
'changeset.secret': '',
Pierre-Yves David
color: reinvent dictionary...
r31109 'diffstat.deleted': 'red',
'diffstat.inserted': 'green',
Boris Feld
debugformat: update label depending on value difference...
r35339 'formatvariant.name.mismatchconfig': 'red',
'formatvariant.name.mismatchdefault': 'yellow',
'formatvariant.name.uptodate': 'green',
'formatvariant.repo.mismatchconfig': 'red',
'formatvariant.repo.mismatchdefault': 'yellow',
'formatvariant.repo.uptodate': 'green',
'formatvariant.config.special': 'yellow',
'formatvariant.config.default': 'green',
'formatvariant.default': '',
Pierre-Yves David
color: reinvent dictionary...
r31109 'histedit.remaining': 'red bold',
Yuya Nishihara
addremove: add "ui." prefix to message color keys...
r40403 'ui.addremove.added': 'green',
'ui.addremove.removed': 'red',
Rodrigo Damazio Bovendorp
dispatch: making all hg abortions be output with a specific label...
r38791 'ui.error': 'red',
Pierre-Yves David
color: reinvent dictionary...
r31109 'ui.prompt': 'yellow',
'log.changeset': 'yellow',
'patchbomb.finalsummary': '',
'patchbomb.from': 'magenta',
'patchbomb.to': 'cyan',
'patchbomb.subject': 'green',
'patchbomb.diffstats': '',
'rebase.rebased': 'blue',
'rebase.remaining': 'red bold',
'resolve.resolved': 'green bold',
'resolve.unresolved': 'red bold',
'shelve.age': 'cyan',
'shelve.newest': 'green bold',
'shelve.name': 'blue bold',
'status.added': 'green bold',
'status.clean': 'none',
'status.copied': 'none',
'status.deleted': 'cyan bold underline',
'status.ignored': 'black bold',
'status.modified': 'blue bold',
'status.removed': 'red bold',
'status.unknown': 'magenta bold underline',
'tags.normal': 'green',
'tags.local': 'black bold',
}
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
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.
if mode not in ('auto', 'terminfo'):
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
for key, val in ui.configitems('color'):
if key.startswith('color.'):
newval = (False, int(val), '')
Pierre-Yves David
color: move the dict with terminfo parameters on the ui object...
r31113 ui._terminfoparams[key[6:]] = newval
Pierre-Yves David
color: move 'terminfosetup' into the core module...
r31100 elif key.startswith('terminfo.'):
newval = (True, '', val.replace('\\E', '\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().
ui.debug("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.
if mode == "terminfo" and formatted:
Pierre-Yves David
color: move 'terminfosetup' into the core module...
r31100 ui.warn(_("no terminfo entry for setab/setaf: reverting to "
"ECMA-48 color\n"))
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
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
Pierre-Yves David
color: move triggering of the initialisation logic in core...
r31105 if mode and mode != 'debug':
configstyles(ui)
Pierre-Yves David
color: add a 'ui.color' option to control color behavior...
r31110 def _modesetup(ui):
Augie Fackler
color: respect HGPLAINEXCEPT=color to allow colors while scripting (issue5749)...
r35176 if ui.plain('color'):
Pierre-Yves David
color: handle 'ui.plain()' directly in mode setup...
r31103 return None
Boris Feld
configitems: register the 'ui.color' config
r33522 config = ui.config('ui', 'color')
Pierre-Yves David
color: add a 'ui.color' option to control color behavior...
r31110 if config == 'debug':
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101 return 'debug'
Pierre-Yves David
color: add a 'ui.color' option to control color behavior...
r31110 auto = (config == '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.
if ui.configsource('ui', 'color') == '--color' or config == '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
formatted = (always or (encoding.environ.get('TERM') != 'dumb'
and ui.formatted()))
configitems: register the 'color.mode' config
r33176 mode = ui.config('color', '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):
mode = ui.config('color', 'pagermode', mode)
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
term = encoding.environ.get('TERM')
# 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.
ansienviron = term and 'xterm' in term
if mode == 'auto':
# 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():
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101 realmode = 'ansi'
else:
realmode = '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.
elif mode == 'ansi' and w32effects and not ansienviron:
win32.enablevtmode()
elif mode == 'auto':
realmode = '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:
Pierre-Yves David
color: move 'modesetup' into the core module...
r31101 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
if realmode == '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
elif realmode == 'ansi':
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 elif realmode == '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()
realmode = 'ansi'
else:
return None
if always or (auto and formatted):
return realmode
return None
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)
Pierre-Yves David
color: move configstyles into the core module...
r30971 for status, cfgeffects in ui.configitems('color'):
if '.' not in status or status.startswith(('color.', 'terminfo.')):
continue
cfgeffects = ui.configlist('color', status)
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:
Pulkit Goyal
py3: use stringutil.pprint() in color.py instead of '%r'...
r40259 ui.warn(_("ignoring unknown color/effect %s "
Pierre-Yves David
color: move configstyles into the core module...
r30971 "(configured in color.%s)\n")
Pulkit Goyal
py3: use stringutil.pprint() in color.py instead of '%r'...
r40259 % (stringutil.pprint(e), status))
Pierre-Yves David
color: move 'styles' definition on the 'ui' object...
r31115 ui._styles[status] = ' '.join(good)
Pierre-Yves David
color: move configstyles into the core module...
r30971
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.'''
if ui._colormode == 'win32':
return w32effects
elif ui._colormode is not None:
return _effects
return {}
Pierre-Yves David
color: add ui to effect rendering...
r31112 def valideffect(ui, effect):
Pierre-Yves David
color: move 'valideffect' function into the core module
r30969 'Determine if the effect is valid or not.'
Matt Harbison
color: stop mutating the default effects map...
r31689 return ((not ui._terminfoparams and effect in _activeeffects(ui))
Pierre-Yves David
color: move the dict with terminfo parameters on the ui object...
r31113 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
if effect.endswith('_background'):
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:
return ''
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
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])
return ''.join(parts)
Pierre-Yves David
color: add ui to effect rendering...
r31112 def _render_effects(ui, text, effects):
Pierre-Yves David
color: move the '_render_effects' function to the core module
r30973 'Wrap text in commands to turn on each effect.'
if not text:
return text
Pierre-Yves David
color: move the dict with terminfo parameters on the ui object...
r31113 if ui._terminfoparams:
Pierre-Yves David
color: add ui to effect rendering...
r31112 start = ''.join(_effect_str(ui, effect)
Pierre-Yves David
color: minor reversal of two conditional clause for clarity...
r31071 for effect in ['none'] + effects.split())
Pierre-Yves David
color: add ui to effect rendering...
r31112 stop = _effect_str(ui, '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)
Pulkit Goyal
color: replace str() with pycompat.bytestr()
r31716 start = [pycompat.bytestr(activeeffects[e])
for e in ['none'] + effects.split()]
Pierre-Yves David
color: move the '_render_effects' function to the core module
r30973 start = '\033[' + ';'.join(start) + 'm'
Pulkit Goyal
color: replace str() with pycompat.bytestr()
r31716 stop = '\033[' + pycompat.bytestr(activeeffects['none']) + '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
Yuya Nishihara
templater: make pad() strip color codes before computing width (issue5416)...
r31521 _ansieffectre = re.compile(br'\x1b\[[0-9;]*m')
def stripeffects(text):
"""Strip ANSI control codes which could be inserted by colorlabel()"""
return _ansieffectre.sub('', text)
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"""
if ui._colormode == 'debug':
if label and msg:
Yuya Nishihara
py3: use bytes.endswith('\n') to strip off '\n' from debug color output
r36520 if msg.endswith('\n'):
Pierre-Yves David
color: move the 'colorlabel' function in the core module...
r31086 msg = "[%s|%s]\n" % (label, msg[:-1])
else:
msg = "[%s|%s]" % (label, msg)
elif ui._colormode is not None:
effects = []
for l in label.split():
Pierre-Yves David
color: move 'styles' definition on the 'ui' object...
r31115 s = ui._styles.get(l, '')
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)
effects = ' '.join(effects)
if effects:
Pierre-Yves David
color: add ui to effect rendering...
r31112 msg = '\n'.join([_render_effects(ui, line, effects)
Pierre-Yves David
color: move the 'colorlabel' function in the core module...
r31086 for line in msg.split('\n')])
return msg
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):
Matt Harbison
py3: fix str vs bytes in enough places to run `hg version` on Windows...
r39680 _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):
Matt Harbison
py3: fix str vs bytes in enough places to run `hg version` on Windows...
r39680 _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):
Matt Harbison
py3: fix str vs bytes in enough places to run `hg version` on Windows...
r39680 _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
_STD_OUTPUT_HANDLE = 0xfffffff5 # (DWORD)-11
_STD_ERROR_HANDLE = 0xfffffff4 # (DWORD)-12
_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 = {
'none': -1,
'black': 0,
'red': _FOREGROUND_RED,
'green': _FOREGROUND_GREEN,
'yellow': _FOREGROUND_RED | _FOREGROUND_GREEN,
'blue': _FOREGROUND_BLUE,
'magenta': _FOREGROUND_BLUE | _FOREGROUND_RED,
'cyan': _FOREGROUND_BLUE | _FOREGROUND_GREEN,
'white': _FOREGROUND_RED | _FOREGROUND_GREEN | _FOREGROUND_BLUE,
'bold': _FOREGROUND_INTENSITY,
'black_background': 0x100, # unused value > 0x0f
'red_background': _BACKGROUND_RED,
'green_background': _BACKGROUND_GREEN,
'yellow_background': _BACKGROUND_RED | _BACKGROUND_GREEN,
'blue_background': _BACKGROUND_BLUE,
'purple_background': _BACKGROUND_BLUE | _BACKGROUND_RED,
'cyan_background': _BACKGROUND_BLUE | _BACKGROUND_GREEN,
'white_background': (_BACKGROUND_RED | _BACKGROUND_GREEN |
_BACKGROUND_BLUE),
'bold_background': _BACKGROUND_INTENSITY,
'underline': _COMMON_LVB_UNDERSCORE, # double-byte charsets only
'inverse': _COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
}
Martin von Zweigbergk
cleanup: use set literals...
r32291 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(
_STD_OUTPUT_HANDLE) # don't close the handle returned
if stdout is None or stdout == _INVALID_HANDLE_VALUE:
w32effects = None
else:
csbi = _CONSOLE_SCREEN_BUFFER_INFO()
if not _kernel32.GetConsoleScreenBufferInfo(
stdout, ctypes.byref(csbi)):
# stdout may not support GetConsoleScreenBufferInfo()
# when called from subprocess or redirected
w32effects = None
else:
origattr = csbi.wAttributes
Gregory Szorc
global: use raw strings for regular expressions with escapes...
r41673 ansire = re.compile(br'\033\[([^m]*)m([^\033]*)(.*)',
Pierre-Yves David
color: move 'win32' declaration to the core module...
r31067 re.MULTILINE | re.DOTALL)
Yuya Nishihara
ui: simply concatenate messages before applying color labels...
r40557 def win32print(ui, writefunc, text, **opts):
Pulkit Goyal
py3: handle keyword arguments correctly in color.py...
r35352 label = opts.get(r'label', '')
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
elif val > 0x0f:
return (val & 0x70) | (attr & 0x8f)
else:
return (val & 0x07) | (attr & 0xf8)
# determine console attributes based on labels
for l in label.split():
Pierre-Yves David
color: move 'styles' definition on the 'ui' object...
r31115 style = ui._styles.get(l, '')
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)