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