##// END OF EJS Templates
color: change the debug output format...
Matt Mackall -
r22464:964dd1c4 default
parent child Browse files
Show More
@@ -1,621 +1,619 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 software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 '''colorize output from some commands
9 9
10 10 This extension modifies the status and resolve commands to add color
11 11 to their output to reflect file status, the qseries command to add
12 12 color to reflect patch status (applied, unapplied, missing), and to
13 13 diff-related commands to highlight additions, removals, diff headers,
14 14 and trailing whitespace.
15 15
16 16 Other effects in addition to color, like bold and underlined text, are
17 17 also available. By default, the terminfo database is used to find the
18 18 terminal codes used to change color and effect. If terminfo is not
19 19 available, then effects are rendered with the ECMA-48 SGR control
20 20 function (aka ANSI escape codes).
21 21
22 22 Text receives color effects depending on the labels that it has. Many
23 23 default Mercurial commands emit labelled text. You can also define
24 24 your own labels in templates using the label function, see :hg:`help
25 25 templates`. A single portion of text may have more than one label. In
26 26 that case, effects given to the last label will override any other
27 27 effects. This includes the special "none" effect, which nullifies
28 28 other effects.
29 29
30 30 Labels are normally invisible. In order to see these labels and their
31 31 position in the text, use the global --color=debug option. In case of
32 32 multiple labels for the same text, the labels will be enclosed by
33 33 square brackets, e.g.
34 34
35 35 [log.changeset changeset.secret](changeset: 22611:6f0a53c8f587)
36 36
37 37 The following are the default effects for some default labels. Default
38 38 effects may be overridden from your configuration file::
39 39
40 40 [color]
41 41 status.modified = blue bold underline red_background
42 42 status.added = green bold
43 43 status.removed = red bold blue_background
44 44 status.deleted = cyan bold underline
45 45 status.unknown = magenta bold underline
46 46 status.ignored = black bold
47 47
48 48 # 'none' turns off all effects
49 49 status.clean = none
50 50 status.copied = none
51 51
52 52 qseries.applied = blue bold underline
53 53 qseries.unapplied = black bold
54 54 qseries.missing = red bold
55 55
56 56 diff.diffline = bold
57 57 diff.extended = cyan bold
58 58 diff.file_a = red bold
59 59 diff.file_b = green bold
60 60 diff.hunk = magenta
61 61 diff.deleted = red
62 62 diff.inserted = green
63 63 diff.changed = white
64 64 diff.trailingwhitespace = bold red_background
65 65
66 66 resolve.unresolved = red bold
67 67 resolve.resolved = green bold
68 68
69 69 bookmarks.current = green
70 70
71 71 branches.active = none
72 72 branches.closed = black bold
73 73 branches.current = green
74 74 branches.inactive = none
75 75
76 76 tags.normal = green
77 77 tags.local = black bold
78 78
79 79 rebase.rebased = blue
80 80 rebase.remaining = red bold
81 81
82 82 shelve.age = cyan
83 83 shelve.newest = green bold
84 84 shelve.name = blue bold
85 85
86 86 histedit.remaining = red bold
87 87
88 88 The available effects in terminfo mode are 'blink', 'bold', 'dim',
89 89 'inverse', 'invisible', 'italic', 'standout', and 'underline'; in
90 90 ECMA-48 mode, the options are 'bold', 'inverse', 'italic', and
91 91 'underline'. How each is rendered depends on the terminal emulator.
92 92 Some may not be available for a given terminal type, and will be
93 93 silently ignored.
94 94
95 95 Note that on some systems, terminfo mode may cause problems when using
96 96 color with the pager extension and less -R. less with the -R option
97 97 will only display ECMA-48 color codes, and terminfo mode may sometimes
98 98 emit codes that less doesn't understand. You can work around this by
99 99 either using ansi mode (or auto mode), or by using less -r (which will
100 100 pass through all terminal control codes, not just color control
101 101 codes).
102 102
103 103 Because there are only eight standard colors, this module allows you
104 104 to define color names for other color slots which might be available
105 105 for your terminal type, assuming terminfo mode. For instance::
106 106
107 107 color.brightblue = 12
108 108 color.pink = 207
109 109 color.orange = 202
110 110
111 111 to set 'brightblue' to color slot 12 (useful for 16 color terminals
112 112 that have brighter colors defined in the upper eight) and, 'pink' and
113 113 'orange' to colors in 256-color xterm's default color cube. These
114 114 defined colors may then be used as any of the pre-defined eight,
115 115 including appending '_background' to set the background to that color.
116 116
117 117 By default, the color extension will use ANSI mode (or win32 mode on
118 118 Windows) if it detects a terminal. To override auto mode (to enable
119 119 terminfo mode, for example), set the following configuration option::
120 120
121 121 [color]
122 122 mode = terminfo
123 123
124 124 Any value other than 'ansi', 'win32', 'terminfo', or 'auto' will
125 125 disable color.
126 126 '''
127 127
128 128 import os
129 129
130 130 from mercurial import cmdutil, commands, dispatch, extensions, ui as uimod, util
131 131 from mercurial import templater, error
132 132 from mercurial.i18n import _
133 133
134 134 cmdtable = {}
135 135 command = cmdutil.command(cmdtable)
136 136 testedwith = 'internal'
137 137
138 138 # start and stop parameters for effects
139 139 _effects = {'none': 0, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33,
140 140 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37, 'bold': 1,
141 141 'italic': 3, 'underline': 4, 'inverse': 7,
142 142 'black_background': 40, 'red_background': 41,
143 143 'green_background': 42, 'yellow_background': 43,
144 144 'blue_background': 44, 'purple_background': 45,
145 145 'cyan_background': 46, 'white_background': 47}
146 146
147 147 def _terminfosetup(ui, mode):
148 148 '''Initialize terminfo data and the terminal if we're in terminfo mode.'''
149 149
150 150 global _terminfo_params
151 151 # If we failed to load curses, we go ahead and return.
152 152 if not _terminfo_params:
153 153 return
154 154 # Otherwise, see what the config file says.
155 155 if mode not in ('auto', 'terminfo'):
156 156 return
157 157
158 158 _terminfo_params.update((key[6:], (False, int(val)))
159 159 for key, val in ui.configitems('color')
160 160 if key.startswith('color.'))
161 161
162 162 try:
163 163 curses.setupterm()
164 164 except curses.error, e:
165 165 _terminfo_params = {}
166 166 return
167 167
168 168 for key, (b, e) in _terminfo_params.items():
169 169 if not b:
170 170 continue
171 171 if not curses.tigetstr(e):
172 172 # Most terminals don't support dim, invis, etc, so don't be
173 173 # noisy and use ui.debug().
174 174 ui.debug("no terminfo entry for %s\n" % e)
175 175 del _terminfo_params[key]
176 176 if not curses.tigetstr('setaf') or not curses.tigetstr('setab'):
177 177 # Only warn about missing terminfo entries if we explicitly asked for
178 178 # terminfo mode.
179 179 if mode == "terminfo":
180 180 ui.warn(_("no terminfo entry for setab/setaf: reverting to "
181 181 "ECMA-48 color\n"))
182 182 _terminfo_params = {}
183 183
184 184 def _modesetup(ui, coloropt):
185 185 global _terminfo_params
186 186
187 187 if coloropt == 'debug':
188 188 return 'debug'
189 189
190 190 auto = (coloropt == 'auto')
191 191 always = not auto and util.parsebool(coloropt)
192 192 if not always and not auto:
193 193 return None
194 194
195 195 formatted = always or (os.environ.get('TERM') != 'dumb' and ui.formatted())
196 196
197 197 mode = ui.config('color', 'mode', 'auto')
198 198 realmode = mode
199 199 if mode == 'auto':
200 200 if os.name == 'nt' and 'TERM' not in os.environ:
201 201 # looks line a cmd.exe console, use win32 API or nothing
202 202 realmode = 'win32'
203 203 else:
204 204 realmode = 'ansi'
205 205
206 206 if realmode == 'win32':
207 207 _terminfo_params = {}
208 208 if not w32effects:
209 209 if mode == 'win32':
210 210 # only warn if color.mode is explicitly set to win32
211 211 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
212 212 return None
213 213 _effects.update(w32effects)
214 214 elif realmode == 'ansi':
215 215 _terminfo_params = {}
216 216 elif realmode == 'terminfo':
217 217 _terminfosetup(ui, mode)
218 218 if not _terminfo_params:
219 219 if mode == 'terminfo':
220 220 ## FIXME Shouldn't we return None in this case too?
221 221 # only warn if color.mode is explicitly set to win32
222 222 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
223 223 realmode = 'ansi'
224 224 else:
225 225 return None
226 226
227 227 if always or (auto and formatted):
228 228 return realmode
229 229 return None
230 230
231 231 try:
232 232 import curses
233 233 # Mapping from effect name to terminfo attribute name or color number.
234 234 # This will also force-load the curses module.
235 235 _terminfo_params = {'none': (True, 'sgr0'),
236 236 'standout': (True, 'smso'),
237 237 'underline': (True, 'smul'),
238 238 'reverse': (True, 'rev'),
239 239 'inverse': (True, 'rev'),
240 240 'blink': (True, 'blink'),
241 241 'dim': (True, 'dim'),
242 242 'bold': (True, 'bold'),
243 243 'invisible': (True, 'invis'),
244 244 'italic': (True, 'sitm'),
245 245 'black': (False, curses.COLOR_BLACK),
246 246 'red': (False, curses.COLOR_RED),
247 247 'green': (False, curses.COLOR_GREEN),
248 248 'yellow': (False, curses.COLOR_YELLOW),
249 249 'blue': (False, curses.COLOR_BLUE),
250 250 'magenta': (False, curses.COLOR_MAGENTA),
251 251 'cyan': (False, curses.COLOR_CYAN),
252 252 'white': (False, curses.COLOR_WHITE)}
253 253 except ImportError:
254 254 _terminfo_params = {}
255 255
256 256 _styles = {'grep.match': 'red bold',
257 257 'grep.linenumber': 'green',
258 258 'grep.rev': 'green',
259 259 'grep.change': 'green',
260 260 'grep.sep': 'cyan',
261 261 'grep.filename': 'magenta',
262 262 'grep.user': 'magenta',
263 263 'grep.date': 'magenta',
264 264 'bookmarks.current': 'green',
265 265 'branches.active': 'none',
266 266 'branches.closed': 'black bold',
267 267 'branches.current': 'green',
268 268 'branches.inactive': 'none',
269 269 'diff.changed': 'white',
270 270 'diff.deleted': 'red',
271 271 'diff.diffline': 'bold',
272 272 'diff.extended': 'cyan bold',
273 273 'diff.file_a': 'red bold',
274 274 'diff.file_b': 'green bold',
275 275 'diff.hunk': 'magenta',
276 276 'diff.inserted': 'green',
277 277 'diff.trailingwhitespace': 'bold red_background',
278 278 'diffstat.deleted': 'red',
279 279 'diffstat.inserted': 'green',
280 280 'histedit.remaining': 'red bold',
281 281 'ui.prompt': 'yellow',
282 282 'log.changeset': 'yellow',
283 283 'rebase.rebased': 'blue',
284 284 'rebase.remaining': 'red bold',
285 285 'resolve.resolved': 'green bold',
286 286 'resolve.unresolved': 'red bold',
287 287 'shelve.age': 'cyan',
288 288 'shelve.newest': 'green bold',
289 289 'shelve.name': 'blue bold',
290 290 'status.added': 'green bold',
291 291 'status.clean': 'none',
292 292 'status.copied': 'none',
293 293 'status.deleted': 'cyan bold underline',
294 294 'status.ignored': 'black bold',
295 295 'status.modified': 'blue bold',
296 296 'status.removed': 'red bold',
297 297 'status.unknown': 'magenta bold underline',
298 298 'tags.normal': 'green',
299 299 'tags.local': 'black bold'}
300 300
301 301
302 302 def _effect_str(effect):
303 303 '''Helper function for render_effects().'''
304 304
305 305 bg = False
306 306 if effect.endswith('_background'):
307 307 bg = True
308 308 effect = effect[:-11]
309 309 attr, val = _terminfo_params[effect]
310 310 if attr:
311 311 return curses.tigetstr(val)
312 312 elif bg:
313 313 return curses.tparm(curses.tigetstr('setab'), val)
314 314 else:
315 315 return curses.tparm(curses.tigetstr('setaf'), val)
316 316
317 317 def render_effects(text, effects):
318 318 'Wrap text in commands to turn on each effect.'
319 319 if not text:
320 320 return text
321 321 if not _terminfo_params:
322 322 start = [str(_effects[e]) for e in ['none'] + effects.split()]
323 323 start = '\033[' + ';'.join(start) + 'm'
324 324 stop = '\033[' + str(_effects['none']) + 'm'
325 325 else:
326 326 start = ''.join(_effect_str(effect)
327 327 for effect in ['none'] + effects.split())
328 328 stop = _effect_str('none')
329 329 return ''.join([start, text, stop])
330 330
331 331 def extstyles():
332 332 for name, ext in extensions.extensions():
333 333 _styles.update(getattr(ext, 'colortable', {}))
334 334
335 335 def valideffect(effect):
336 336 'Determine if the effect is valid or not.'
337 337 good = False
338 338 if not _terminfo_params and effect in _effects:
339 339 good = True
340 340 elif effect in _terminfo_params or effect[:-11] in _terminfo_params:
341 341 good = True
342 342 return good
343 343
344 344 def configstyles(ui):
345 345 for status, cfgeffects in ui.configitems('color'):
346 346 if '.' not in status or status.startswith('color.'):
347 347 continue
348 348 cfgeffects = ui.configlist('color', status)
349 349 if cfgeffects:
350 350 good = []
351 351 for e in cfgeffects:
352 352 if valideffect(e):
353 353 good.append(e)
354 354 else:
355 355 ui.warn(_("ignoring unknown color/effect %r "
356 356 "(configured in color.%s)\n")
357 357 % (e, status))
358 358 _styles[status] = ' '.join(good)
359 359
360 360 class colorui(uimod.ui):
361 361 def popbuffer(self, labeled=False):
362 362 if self._colormode is None:
363 363 return super(colorui, self).popbuffer(labeled)
364 364
365 365 self._bufferstates.pop()
366 366 if labeled:
367 367 return ''.join(self.label(a, label) for a, label
368 368 in self._buffers.pop())
369 369 return ''.join(a for a, label in self._buffers.pop())
370 370
371 371 _colormode = 'ansi'
372 372 def write(self, *args, **opts):
373 373 if self._colormode is None:
374 374 return super(colorui, self).write(*args, **opts)
375 375
376 376 label = opts.get('label', '')
377 377 if self._buffers:
378 378 self._buffers[-1].extend([(str(a), label) for a in args])
379 379 elif self._colormode == 'win32':
380 380 for a in args:
381 381 win32print(a, super(colorui, self).write, **opts)
382 382 else:
383 383 return super(colorui, self).write(
384 384 *[self.label(str(a), label) for a in args], **opts)
385 385
386 386 def write_err(self, *args, **opts):
387 387 if self._colormode is None:
388 388 return super(colorui, self).write_err(*args, **opts)
389 389
390 390 label = opts.get('label', '')
391 391 if self._bufferstates and self._bufferstates[-1]:
392 392 return self.write(*args, **opts)
393 393 if self._colormode == 'win32':
394 394 for a in args:
395 395 win32print(a, super(colorui, self).write_err, **opts)
396 396 else:
397 397 return super(colorui, self).write_err(
398 398 *[self.label(str(a), label) for a in args], **opts)
399 399
400 400 def showlabel(self, msg, label):
401 if ' ' in label:
402 label = '[' + label + ']'
403 401 if label:
404 402 if msg and msg[-1] == '\n':
405 return "%s(%s)\n" % (label, msg[:-1])
403 return "[%s|%s]\n" % (label, msg[:-1])
406 404 else:
407 return "%s(%s)" % (label, msg)
405 return "[%s|%s]" % (label, msg)
408 406 else:
409 407 return msg
410 408
411 409 def label(self, msg, label):
412 410 if self._colormode is None:
413 411 return super(colorui, self).label(msg, label)
414 412
415 413 if self._colormode == 'debug':
416 414 return self.showlabel(msg, label)
417 415
418 416 effects = []
419 417 for l in label.split():
420 418 s = _styles.get(l, '')
421 419 if s:
422 420 effects.append(s)
423 421 elif valideffect(l):
424 422 effects.append(l)
425 423 effects = ' '.join(effects)
426 424 if effects:
427 425 return '\n'.join([render_effects(s, effects)
428 426 for s in msg.split('\n')])
429 427 return msg
430 428
431 429 def templatelabel(context, mapping, args):
432 430 if len(args) != 2:
433 431 # i18n: "label" is a keyword
434 432 raise error.ParseError(_("label expects two arguments"))
435 433
436 434 # add known effects to the mapping so symbols like 'red', 'bold',
437 435 # etc. don't need to be quoted
438 436 mapping.update(dict([(k, k) for k in _effects]))
439 437
440 438 thing = templater._evalifliteral(args[1], context, mapping)
441 439
442 440 # apparently, repo could be a string that is the favicon?
443 441 repo = mapping.get('repo', '')
444 442 if isinstance(repo, str):
445 443 return thing
446 444
447 445 label = templater._evalifliteral(args[0], context, mapping)
448 446
449 447 thing = templater.stringify(thing)
450 448 label = templater.stringify(label)
451 449
452 450 return repo.ui.label(thing, label)
453 451
454 452 def uisetup(ui):
455 453 if ui.plain():
456 454 return
457 455 if not isinstance(ui, colorui):
458 456 colorui.__bases__ = (ui.__class__,)
459 457 ui.__class__ = colorui
460 458 def colorcmd(orig, ui_, opts, cmd, cmdfunc):
461 459 mode = _modesetup(ui_, opts['color'])
462 460 colorui._colormode = mode
463 461 if mode and mode != 'debug':
464 462 extstyles()
465 463 configstyles(ui_)
466 464 return orig(ui_, opts, cmd, cmdfunc)
467 465 extensions.wrapfunction(dispatch, '_runcommand', colorcmd)
468 466 templater.funcs['label'] = templatelabel
469 467
470 468 def extsetup(ui):
471 469 commands.globalopts.append(
472 470 ('', 'color', 'auto',
473 471 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
474 472 # and should not be translated
475 473 _("when to colorize (boolean, always, auto, never, or debug)"),
476 474 _('TYPE')))
477 475
478 476 @command('debugcolor', [], 'hg debugcolor')
479 477 def debugcolor(ui, repo, **opts):
480 478 global _styles
481 479 _styles = {}
482 480 for effect in _effects.keys():
483 481 _styles[effect] = effect
484 482 ui.write(('color mode: %s\n') % ui._colormode)
485 483 ui.write(_('available colors:\n'))
486 484 for label, colors in _styles.items():
487 485 ui.write(('%s\n') % colors, label=label)
488 486
489 487 if os.name != 'nt':
490 488 w32effects = None
491 489 else:
492 490 import re, ctypes
493 491
494 492 _kernel32 = ctypes.windll.kernel32
495 493
496 494 _WORD = ctypes.c_ushort
497 495
498 496 _INVALID_HANDLE_VALUE = -1
499 497
500 498 class _COORD(ctypes.Structure):
501 499 _fields_ = [('X', ctypes.c_short),
502 500 ('Y', ctypes.c_short)]
503 501
504 502 class _SMALL_RECT(ctypes.Structure):
505 503 _fields_ = [('Left', ctypes.c_short),
506 504 ('Top', ctypes.c_short),
507 505 ('Right', ctypes.c_short),
508 506 ('Bottom', ctypes.c_short)]
509 507
510 508 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
511 509 _fields_ = [('dwSize', _COORD),
512 510 ('dwCursorPosition', _COORD),
513 511 ('wAttributes', _WORD),
514 512 ('srWindow', _SMALL_RECT),
515 513 ('dwMaximumWindowSize', _COORD)]
516 514
517 515 _STD_OUTPUT_HANDLE = 0xfffffff5L # (DWORD)-11
518 516 _STD_ERROR_HANDLE = 0xfffffff4L # (DWORD)-12
519 517
520 518 _FOREGROUND_BLUE = 0x0001
521 519 _FOREGROUND_GREEN = 0x0002
522 520 _FOREGROUND_RED = 0x0004
523 521 _FOREGROUND_INTENSITY = 0x0008
524 522
525 523 _BACKGROUND_BLUE = 0x0010
526 524 _BACKGROUND_GREEN = 0x0020
527 525 _BACKGROUND_RED = 0x0040
528 526 _BACKGROUND_INTENSITY = 0x0080
529 527
530 528 _COMMON_LVB_REVERSE_VIDEO = 0x4000
531 529 _COMMON_LVB_UNDERSCORE = 0x8000
532 530
533 531 # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
534 532 w32effects = {
535 533 'none': -1,
536 534 'black': 0,
537 535 'red': _FOREGROUND_RED,
538 536 'green': _FOREGROUND_GREEN,
539 537 'yellow': _FOREGROUND_RED | _FOREGROUND_GREEN,
540 538 'blue': _FOREGROUND_BLUE,
541 539 'magenta': _FOREGROUND_BLUE | _FOREGROUND_RED,
542 540 'cyan': _FOREGROUND_BLUE | _FOREGROUND_GREEN,
543 541 'white': _FOREGROUND_RED | _FOREGROUND_GREEN | _FOREGROUND_BLUE,
544 542 'bold': _FOREGROUND_INTENSITY,
545 543 'black_background': 0x100, # unused value > 0x0f
546 544 'red_background': _BACKGROUND_RED,
547 545 'green_background': _BACKGROUND_GREEN,
548 546 'yellow_background': _BACKGROUND_RED | _BACKGROUND_GREEN,
549 547 'blue_background': _BACKGROUND_BLUE,
550 548 'purple_background': _BACKGROUND_BLUE | _BACKGROUND_RED,
551 549 'cyan_background': _BACKGROUND_BLUE | _BACKGROUND_GREEN,
552 550 'white_background': (_BACKGROUND_RED | _BACKGROUND_GREEN |
553 551 _BACKGROUND_BLUE),
554 552 'bold_background': _BACKGROUND_INTENSITY,
555 553 'underline': _COMMON_LVB_UNDERSCORE, # double-byte charsets only
556 554 'inverse': _COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
557 555 }
558 556
559 557 passthrough = set([_FOREGROUND_INTENSITY,
560 558 _BACKGROUND_INTENSITY,
561 559 _COMMON_LVB_UNDERSCORE,
562 560 _COMMON_LVB_REVERSE_VIDEO])
563 561
564 562 stdout = _kernel32.GetStdHandle(
565 563 _STD_OUTPUT_HANDLE) # don't close the handle returned
566 564 if stdout is None or stdout == _INVALID_HANDLE_VALUE:
567 565 w32effects = None
568 566 else:
569 567 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
570 568 if not _kernel32.GetConsoleScreenBufferInfo(
571 569 stdout, ctypes.byref(csbi)):
572 570 # stdout may not support GetConsoleScreenBufferInfo()
573 571 # when called from subprocess or redirected
574 572 w32effects = None
575 573 else:
576 574 origattr = csbi.wAttributes
577 575 ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)',
578 576 re.MULTILINE | re.DOTALL)
579 577
580 578 def win32print(text, orig, **opts):
581 579 label = opts.get('label', '')
582 580 attr = origattr
583 581
584 582 def mapcolor(val, attr):
585 583 if val == -1:
586 584 return origattr
587 585 elif val in passthrough:
588 586 return attr | val
589 587 elif val > 0x0f:
590 588 return (val & 0x70) | (attr & 0x8f)
591 589 else:
592 590 return (val & 0x07) | (attr & 0xf8)
593 591
594 592 # determine console attributes based on labels
595 593 for l in label.split():
596 594 style = _styles.get(l, '')
597 595 for effect in style.split():
598 596 try:
599 597 attr = mapcolor(w32effects[effect], attr)
600 598 except KeyError:
601 599 # w32effects could not have certain attributes so we skip
602 600 # them if not found
603 601 pass
604 602 # hack to ensure regexp finds data
605 603 if not text.startswith('\033['):
606 604 text = '\033[m' + text
607 605
608 606 # Look for ANSI-like codes embedded in text
609 607 m = re.match(ansire, text)
610 608
611 609 try:
612 610 while m:
613 611 for sattr in m.group(1).split(';'):
614 612 if sattr:
615 613 attr = mapcolor(int(sattr), attr)
616 614 _kernel32.SetConsoleTextAttribute(stdout, attr)
617 615 orig(m.group(2), **opts)
618 616 m = re.match(ansire, m.group(3))
619 617 finally:
620 618 # Explicitly reset original attributes
621 619 _kernel32.SetConsoleTextAttribute(stdout, origattr)
@@ -1,350 +1,350 b''
1 1 $ echo "[extensions]" >> $HGRCPATH
2 2 $ echo "color=" >> $HGRCPATH
3 3 $ echo "[color]" >> $HGRCPATH
4 4 $ echo "mode=ansi" >> $HGRCPATH
5 5 Terminfo codes compatibility fix
6 6 $ echo "color.none=0" >> $HGRCPATH
7 7
8 8 $ hg init repo1
9 9 $ cd repo1
10 10 $ mkdir a b a/1 b/1 b/2
11 11 $ touch in_root a/in_a b/in_b a/1/in_a_1 b/1/in_b_1 b/2/in_b_2
12 12
13 13 hg status in repo root:
14 14
15 15 $ hg status --color=always
16 16 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc)
17 17 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc)
18 18 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc)
19 19 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc)
20 20 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc)
21 21 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc)
22 22
23 23 $ hg status --color=debug
24 status.unknown(? )status.unknown(a/1/in_a_1)
25 status.unknown(? )status.unknown(a/in_a)
26 status.unknown(? )status.unknown(b/1/in_b_1)
27 status.unknown(? )status.unknown(b/2/in_b_2)
28 status.unknown(? )status.unknown(b/in_b)
29 status.unknown(? )status.unknown(in_root)
24 [status.unknown|? ][status.unknown|a/1/in_a_1]
25 [status.unknown|? ][status.unknown|a/in_a]
26 [status.unknown|? ][status.unknown|b/1/in_b_1]
27 [status.unknown|? ][status.unknown|b/2/in_b_2]
28 [status.unknown|? ][status.unknown|b/in_b]
29 [status.unknown|? ][status.unknown|in_root]
30 30
31 31 hg status . in repo root:
32 32
33 33 $ hg status --color=always .
34 34 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc)
35 35 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc)
36 36 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc)
37 37 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc)
38 38 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc)
39 39 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc)
40 40
41 41 $ hg status --color=always --cwd a
42 42 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc)
43 43 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc)
44 44 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc)
45 45 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc)
46 46 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc)
47 47 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc)
48 48 $ hg status --color=always --cwd a .
49 49 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m1/in_a_1\x1b[0m (esc)
50 50 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_a\x1b[0m (esc)
51 51 $ hg status --color=always --cwd a ..
52 52 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m1/in_a_1\x1b[0m (esc)
53 53 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_a\x1b[0m (esc)
54 54 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../b/1/in_b_1\x1b[0m (esc)
55 55 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../b/2/in_b_2\x1b[0m (esc)
56 56 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../b/in_b\x1b[0m (esc)
57 57 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../in_root\x1b[0m (esc)
58 58
59 59 $ hg status --color=always --cwd b
60 60 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc)
61 61 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc)
62 62 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc)
63 63 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc)
64 64 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc)
65 65 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc)
66 66 $ hg status --color=always --cwd b .
67 67 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m1/in_b_1\x1b[0m (esc)
68 68 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m2/in_b_2\x1b[0m (esc)
69 69 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b\x1b[0m (esc)
70 70 $ hg status --color=always --cwd b ..
71 71 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../a/1/in_a_1\x1b[0m (esc)
72 72 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../a/in_a\x1b[0m (esc)
73 73 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m1/in_b_1\x1b[0m (esc)
74 74 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m2/in_b_2\x1b[0m (esc)
75 75 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b\x1b[0m (esc)
76 76 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../in_root\x1b[0m (esc)
77 77
78 78 $ hg status --color=always --cwd a/1
79 79 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc)
80 80 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc)
81 81 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc)
82 82 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc)
83 83 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc)
84 84 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc)
85 85 $ hg status --color=always --cwd a/1 .
86 86 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_a_1\x1b[0m (esc)
87 87 $ hg status --color=always --cwd a/1 ..
88 88 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_a_1\x1b[0m (esc)
89 89 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../in_a\x1b[0m (esc)
90 90
91 91 $ hg status --color=always --cwd b/1
92 92 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc)
93 93 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc)
94 94 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc)
95 95 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc)
96 96 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc)
97 97 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc)
98 98 $ hg status --color=always --cwd b/1 .
99 99 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b_1\x1b[0m (esc)
100 100 $ hg status --color=always --cwd b/1 ..
101 101 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b_1\x1b[0m (esc)
102 102 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../2/in_b_2\x1b[0m (esc)
103 103 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../in_b\x1b[0m (esc)
104 104
105 105 $ hg status --color=always --cwd b/2
106 106 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc)
107 107 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc)
108 108 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc)
109 109 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc)
110 110 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc)
111 111 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc)
112 112 $ hg status --color=always --cwd b/2 .
113 113 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b_2\x1b[0m (esc)
114 114 $ hg status --color=always --cwd b/2 ..
115 115 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../1/in_b_1\x1b[0m (esc)
116 116 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b_2\x1b[0m (esc)
117 117 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../in_b\x1b[0m (esc)
118 118
119 119 Make sure --color=never works
120 120 $ hg status --color=never
121 121 ? a/1/in_a_1
122 122 ? a/in_a
123 123 ? b/1/in_b_1
124 124 ? b/2/in_b_2
125 125 ? b/in_b
126 126 ? in_root
127 127
128 128 Make sure ui.formatted=False works
129 129 $ hg status --config ui.formatted=False
130 130 ? a/1/in_a_1
131 131 ? a/in_a
132 132 ? b/1/in_b_1
133 133 ? b/2/in_b_2
134 134 ? b/in_b
135 135 ? in_root
136 136
137 137 $ cd ..
138 138
139 139 $ hg init repo2
140 140 $ cd repo2
141 141 $ touch modified removed deleted ignored
142 142 $ echo "^ignored$" > .hgignore
143 143 $ hg ci -A -m 'initial checkin'
144 144 adding .hgignore
145 145 adding deleted
146 146 adding modified
147 147 adding removed
148 148 $ hg log --color=debug
149 [log.changeset changeset.draft](changeset: 0:389aef86a55e)
150 log.tag(tag: tip)
151 log.user(user: test)
152 log.date(date: Thu Jan 01 00:00:00 1970 +0000)
153 log.summary(summary: initial checkin)
149 [log.changeset changeset.draft|changeset: 0:389aef86a55e]
150 [log.tag|tag: tip]
151 [log.user|user: test]
152 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
153 [log.summary|summary: initial checkin]
154 154
155 155 $ touch modified added unknown ignored
156 156 $ hg add added
157 157 $ hg remove removed
158 158 $ rm deleted
159 159
160 160 hg status:
161 161
162 162 $ hg status --color=always
163 163 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1madded\x1b[0m (esc)
164 164 \x1b[0;31;1mR \x1b[0m\x1b[0;31;1mremoved\x1b[0m (esc)
165 165 \x1b[0;36;1;4m! \x1b[0m\x1b[0;36;1;4mdeleted\x1b[0m (esc)
166 166 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4munknown\x1b[0m (esc)
167 167
168 168 hg status modified added removed deleted unknown never-existed ignored:
169 169
170 170 $ hg status --color=always modified added removed deleted unknown never-existed ignored
171 171 never-existed: * (glob)
172 172 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1madded\x1b[0m (esc)
173 173 \x1b[0;31;1mR \x1b[0m\x1b[0;31;1mremoved\x1b[0m (esc)
174 174 \x1b[0;36;1;4m! \x1b[0m\x1b[0;36;1;4mdeleted\x1b[0m (esc)
175 175 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4munknown\x1b[0m (esc)
176 176
177 177 $ hg copy modified copied
178 178
179 179 hg status -C:
180 180
181 181 $ hg status --color=always -C
182 182 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1madded\x1b[0m (esc)
183 183 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mcopied\x1b[0m (esc)
184 184 \x1b[0;0m modified\x1b[0m (esc)
185 185 \x1b[0;31;1mR \x1b[0m\x1b[0;31;1mremoved\x1b[0m (esc)
186 186 \x1b[0;36;1;4m! \x1b[0m\x1b[0;36;1;4mdeleted\x1b[0m (esc)
187 187 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4munknown\x1b[0m (esc)
188 188
189 189 hg status -A:
190 190
191 191 $ hg status --color=always -A
192 192 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1madded\x1b[0m (esc)
193 193 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mcopied\x1b[0m (esc)
194 194 \x1b[0;0m modified\x1b[0m (esc)
195 195 \x1b[0;31;1mR \x1b[0m\x1b[0;31;1mremoved\x1b[0m (esc)
196 196 \x1b[0;36;1;4m! \x1b[0m\x1b[0;36;1;4mdeleted\x1b[0m (esc)
197 197 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4munknown\x1b[0m (esc)
198 198 \x1b[0;30;1mI \x1b[0m\x1b[0;30;1mignored\x1b[0m (esc)
199 199 \x1b[0;0mC \x1b[0m\x1b[0;0m.hgignore\x1b[0m (esc)
200 200 \x1b[0;0mC \x1b[0m\x1b[0;0mmodified\x1b[0m (esc)
201 201
202 202
203 203 hg status -A (with terminfo color):
204 204
205 205 #if tic
206 206
207 207 $ mkdir "$TESTTMP/terminfo"
208 208 $ TERMINFO="$TESTTMP/terminfo" tic "$TESTDIR/hgterm.ti"
209 209 $ TERM=hgterm TERMINFO="$TESTTMP/terminfo" hg status --config color.mode=terminfo --color=always -A
210 210 \x1b[30m\x1b[32m\x1b[1mA \x1b[30m\x1b[30m\x1b[32m\x1b[1madded\x1b[30m (esc)
211 211 \x1b[30m\x1b[32m\x1b[1mA \x1b[30m\x1b[30m\x1b[32m\x1b[1mcopied\x1b[30m (esc)
212 212 \x1b[30m\x1b[30m modified\x1b[30m (esc)
213 213 \x1b[30m\x1b[31m\x1b[1mR \x1b[30m\x1b[30m\x1b[31m\x1b[1mremoved\x1b[30m (esc)
214 214 \x1b[30m\x1b[36m\x1b[1m\x1b[4m! \x1b[30m\x1b[30m\x1b[36m\x1b[1m\x1b[4mdeleted\x1b[30m (esc)
215 215 \x1b[30m\x1b[35m\x1b[1m\x1b[4m? \x1b[30m\x1b[30m\x1b[35m\x1b[1m\x1b[4munknown\x1b[30m (esc)
216 216 \x1b[30m\x1b[30m\x1b[1mI \x1b[30m\x1b[30m\x1b[30m\x1b[1mignored\x1b[30m (esc)
217 217 \x1b[30m\x1b[30mC \x1b[30m\x1b[30m\x1b[30m.hgignore\x1b[30m (esc)
218 218 \x1b[30m\x1b[30mC \x1b[30m\x1b[30m\x1b[30mmodified\x1b[30m (esc)
219 219
220 220 #endif
221 221
222 222
223 223 $ echo "^ignoreddir$" > .hgignore
224 224 $ mkdir ignoreddir
225 225 $ touch ignoreddir/file
226 226
227 227 hg status ignoreddir/file:
228 228
229 229 $ hg status --color=always ignoreddir/file
230 230
231 231 hg status -i ignoreddir/file:
232 232
233 233 $ hg status --color=always -i ignoreddir/file
234 234 \x1b[0;30;1mI \x1b[0m\x1b[0;30;1mignoreddir/file\x1b[0m (esc)
235 235 $ cd ..
236 236
237 237 check 'status -q' and some combinations
238 238
239 239 $ hg init repo3
240 240 $ cd repo3
241 241 $ touch modified removed deleted ignored
242 242 $ echo "^ignored$" > .hgignore
243 243 $ hg commit -A -m 'initial checkin'
244 244 adding .hgignore
245 245 adding deleted
246 246 adding modified
247 247 adding removed
248 248 $ touch added unknown ignored
249 249 $ hg add added
250 250 $ echo "test" >> modified
251 251 $ hg remove removed
252 252 $ rm deleted
253 253 $ hg copy modified copied
254 254
255 255 test unknown color
256 256
257 257 $ hg --config color.status.modified=periwinkle status --color=always
258 258 ignoring unknown color/effect 'periwinkle' (configured in color.status.modified)
259 259 M modified
260 260 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1madded\x1b[0m (esc)
261 261 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mcopied\x1b[0m (esc)
262 262 \x1b[0;31;1mR \x1b[0m\x1b[0;31;1mremoved\x1b[0m (esc)
263 263 \x1b[0;36;1;4m! \x1b[0m\x1b[0;36;1;4mdeleted\x1b[0m (esc)
264 264 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4munknown\x1b[0m (esc)
265 265
266 266 Run status with 2 different flags.
267 267 Check if result is the same or different.
268 268 If result is not as expected, raise error
269 269
270 270 $ assert() {
271 271 > hg status --color=always $1 > ../a
272 272 > hg status --color=always $2 > ../b
273 273 > if diff ../a ../b > /dev/null; then
274 274 > out=0
275 275 > else
276 276 > out=1
277 277 > fi
278 278 > if [ $3 -eq 0 ]; then
279 279 > df="same"
280 280 > else
281 281 > df="different"
282 282 > fi
283 283 > if [ $out -ne $3 ]; then
284 284 > echo "Error on $1 and $2, should be $df."
285 285 > fi
286 286 > }
287 287
288 288 assert flag1 flag2 [0-same | 1-different]
289 289
290 290 $ assert "-q" "-mard" 0
291 291 $ assert "-A" "-marduicC" 0
292 292 $ assert "-qA" "-mardcC" 0
293 293 $ assert "-qAui" "-A" 0
294 294 $ assert "-qAu" "-marducC" 0
295 295 $ assert "-qAi" "-mardicC" 0
296 296 $ assert "-qu" "-u" 0
297 297 $ assert "-q" "-u" 1
298 298 $ assert "-m" "-a" 1
299 299 $ assert "-r" "-d" 1
300 300 $ cd ..
301 301
302 302 test 'resolve -l'
303 303
304 304 $ hg init repo4
305 305 $ cd repo4
306 306 $ echo "file a" > a
307 307 $ echo "file b" > b
308 308 $ hg add a b
309 309 $ hg commit -m "initial"
310 310 $ echo "file a change 1" > a
311 311 $ echo "file b change 1" > b
312 312 $ hg commit -m "head 1"
313 313 $ hg update 0
314 314 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
315 315 $ echo "file a change 2" > a
316 316 $ echo "file b change 2" > b
317 317 $ hg commit -m "head 2"
318 318 created new head
319 319 $ hg merge
320 320 merging a
321 321 warning: conflicts during merge.
322 322 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
323 323 merging b
324 324 warning: conflicts during merge.
325 325 merging b incomplete! (edit conflicts, then use 'hg resolve --mark')
326 326 0 files updated, 0 files merged, 0 files removed, 2 files unresolved
327 327 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
328 328 [1]
329 329 $ hg resolve -m b
330 330
331 331 hg resolve with one unresolved, one resolved:
332 332
333 333 $ hg resolve --color=always -l
334 334 \x1b[0;31;1mU a\x1b[0m (esc)
335 335 \x1b[0;32;1mR b\x1b[0m (esc)
336 336
337 337 color coding of error message with current availability of curses
338 338
339 339 $ hg unknowncommand > /dev/null
340 340 hg: unknown command 'unknowncommand'
341 341 [255]
342 342
343 343 color coding of error message without curses
344 344
345 345 $ echo 'raise ImportError' > curses.py
346 346 $ PYTHONPATH=`pwd`:$PYTHONPATH hg unknowncommand > /dev/null
347 347 hg: unknown command 'unknowncommand'
348 348 [255]
349 349
350 350 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now