[PATCH 1 of 1] diff colorization, --color switch
Brodie Rao
dackze at gmail.com
Wed Nov 26 13:29:02 UTC 2008
# HG changeset patch
# User Brodie Rao <me+hg at dackz.net>
# Date 1227706077 18000
# Node ID f4201a720f4612db3309794d15bdc3a6a82cbeb6
# Parent b4ac1e2cd38c6ffb615390919cc3cc1c33652c69
diff colorization, --color switch
This colorizes diff, qdiff, log -p, outgoing -p, incoming -p, and tip -p.
--color works like GNU grep --color. --color=auto only colorizes output
for non-dumb terminals that are TTYs.
diff -r b4ac1e2cd38c -r f4201a720f46 hgext/color.py
--- a/hgext/color.py Tue Nov 25 18:45:08 2008 -0800
+++ b/hgext/color.py Wed Nov 26 08:27:57 2008 -0500
@@ -16,15 +16,16 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-'''add color output to the status and qseries commands
+'''add color output to status, qseries, and diff-related commands
This extension modifies the status command to add color to its output to
-reflect file status, and the qseries command to add color to reflect patch
-status (applied, unapplied, missing). Other effects in addition to color,
-like bold and underlined text, are also available. Effects are rendered
-with the ECMA-48 SGR control function (aka ANSI escape codes). This module
-also provides the render_text function, which can be used to add effects to
-any text.
+reflect file status, the qseries command to add color to reflect patch status
+(applied, unapplied, missing), and to diff-related commands to highlight
+additions, removals, diff headers, and trailing whitespace. Other effects in
+addition to color, like bold and underlined text, are also available.
+Effects are rendered with the ECMA-48 SGR control function (aka ANSI escape
+codes). This module also provides the render_text function, which can be
+used to add effects to any text.
To enable this extension, add this to your .hgrc file:
[extensions]
@@ -47,11 +48,21 @@
qseries.applied = blue bold underline
qseries.unapplied = black bold
qseries.missing = red bold
+
+diff.diffline = bold
+diff.extended = cyan bold
+diff.file_a = red bold
+diff.file_b = green bold
+diff.hunk = magenta
+diff.deleted = red
+diff.inserted = green
+diff.changed = white
+diff.whitespace = bold red_background
'''
-import re, sys
+import os, re, sys
-from mercurial import commands, extensions
+from mercurial import cmdutil, commands, extensions
from mercurial.i18n import _
# start and stop parameters for effects
@@ -113,7 +124,7 @@
effects = _status_effects[status]
if effects:
lines[i] = render_effects(lines[i], *effects)
- sys.stdout.write(lines[i] + delimiter)
+ ui.write(lines[i] + delimiter)
return retval
_status_abbreviations = { 'M': 'modified',
@@ -154,30 +165,108 @@
effects = _patch_effects['applied']
else:
effects = _patch_effects['unapplied']
- sys.stdout.write(render_effects(patch, *effects) + '\n')
+ ui.write(render_effects(patch, *effects) + '\n')
return retval
_patch_effects = { 'applied': ('blue', 'bold', 'underline'),
'missing': ('red', 'bold'),
'unapplied': ('black', 'bold'), }
+def _color_wrapper(orig, s):
+ lines = s.split('\n')
+ for i, line in enumerate(lines):
+ for prefix, style in _diff_prefixes:
+ if line.startswith(prefix):
+ effects = _diff_effects[style]
+ lines[i] = render_effects(line, *_diff_effects[style])
+ break
+ orig('\n'.join(lines))
+
+def showpatch_color(orig, self, node):
+ old_write = extensions.wrapfunction(self.ui, 'write', _color_wrapper)
+ try:
+ orig(self, node)
+ finally:
+ self.ui.write = old_write
+
+def colordiff(orig, ui, repo, *pats, **opts):
+ '''run the diff command with colored output'''
+
+ old_write = extensions.wrapfunction(ui, 'write', _color_wrapper)
+ try:
+ orig(ui, repo, *pats, **opts)
+ finally:
+ ui.write = old_write
+
+_diff_prefixes = [ ('diff', 'diffline'),
+ ('copy', 'extended'),
+ ('rename', 'extended'),
+ ('new', 'extended'),
+ ('deleted', 'extended'),
+ ('---', 'file_a'),
+ ('+++', 'file_b'),
+ ('@', 'hunk'),
+ ('-', 'deleted'),
+ ('+', 'inserted'), ]
+
+_diff_effects = { 'diffline': ('bold', ),
+ 'extended': ('cyan', 'bold'),
+ 'file_a': ('red', 'bold'),
+ 'file_b': ('green', 'bold'),
+ 'hunk': ('magenta', ),
+ 'deleted': ('red', ),
+ 'inserted': ('green', ),
+ 'changed': ('white', ), }
+
def uisetup(ui):
'''Initialize the extension.'''
+ _setupcmd(ui, 'diff', commands.table, colordiff, _diff_effects)
+ _setupcmd(ui, 'incoming', commands.table, None, _diff_effects)
+ _setupcmd(ui, 'log', commands.table, None, _diff_effects)
+ _setupcmd(ui, 'outgoing', commands.table, None, _diff_effects)
+ _setupcmd(ui, 'tip', commands.table, None, _diff_effects)
_setupcmd(ui, 'status', commands.table, colorstatus, _status_effects)
if ui.config('extensions', 'hgext.mq') is not None or \
ui.config('extensions', 'mq') is not None:
from hgext import mq
+ _setupcmd(ui, 'qdiff', mq.cmdtable, colordiff, _diff_effects)
_setupcmd(ui, 'qseries', mq.cmdtable, colorqseries, _patch_effects)
def _setupcmd(ui, cmd, table, func, effectsmap):
'''patch in command to command table and load effect map'''
- def nocolor(orig, *args, **kwargs):
- if kwargs['no_color']:
- return orig(*args, **kwargs)
- return func(orig, *args, **kwargs)
+ def nocolor(orig, *args, **opts):
+ def isatty():
+ # Duplicate stdout in case sys.stdout has been reassigned
+ if sys.stdout.fileno() != 1:
+ try:
+ stdout = os.fdopen(os.dup(1), 'w')
+ try:
+ return stdout.isatty()
+ finally:
+ stdout.close()
+ except Exception:
+ pass
+ return sys.stdout.isatty()
+
+ if (opts['no_color'] or opts['color'] == 'never' or
+ (opts['color'] == 'auto' and
+ (os.environ.get('TERM') == 'dumb' or not isatty()))):
+ return orig(*args, **opts)
+
+ old_showpatch = extensions.wrapfunction(cmdutil.changeset_printer,
+ 'showpatch', showpatch_color)
+ try:
+ if func is not None:
+ return func(orig, *args, **opts)
+ return orig(*args, **opts)
+ finally:
+ cmdutil.changeset_printer.showpatch = old_showpatch
entry = extensions.wrapcommand(table, cmd, nocolor)
- entry[1].append(('', 'no-color', None, _("don't colorize output")))
+ entry[1].extend([
+ ('', 'color', 'auto', _("when to colorize (always, auto, or never)")),
+ ('', 'no-color', None, _("don't colorize output")),
+ ])
for status in effectsmap:
effects = ui.config('color', cmd + '.' + status)
More information about the Mercurial-devel
mailing list