##// END OF EJS Templates
Apply color to output of qseries --verbose...
Kevin Christen -
r6855:09db2b82 default
parent child Browse files
Show More
@@ -1,220 +1,224 b''
1 1 # color.py color output for the status and qseries commands
2 2 #
3 3 # Copyright (C) 2007 Kevin Christen <kevin.christen@gmail.com>
4 4 #
5 5 # This program is free software; you can redistribute it and/or modify it
6 6 # under the terms of the GNU General Public License as published by the
7 7 # Free Software Foundation; either version 2 of the License, or (at your
8 8 # option) any later version.
9 9 #
10 10 # This program is distributed in the hope that it will be useful, but
11 11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 13 # Public License for more details.
14 14 #
15 15 # You should have received a copy of the GNU General Public License along
16 16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 18
19 19 '''add color output to the status and qseries commands
20 20
21 21 This extension modifies the status command to add color to its output to
22 22 reflect file status, and the qseries command to add color to reflect patch
23 23 status (applied, unapplied, missing). Other effects in addition to color,
24 24 like bold and underlined text, are also available. Effects are rendered
25 25 with the ECMA-48 SGR control function (aka ANSI escape codes). This module
26 26 also provides the render_text function, which can be used to add effects to
27 27 any text.
28 28
29 29 To enable this extension, add this to your .hgrc file:
30 30 [extensions]
31 31 color =
32 32
33 33 Default effects my be overriden from the .hgrc file:
34 34
35 35 [color]
36 36 status.modified = blue bold underline red_background
37 37 status.added = green bold
38 38 status.removed = red bold blue_background
39 39 status.deleted = cyan bold underline
40 40 status.unknown = magenta bold underline
41 41 status.ignored = black bold
42 42
43 'none' turns off all effects
43 # 'none' turns off all effects
44 44 status.clean = none
45 45 status.copied = none
46 46
47 47 qseries.applied = blue bold underline
48 48 qseries.unapplied = black bold
49 49 qseries.missing = red bold
50 50 '''
51 51
52 52 import re, sys
53 53
54 54 from mercurial import commands, cmdutil
55 55 from mercurial.i18n import _
56 56
57 57 # start and stop parameters for effects
58 58 _effect_params = { 'none': (0, 0),
59 59 'black': (30, 39),
60 60 'red': (31, 39),
61 61 'green': (32, 39),
62 62 'yellow': (33, 39),
63 63 'blue': (34, 39),
64 64 'magenta': (35, 39),
65 65 'cyan': (36, 39),
66 66 'white': (37, 39),
67 67 'bold': (1, 22),
68 68 'italic': (3, 23),
69 69 'underline': (4, 24),
70 70 'inverse': (7, 27),
71 71 'black_background': (40, 49),
72 72 'red_background': (41, 49),
73 73 'green_background': (42, 49),
74 74 'yellow_background': (43, 49),
75 75 'blue_background': (44, 49),
76 76 'purple_background': (45, 49),
77 77 'cyan_background': (46, 49),
78 78 'white_background': (47, 49), }
79 79
80 80 def render_effects(text, *effects):
81 81 'Wrap text in commands to turn on each effect.'
82 82 start = []
83 83 stop = []
84 84 for effect in effects:
85 85 start.append(str(_effect_params[effect][0]))
86 86 stop.append(str(_effect_params[effect][1]))
87 87 start = '\033[' + ';'.join(start) + 'm'
88 88 stop = '\033[' + ';'.join(stop) + 'm'
89 89 return start + text + stop
90 90
91 91 def colorstatus(statusfunc, ui, repo, *pats, **opts):
92 92 '''run the status command with colored output'''
93 93
94 94 delimiter = opts['print0'] and '\0' or '\n'
95 95
96 96 # run status and capture it's output
97 97 ui.pushbuffer()
98 98 retval = statusfunc(ui, repo, *pats, **opts)
99 99 # filter out empty strings
100 100 lines = [ line for line in ui.popbuffer().split(delimiter) if line ]
101 101
102 102 if opts['no_status']:
103 103 # if --no-status, run the command again without that option to get
104 104 # output with status abbreviations
105 105 opts['no_status'] = False
106 106 ui.pushbuffer()
107 107 statusfunc(ui, repo, *pats, **opts)
108 108 # filter out empty strings
109 109 lines_with_status = [ line for
110 110 line in ui.popbuffer().split(delimiter) if line ]
111 111 else:
112 112 lines_with_status = lines
113 113
114 114 # apply color to output and display it
115 115 for i in xrange(0, len(lines)):
116 116 status = _status_abbreviations[lines_with_status[i][0]]
117 117 effects = _status_effects[status]
118 118 if effects:
119 119 lines[i] = render_effects(lines[i], *effects)
120 120 sys.stdout.write(lines[i] + delimiter)
121 121 return retval
122 122
123 123 _status_abbreviations = { 'M': 'modified',
124 124 'A': 'added',
125 125 'R': 'removed',
126 126 '!': 'deleted',
127 127 '?': 'unknown',
128 128 'I': 'ignored',
129 129 'C': 'clean',
130 130 ' ': 'copied', }
131 131
132 132 _status_effects = { 'modified': ('blue', 'bold'),
133 133 'added': ('green', 'bold'),
134 134 'removed': ('red', 'bold'),
135 135 'deleted': ('cyan', 'bold', 'underline'),
136 136 'unknown': ('magenta', 'bold', 'underline'),
137 137 'ignored': ('black', 'bold'),
138 138 'clean': ('none', ),
139 139 'copied': ('none', ), }
140 140
141 141 def colorqseries(qseriesfunc, ui, repo, *dummy, **opts):
142 142 '''run the qseries command with colored output'''
143 143 ui.pushbuffer()
144 144 retval = qseriesfunc(ui, repo, **opts)
145 145 patches = ui.popbuffer().splitlines()
146 146 for patch in patches:
147 patchname = patch
148 if opts['summary']:
149 patchname = patchname.split(': ')[0]
150 if ui.verbose:
151 patchname = patchname.split(' ', 2)[-1]
152
147 153 if opts['missing']:
148 154 effects = _patch_effects['missing']
149 # Determine if patch is applied. Search for beginning of output
150 # line in the applied patch list, in case --summary has been used
151 # and output line isn't just the patch name.
155 # Determine if patch is applied.
152 156 elif [ applied for applied in repo.mq.applied
153 if patch.startswith(applied.name) ]:
157 if patchname == applied.name ]:
154 158 effects = _patch_effects['applied']
155 159 else:
156 160 effects = _patch_effects['unapplied']
157 161 sys.stdout.write(render_effects(patch, *effects) + '\n')
158 162 return retval
159 163
160 164 _patch_effects = { 'applied': ('blue', 'bold', 'underline'),
161 165 'missing': ('red', 'bold'),
162 166 'unapplied': ('black', 'bold'), }
163 167
164 168 def uisetup(ui):
165 169 '''Initialize the extension.'''
166 170 nocoloropt = ('', 'no-color', None, _("don't colorize output"))
167 171 _decoratecmd(ui, 'status', commands.table, colorstatus, nocoloropt)
168 172 _configcmdeffects(ui, 'status', _status_effects);
169 173 if ui.config('extensions', 'hgext.mq') is not None or \
170 174 ui.config('extensions', 'mq') is not None:
171 175 from hgext import mq
172 176 _decoratecmd(ui, 'qseries', mq.cmdtable, colorqseries, nocoloropt)
173 177 _configcmdeffects(ui, 'qseries', _patch_effects);
174 178
175 179 def _decoratecmd(ui, cmd, table, delegate, *delegateoptions):
176 180 '''Replace the function that implements cmd in table with a decorator.
177 181
178 182 The decorator that becomes the new implementation of cmd calls
179 183 delegate. The delegate's first argument is the replaced function,
180 184 followed by the normal Mercurial command arguments (ui, repo, ...). If
181 185 the delegate adds command options, supply them as delegateoptions.
182 186 '''
183 187 cmdkey, cmdentry = _cmdtableitem(ui, cmd, table)
184 188 decorator = lambda ui, repo, *args, **opts: \
185 189 _colordecorator(delegate, cmdentry[0],
186 190 ui, repo, *args, **opts)
187 191 # make sure 'hg help cmd' still works
188 192 decorator.__doc__ = cmdentry[0].__doc__
189 193 decoratorentry = (decorator,) + cmdentry[1:]
190 194 for option in delegateoptions:
191 195 decoratorentry[1].append(option)
192 196 table[cmdkey] = decoratorentry
193 197
194 198 def _cmdtableitem(ui, cmd, table):
195 199 '''Return key, value from table for cmd, or None if not found.'''
196 200 aliases, entry = cmdutil.findcmd(ui, cmd, table)
197 201 for candidatekey, candidateentry in table.iteritems():
198 202 if candidateentry is entry:
199 203 return candidatekey, entry
200 204
201 205 def _colordecorator(colorfunc, nocolorfunc, ui, repo, *args, **opts):
202 206 '''Delegate to colorfunc or nocolorfunc, depending on conditions.
203 207
204 208 Delegate to colorfunc unless --no-color option is set or output is not
205 209 to a tty.
206 210 '''
207 211 if opts['no_color'] or not sys.stdout.isatty():
208 212 return nocolorfunc(ui, repo, *args, **opts)
209 213 return colorfunc(nocolorfunc, ui, repo, *args, **opts)
210 214
211 215 def _configcmdeffects(ui, cmdname, effectsmap):
212 216 '''Override default effects for cmdname with those from .hgrc file.
213 217
214 218 Entries in the .hgrc file are in the [color] section, and look like
215 219 'cmdname'.'status' (for instance, 'status.modified = blue bold inverse').
216 220 '''
217 221 for status in effectsmap:
218 222 effects = ui.config('color', cmdname + '.' + status)
219 223 if effects:
220 224 effectsmap[status] = re.split('\W+', effects)
General Comments 0
You need to be logged in to leave comments. Login now