[PATCH] Color command output using ui buffers
kevin.christen at gmail.com
kevin.christen at gmail.com
Sat Dec 29 17:21:27 CST 2007
# HG changeset patch
# User Kevin Christen <kevin.christen at gmail.com>
# Date 1198945152 21600
# Node ID 7ebe8ea4d38e57bb27821ef5bd389662f20196f3
# Parent bc475d1f74caf65df21b267b5b9ab58770c3a903
Color command output using ui buffers
diff -r bc475d1f74ca -r 7ebe8ea4d38e hgext/color.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/color.py Sat Dec 29 10:19:12 2007 -0600
@@ -0,0 +1,196 @@
+# color.py color output for the status and qseries commands
+#
+# Copyright (C) 2007 Kevin Christen <kevin.christen at gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>. This
+# software may be used and distributed according to the terms of the GNU
+# General Public License, incorporated herein by reference.
+
+'''add color output to the status and qseries commands
+
+This extension provides the cstatus command, which adds color to the output
+of the status command to reflect file status, and the cqseries command,
+which adds color to the output of the qseries command to reflect patch
+status (applied, unapplied, missing). Other effects in addition to color
+are availble, like bold and underlined text. 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]
+color =
+
+Default effects my be overriden from the .hgrc file:
+
+[color]
+cstatus.modified = blue bold underline red_background
+cstatus.added = green bold
+cstatus.removed = red bold blue_background
+cstatus.deleted = cyan bold underline
+cstatus.unknown = magenta bold underline
+cstatus.ignored = black bold
+
+ 'none' turns off all effects
+cstatus.clean = none
+cstatus.copied = none
+
+cqseries.applied = blue bold underline
+cqseries.unapplied = black bold
+cqseries.missing = red bold
+'''
+
+import re, sys
+
+from mercurial import commands, cmdutil, ui
+from mercurial.i18n import _
+from hgext import mq
+
+_effect_commands = { 'none': (0, 0),
+ 'black': (30, 39),
+ 'red': (31, 39),
+ 'green': (32, 39),
+ 'yellow': (33, 39),
+ 'blue': (34, 39),
+ 'magenta': (35, 39),
+ 'cyan': (36, 39),
+ 'white': (37, 39),
+ 'bold': (1, 22),
+ 'italic': (3, 23),
+ 'underline': (4, 24),
+ 'inverse': (7, 27),
+ 'black_background': (40, 49),
+ 'red_background': (41, 49),
+ 'green_background': (42, 49),
+ 'yellow_background': (43, 49),
+ 'blue_background': (44, 49),
+ 'purple_background': (45, 49),
+ 'cyan_background': (46, 49),
+ 'white_background': (47, 49), }
+
+def render_effects(text, *effects):
+ 'Wrap text in commands to turn on each effect.'
+ start = []
+ stop = []
+ for effect in effects:
+ start.append(str(_effect_commands[effect][0]))
+ stop.append(str(_effect_commands[effect][1]))
+ start = '\033[' + ';'.join(start) + 'm'
+ stop = '\033[' + ';'.join(stop) + 'm'
+ return start + text + stop
+
+_status_abbreviations = { 'M': 'modified',
+ 'A': 'added',
+ 'R': 'removed',
+ 'D': 'deleted',
+ '?': 'unknown',
+ 'I': 'ignored',
+ 'C': 'clean',
+ ' ': 'copied', }
+
+_status_effects = { 'modified': ('blue', 'bold'),
+ 'added': ('green', 'bold'),
+ 'removed': ('red', 'bold'),
+ 'deleted': ('cyan', 'bold', 'underline'),
+ 'unknown': ('magenta', 'bold', 'underline'),
+ 'ignored': ('black', 'bold'),
+ 'clean': ('none', ),
+ 'copied': ('none', ), }
+
+def colorstatus(ui, repo, *pats, **opts):
+ '''run the status command with colored output
+
+ Usage is identical to the status command.
+ '''
+
+ delimiter = opts['print0'] and '\0' or '\n'
+
+ # run status and capture it's output
+ ui.pushbuffer()
+ commands.status(ui, repo, *pats, **opts)
+ # filter out empty strings
+ lines = filter(lambda l: l, ui.popbuffer().split(delimiter))
+
+ if opts['no_status']:
+ # if --no-status, run the command again without that option to get
+ # output with status abbreviations
+ opts['no_status'] = False
+ ui.pushbuffer()
+ commands.status(ui, repo, *pats, **opts)
+ lines_with_status = filter(lambda l: l,
+ ui.popbuffer().split(delimiter))
+ else:
+ lines_with_status = lines
+
+ # apply color to output and display it
+ for i in xrange(0, len(lines)):
+ status = _status_abbreviations[lines_with_status[i][0]]
+ effects = _status_effects[status]
+ if effects:
+ lines[i] = render_effects(lines[i], *effects)
+ sys.stdout.write(lines[i] + delimiter)
+
+_patch_effects = { 'applied': ('blue', 'bold', 'underline'),
+ 'missing': ('red', 'bold'),
+ 'unapplied': ('black', 'bold'), }
+
+def colorqseries(ui, repo, **opts):
+ '''run the qseries command with colored output
+
+ Usage is identical to the qseries command.
+ '''
+ ui.pushbuffer()
+ mq.series(ui, repo, **opts)
+ patches = ui.popbuffer().splitlines()
+ for patch in patches:
+ if opts['missing']:
+ effects = _patch_effects['missing']
+ elif filter(lambda n: patch.startswith(n.name), repo.mq.applied):
+ effects = _patch_effects['applied']
+ else:
+ effects = _patch_effects['unapplied']
+ sys.stdout.write(render_effects(patch, *effects) + '\n')
+
+def _copy_options(ui, fromcmd, fromtable, tocmd):
+ '''Copy fromcmd options into the local command table for tocmd.'''
+ toentry = cmdutil.findcmd(ui, tocmd, cmdtable)
+ fromentry = cmdutil.findcmd(ui, fromcmd, fromtable)
+ toentry[1][1].extend(fromentry[1][1])
+
+def _configeffects(ui):
+ '''Override default effects with those from .hgrc'''
+ for filestatus in _status_effects:
+ effects = ui.config('color', 'cstatus.' + filestatus)
+ if effects:
+ _status_effects[filestatus] = re.split('\W+', effects)
+ for patchstatus in _patch_effects:
+ effects = ui.config('color', 'cqseries.' + patchstatus)
+ if effects:
+ _patch_effects[patchstatus] = re.split('\W+', effects)
+
+def uisetup(ui):
+ '''Initialize the extension.'''
+ _copy_options(ui, 'status', commands.table, 'cstatus')
+ _configeffects(ui)
+ if ui.config('extensions', 'hgext.mq', default=None) is not None:
+ cmdtable['cqseries'] = (colorqseries,
+ [],
+ _('hg cqseries [-ms]'))
+ _copy_options(ui, 'qseries', mq.cmdtable, 'cqseries')
+
+cmdtable = {
+ "cstatus|cst": (colorstatus,
+ [], # filled in from status command's options
+ _('hg cstatus [OPTION]... [FILE]...')),
+}
More information about the Mercurial-devel
mailing list