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