##// END OF EJS Templates
color: cleanup extra commas
Martin Geisler -
r8630:8ff65f7e default
parent child Browse files
Show More
@@ -1,270 +1,270 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 status, qseries, and diff-related commands
20 20
21 21 This extension modifies the status command to add color to its output
22 22 to reflect file status, the qseries command to add color to reflect
23 23 patch status (applied, unapplied, missing), and to diff-related
24 24 commands to highlight additions, removals, diff headers, and trailing
25 25 whitespace.
26 26
27 27 Other effects in addition to color, like bold and underlined text, are
28 28 also available. Effects are rendered with the ECMA-48 SGR control
29 29 function (aka ANSI escape codes). This module also provides the
30 30 render_text function, which can be used to add effects to any text.
31 31
32 32 To enable this extension, add this to your .hgrc file:
33 33 [extensions]
34 34 color =
35 35
36 36 Default effects my be overriden from the .hgrc file:
37 37
38 38 [color]
39 39 status.modified = blue bold underline red_background
40 40 status.added = green bold
41 41 status.removed = red bold blue_background
42 42 status.deleted = cyan bold underline
43 43 status.unknown = magenta bold underline
44 44 status.ignored = black bold
45 45
46 46 # 'none' turns off all effects
47 47 status.clean = none
48 48 status.copied = none
49 49
50 50 qseries.applied = blue bold underline
51 51 qseries.unapplied = black bold
52 52 qseries.missing = red bold
53 53
54 54 diff.diffline = bold
55 55 diff.extended = cyan bold
56 56 diff.file_a = red bold
57 57 diff.file_b = green bold
58 58 diff.hunk = magenta
59 59 diff.deleted = red
60 60 diff.inserted = green
61 61 diff.changed = white
62 62 diff.trailingwhitespace = bold red_background
63 63 '''
64 64
65 65 import os, sys
66 66
67 67 from mercurial import cmdutil, commands, extensions
68 68 from mercurial.i18n import _
69 69
70 70 # start and stop parameters for effects
71 71 _effect_params = {'none': 0,
72 72 'black': 30,
73 73 'red': 31,
74 74 'green': 32,
75 75 'yellow': 33,
76 76 'blue': 34,
77 77 'magenta': 35,
78 78 'cyan': 36,
79 79 'white': 37,
80 80 'bold': 1,
81 81 'italic': 3,
82 82 'underline': 4,
83 83 'inverse': 7,
84 84 'black_background': 40,
85 85 'red_background': 41,
86 86 'green_background': 42,
87 87 'yellow_background': 43,
88 88 'blue_background': 44,
89 89 'purple_background': 45,
90 90 'cyan_background': 46,
91 91 'white_background': 47}
92 92
93 93 def render_effects(text, effects):
94 94 'Wrap text in commands to turn on each effect.'
95 95 start = [str(_effect_params[e]) for e in ['none'] + effects]
96 96 start = '\033[' + ';'.join(start) + 'm'
97 97 stop = '\033[' + str(_effect_params['none']) + 'm'
98 98 return ''.join([start, text, stop])
99 99
100 100 def colorstatus(orig, ui, repo, *pats, **opts):
101 101 '''run the status command with colored output'''
102 102
103 103 delimiter = opts['print0'] and '\0' or '\n'
104 104
105 105 nostatus = opts.get('no_status')
106 106 opts['no_status'] = False
107 107 # run status and capture its output
108 108 ui.pushbuffer()
109 109 retval = orig(ui, repo, *pats, **opts)
110 110 # filter out empty strings
111 111 lines_with_status = [ line for line in ui.popbuffer().split(delimiter) if line ]
112 112
113 113 if nostatus:
114 114 lines = [l[2:] for l in lines_with_status]
115 115 else:
116 116 lines = lines_with_status
117 117
118 118 # apply color to output and display it
119 119 for i in xrange(len(lines)):
120 120 status = _status_abbreviations[lines_with_status[i][0]]
121 121 effects = _status_effects[status]
122 122 if effects:
123 123 lines[i] = render_effects(lines[i], effects)
124 124 ui.write(lines[i] + delimiter)
125 125 return retval
126 126
127 127 _status_abbreviations = { 'M': 'modified',
128 128 'A': 'added',
129 129 'R': 'removed',
130 130 '!': 'deleted',
131 131 '?': 'unknown',
132 132 'I': 'ignored',
133 133 'C': 'clean',
134 134 ' ': 'copied', }
135 135
136 136 _status_effects = { 'modified': ['blue', 'bold'],
137 137 'added': ['green', 'bold'],
138 138 'removed': ['red', 'bold'],
139 139 'deleted': ['cyan', 'bold', 'underline'],
140 140 'unknown': ['magenta', 'bold', 'underline'],
141 141 'ignored': ['black', 'bold'],
142 142 'clean': ['none'],
143 143 'copied': ['none'], }
144 144
145 145 def colorqseries(orig, ui, repo, *dummy, **opts):
146 146 '''run the qseries command with colored output'''
147 147 ui.pushbuffer()
148 148 retval = orig(ui, repo, **opts)
149 149 patches = ui.popbuffer().splitlines()
150 150 for patch in patches:
151 151 patchname = patch
152 152 if opts['summary']:
153 153 patchname = patchname.split(': ')[0]
154 154 if ui.verbose:
155 155 patchname = patchname.split(' ', 2)[-1]
156 156
157 157 if opts['missing']:
158 158 effects = _patch_effects['missing']
159 159 # Determine if patch is applied.
160 160 elif [ applied for applied in repo.mq.applied
161 161 if patchname == applied.name ]:
162 162 effects = _patch_effects['applied']
163 163 else:
164 164 effects = _patch_effects['unapplied']
165 165 ui.write(render_effects(patch, effects) + '\n')
166 166 return retval
167 167
168 168 _patch_effects = { 'applied': ['blue', 'bold', 'underline'],
169 169 'missing': ['red', 'bold'],
170 170 'unapplied': ['black', 'bold'], }
171 171
172 172 def colorwrap(orig, s):
173 173 '''wrap ui.write for colored diff output'''
174 174 lines = s.split('\n')
175 175 for i, line in enumerate(lines):
176 176 stripline = line
177 177 if line and line[0] in '+-':
178 178 # highlight trailing whitespace, but only in changed lines
179 179 stripline = line.rstrip()
180 180 for prefix, style in _diff_prefixes:
181 181 if stripline.startswith(prefix):
182 182 lines[i] = render_effects(stripline, _diff_effects[style])
183 183 break
184 184 if line != stripline:
185 185 lines[i] += render_effects(
186 186 line[len(stripline):], _diff_effects['trailingwhitespace'])
187 187 orig('\n'.join(lines))
188 188
189 189 def colorshowpatch(orig, self, node):
190 190 '''wrap cmdutil.changeset_printer.showpatch with colored output'''
191 191 oldwrite = extensions.wrapfunction(self.ui, 'write', colorwrap)
192 192 try:
193 193 orig(self, node)
194 194 finally:
195 195 self.ui.write = oldwrite
196 196
197 197 def colordiff(orig, ui, repo, *pats, **opts):
198 198 '''run the diff command with colored output'''
199 199 oldwrite = extensions.wrapfunction(ui, 'write', colorwrap)
200 200 try:
201 201 orig(ui, repo, *pats, **opts)
202 202 finally:
203 203 ui.write = oldwrite
204 204
205 205 _diff_prefixes = [('diff', 'diffline'),
206 206 ('copy', 'extended'),
207 207 ('rename', 'extended'),
208 208 ('old', 'extended'),
209 209 ('new', 'extended'),
210 210 ('deleted', 'extended'),
211 211 ('---', 'file_a'),
212 212 ('+++', 'file_b'),
213 213 ('@', 'hunk'),
214 214 ('-', 'deleted'),
215 215 ('+', 'inserted')]
216 216
217 _diff_effects = {'diffline': ['bold',],
217 _diff_effects = {'diffline': ['bold'],
218 218 'extended': ['cyan', 'bold'],
219 219 'file_a': ['red', 'bold'],
220 220 'file_b': ['green', 'bold'],
221 'hunk': ['magenta',],
222 'deleted': ['red',],
223 'inserted': ['green',],
224 'changed': ['white',],
225 'trailingwhitespace': ['bold', 'red_background'],}
221 'hunk': ['magenta'],
222 'deleted': ['red'],
223 'inserted': ['green'],
224 'changed': ['white'],
225 'trailingwhitespace': ['bold', 'red_background']}
226 226
227 227 def uisetup(ui):
228 228 '''Initialize the extension.'''
229 229 _setupcmd(ui, 'diff', commands.table, colordiff, _diff_effects)
230 230 _setupcmd(ui, 'incoming', commands.table, None, _diff_effects)
231 231 _setupcmd(ui, 'log', commands.table, None, _diff_effects)
232 232 _setupcmd(ui, 'outgoing', commands.table, None, _diff_effects)
233 233 _setupcmd(ui, 'tip', commands.table, None, _diff_effects)
234 234 _setupcmd(ui, 'status', commands.table, colorstatus, _status_effects)
235 235 try:
236 236 mq = extensions.find('mq')
237 237 _setupcmd(ui, 'qdiff', mq.cmdtable, colordiff, _diff_effects)
238 238 _setupcmd(ui, 'qseries', mq.cmdtable, colorqseries, _patch_effects)
239 239 except KeyError:
240 240 # The mq extension is not enabled
241 241 pass
242 242
243 243 def _setupcmd(ui, cmd, table, func, effectsmap):
244 244 '''patch in command to command table and load effect map'''
245 245 def nocolor(orig, *args, **opts):
246 246
247 247 if (opts['no_color'] or opts['color'] == 'never' or
248 248 (opts['color'] == 'auto' and (os.environ.get('TERM') == 'dumb'
249 249 or not sys.__stdout__.isatty()))):
250 250 return orig(*args, **opts)
251 251
252 252 oldshowpatch = extensions.wrapfunction(cmdutil.changeset_printer,
253 253 'showpatch', colorshowpatch)
254 254 try:
255 255 if func is not None:
256 256 return func(orig, *args, **opts)
257 257 return orig(*args, **opts)
258 258 finally:
259 259 cmdutil.changeset_printer.showpatch = oldshowpatch
260 260
261 261 entry = extensions.wrapcommand(table, cmd, nocolor)
262 262 entry[1].extend([
263 263 ('', 'color', 'auto', _("when to colorize (always, auto, or never)")),
264 264 ('', 'no-color', None, _("don't colorize output")),
265 265 ])
266 266
267 267 for status in effectsmap:
268 268 effects = ui.configlist('color', cmd + '.' + status)
269 269 if effects:
270 270 effectsmap[status] = effects
General Comments 0
You need to be logged in to leave comments. Login now