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