##// END OF EJS Templates
color: change color of grep.rev label (BC)...
Jordi Gutiérrez Hermoso -
r41889:a91615b7 default
parent child Browse files
Show More
@@ -1,534 +1,534 b''
1 1 # utility for color output for Mercurial commands
2 2 #
3 3 # Copyright (C) 2007 Kevin Christen <kevin.christen@gmail.com> and other
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 from __future__ import absolute_import
9 9
10 10 import re
11 11
12 12 from .i18n import _
13 13
14 14 from . import (
15 15 encoding,
16 16 pycompat,
17 17 )
18 18
19 19 from .utils import (
20 20 stringutil,
21 21 )
22 22
23 23 try:
24 24 import curses
25 25 # Mapping from effect name to terminfo attribute name (or raw code) or
26 26 # color number. This will also force-load the curses module.
27 27 _baseterminfoparams = {
28 28 'none': (True, 'sgr0', ''),
29 29 'standout': (True, 'smso', ''),
30 30 'underline': (True, 'smul', ''),
31 31 'reverse': (True, 'rev', ''),
32 32 'inverse': (True, 'rev', ''),
33 33 'blink': (True, 'blink', ''),
34 34 'dim': (True, 'dim', ''),
35 35 'bold': (True, 'bold', ''),
36 36 'invisible': (True, 'invis', ''),
37 37 'italic': (True, 'sitm', ''),
38 38 'black': (False, curses.COLOR_BLACK, ''),
39 39 'red': (False, curses.COLOR_RED, ''),
40 40 'green': (False, curses.COLOR_GREEN, ''),
41 41 'yellow': (False, curses.COLOR_YELLOW, ''),
42 42 'blue': (False, curses.COLOR_BLUE, ''),
43 43 'magenta': (False, curses.COLOR_MAGENTA, ''),
44 44 'cyan': (False, curses.COLOR_CYAN, ''),
45 45 'white': (False, curses.COLOR_WHITE, ''),
46 46 }
47 47 except ImportError:
48 48 curses = None
49 49 _baseterminfoparams = {}
50 50
51 51 # start and stop parameters for effects
52 52 _effects = {
53 53 'none': 0,
54 54 'black': 30,
55 55 'red': 31,
56 56 'green': 32,
57 57 'yellow': 33,
58 58 'blue': 34,
59 59 'magenta': 35,
60 60 'cyan': 36,
61 61 'white': 37,
62 62 'bold': 1,
63 63 'italic': 3,
64 64 'underline': 4,
65 65 'inverse': 7,
66 66 'dim': 2,
67 67 'black_background': 40,
68 68 'red_background': 41,
69 69 'green_background': 42,
70 70 'yellow_background': 43,
71 71 'blue_background': 44,
72 72 'purple_background': 45,
73 73 'cyan_background': 46,
74 74 'white_background': 47,
75 75 }
76 76
77 77 _defaultstyles = {
78 78 'grep.match': 'red bold',
79 79 'grep.linenumber': 'green',
80 'grep.rev': 'green',
80 'grep.rev': 'blue',
81 81 'grep.sep': 'cyan',
82 82 'grep.filename': 'magenta',
83 83 'grep.user': 'magenta',
84 84 'grep.date': 'magenta',
85 85 'grep.inserted': 'green bold',
86 86 'grep.deleted': 'red bold',
87 87 'bookmarks.active': 'green',
88 88 'branches.active': 'none',
89 89 'branches.closed': 'black bold',
90 90 'branches.current': 'green',
91 91 'branches.inactive': 'none',
92 92 'diff.changed': 'white',
93 93 'diff.deleted': 'red',
94 94 'diff.deleted.changed': 'red bold underline',
95 95 'diff.deleted.unchanged': 'red',
96 96 'diff.diffline': 'bold',
97 97 'diff.extended': 'cyan bold',
98 98 'diff.file_a': 'red bold',
99 99 'diff.file_b': 'green bold',
100 100 'diff.hunk': 'magenta',
101 101 'diff.inserted': 'green',
102 102 'diff.inserted.changed': 'green bold underline',
103 103 'diff.inserted.unchanged': 'green',
104 104 'diff.tab': '',
105 105 'diff.trailingwhitespace': 'bold red_background',
106 106 'changeset.public': '',
107 107 'changeset.draft': '',
108 108 'changeset.secret': '',
109 109 'diffstat.deleted': 'red',
110 110 'diffstat.inserted': 'green',
111 111 'formatvariant.name.mismatchconfig': 'red',
112 112 'formatvariant.name.mismatchdefault': 'yellow',
113 113 'formatvariant.name.uptodate': 'green',
114 114 'formatvariant.repo.mismatchconfig': 'red',
115 115 'formatvariant.repo.mismatchdefault': 'yellow',
116 116 'formatvariant.repo.uptodate': 'green',
117 117 'formatvariant.config.special': 'yellow',
118 118 'formatvariant.config.default': 'green',
119 119 'formatvariant.default': '',
120 120 'histedit.remaining': 'red bold',
121 121 'ui.addremove.added': 'green',
122 122 'ui.addremove.removed': 'red',
123 123 'ui.error': 'red',
124 124 'ui.prompt': 'yellow',
125 125 'log.changeset': 'yellow',
126 126 'patchbomb.finalsummary': '',
127 127 'patchbomb.from': 'magenta',
128 128 'patchbomb.to': 'cyan',
129 129 'patchbomb.subject': 'green',
130 130 'patchbomb.diffstats': '',
131 131 'rebase.rebased': 'blue',
132 132 'rebase.remaining': 'red bold',
133 133 'resolve.resolved': 'green bold',
134 134 'resolve.unresolved': 'red bold',
135 135 'shelve.age': 'cyan',
136 136 'shelve.newest': 'green bold',
137 137 'shelve.name': 'blue bold',
138 138 'status.added': 'green bold',
139 139 'status.clean': 'none',
140 140 'status.copied': 'none',
141 141 'status.deleted': 'cyan bold underline',
142 142 'status.ignored': 'black bold',
143 143 'status.modified': 'blue bold',
144 144 'status.removed': 'red bold',
145 145 'status.unknown': 'magenta bold underline',
146 146 'tags.normal': 'green',
147 147 'tags.local': 'black bold',
148 148 }
149 149
150 150 def loadcolortable(ui, extname, colortable):
151 151 _defaultstyles.update(colortable)
152 152
153 153 def _terminfosetup(ui, mode, formatted):
154 154 '''Initialize terminfo data and the terminal if we're in terminfo mode.'''
155 155
156 156 # If we failed to load curses, we go ahead and return.
157 157 if curses is None:
158 158 return
159 159 # Otherwise, see what the config file says.
160 160 if mode not in ('auto', 'terminfo'):
161 161 return
162 162 ui._terminfoparams.update(_baseterminfoparams)
163 163
164 164 for key, val in ui.configitems('color'):
165 165 if key.startswith('color.'):
166 166 newval = (False, int(val), '')
167 167 ui._terminfoparams[key[6:]] = newval
168 168 elif key.startswith('terminfo.'):
169 169 newval = (True, '', val.replace('\\E', '\x1b'))
170 170 ui._terminfoparams[key[9:]] = newval
171 171 try:
172 172 curses.setupterm()
173 173 except curses.error:
174 174 ui._terminfoparams.clear()
175 175 return
176 176
177 177 for key, (b, e, c) in ui._terminfoparams.copy().items():
178 178 if not b:
179 179 continue
180 180 if not c and not curses.tigetstr(pycompat.sysstr(e)):
181 181 # Most terminals don't support dim, invis, etc, so don't be
182 182 # noisy and use ui.debug().
183 183 ui.debug("no terminfo entry for %s\n" % e)
184 184 del ui._terminfoparams[key]
185 185 if not curses.tigetstr(r'setaf') or not curses.tigetstr(r'setab'):
186 186 # Only warn about missing terminfo entries if we explicitly asked for
187 187 # terminfo mode and we're in a formatted terminal.
188 188 if mode == "terminfo" and formatted:
189 189 ui.warn(_("no terminfo entry for setab/setaf: reverting to "
190 190 "ECMA-48 color\n"))
191 191 ui._terminfoparams.clear()
192 192
193 193 def setup(ui):
194 194 """configure color on a ui
195 195
196 196 That function both set the colormode for the ui object and read
197 197 the configuration looking for custom colors and effect definitions."""
198 198 mode = _modesetup(ui)
199 199 ui._colormode = mode
200 200 if mode and mode != 'debug':
201 201 configstyles(ui)
202 202
203 203 def _modesetup(ui):
204 204 if ui.plain('color'):
205 205 return None
206 206 config = ui.config('ui', 'color')
207 207 if config == 'debug':
208 208 return 'debug'
209 209
210 210 auto = (config == 'auto')
211 211 always = False
212 212 if not auto and stringutil.parsebool(config):
213 213 # We want the config to behave like a boolean, "on" is actually auto,
214 214 # but "always" value is treated as a special case to reduce confusion.
215 215 if ui.configsource('ui', 'color') == '--color' or config == 'always':
216 216 always = True
217 217 else:
218 218 auto = True
219 219
220 220 if not always and not auto:
221 221 return None
222 222
223 223 formatted = (always or (encoding.environ.get('TERM') != 'dumb'
224 224 and ui.formatted()))
225 225
226 226 mode = ui.config('color', 'mode')
227 227
228 228 # If pager is active, color.pagermode overrides color.mode.
229 229 if getattr(ui, 'pageractive', False):
230 230 mode = ui.config('color', 'pagermode', mode)
231 231
232 232 realmode = mode
233 233 if pycompat.iswindows:
234 234 from . import win32
235 235
236 236 term = encoding.environ.get('TERM')
237 237 # TERM won't be defined in a vanilla cmd.exe environment.
238 238
239 239 # UNIX-like environments on Windows such as Cygwin and MSYS will
240 240 # set TERM. They appear to make a best effort attempt at setting it
241 241 # to something appropriate. However, not all environments with TERM
242 242 # defined support ANSI.
243 243 ansienviron = term and 'xterm' in term
244 244
245 245 if mode == 'auto':
246 246 # Since "ansi" could result in terminal gibberish, we error on the
247 247 # side of selecting "win32". However, if w32effects is not defined,
248 248 # we almost certainly don't support "win32", so don't even try.
249 249 # w32effects is not populated when stdout is redirected, so checking
250 250 # it first avoids win32 calls in a state known to error out.
251 251 if ansienviron or not w32effects or win32.enablevtmode():
252 252 realmode = 'ansi'
253 253 else:
254 254 realmode = 'win32'
255 255 # An empty w32effects is a clue that stdout is redirected, and thus
256 256 # cannot enable VT mode.
257 257 elif mode == 'ansi' and w32effects and not ansienviron:
258 258 win32.enablevtmode()
259 259 elif mode == 'auto':
260 260 realmode = 'ansi'
261 261
262 262 def modewarn():
263 263 # only warn if color.mode was explicitly set and we're in
264 264 # a formatted terminal
265 265 if mode == realmode and formatted:
266 266 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
267 267
268 268 if realmode == 'win32':
269 269 ui._terminfoparams.clear()
270 270 if not w32effects:
271 271 modewarn()
272 272 return None
273 273 elif realmode == 'ansi':
274 274 ui._terminfoparams.clear()
275 275 elif realmode == 'terminfo':
276 276 _terminfosetup(ui, mode, formatted)
277 277 if not ui._terminfoparams:
278 278 ## FIXME Shouldn't we return None in this case too?
279 279 modewarn()
280 280 realmode = 'ansi'
281 281 else:
282 282 return None
283 283
284 284 if always or (auto and formatted):
285 285 return realmode
286 286 return None
287 287
288 288 def configstyles(ui):
289 289 ui._styles.update(_defaultstyles)
290 290 for status, cfgeffects in ui.configitems('color'):
291 291 if '.' not in status or status.startswith(('color.', 'terminfo.')):
292 292 continue
293 293 cfgeffects = ui.configlist('color', status)
294 294 if cfgeffects:
295 295 good = []
296 296 for e in cfgeffects:
297 297 if valideffect(ui, e):
298 298 good.append(e)
299 299 else:
300 300 ui.warn(_("ignoring unknown color/effect %s "
301 301 "(configured in color.%s)\n")
302 302 % (stringutil.pprint(e), status))
303 303 ui._styles[status] = ' '.join(good)
304 304
305 305 def _activeeffects(ui):
306 306 '''Return the effects map for the color mode set on the ui.'''
307 307 if ui._colormode == 'win32':
308 308 return w32effects
309 309 elif ui._colormode is not None:
310 310 return _effects
311 311 return {}
312 312
313 313 def valideffect(ui, effect):
314 314 'Determine if the effect is valid or not.'
315 315 return ((not ui._terminfoparams and effect in _activeeffects(ui))
316 316 or (effect in ui._terminfoparams
317 317 or effect[:-11] in ui._terminfoparams))
318 318
319 319 def _effect_str(ui, effect):
320 320 '''Helper function for render_effects().'''
321 321
322 322 bg = False
323 323 if effect.endswith('_background'):
324 324 bg = True
325 325 effect = effect[:-11]
326 326 try:
327 327 attr, val, termcode = ui._terminfoparams[effect]
328 328 except KeyError:
329 329 return ''
330 330 if attr:
331 331 if termcode:
332 332 return termcode
333 333 else:
334 334 return curses.tigetstr(pycompat.sysstr(val))
335 335 elif bg:
336 336 return curses.tparm(curses.tigetstr(r'setab'), val)
337 337 else:
338 338 return curses.tparm(curses.tigetstr(r'setaf'), val)
339 339
340 340 def _mergeeffects(text, start, stop):
341 341 """Insert start sequence at every occurrence of stop sequence
342 342
343 343 >>> s = _mergeeffects(b'cyan', b'[C]', b'|')
344 344 >>> s = _mergeeffects(s + b'yellow', b'[Y]', b'|')
345 345 >>> s = _mergeeffects(b'ma' + s + b'genta', b'[M]', b'|')
346 346 >>> s = _mergeeffects(b'red' + s, b'[R]', b'|')
347 347 >>> s
348 348 '[R]red[M]ma[Y][C]cyan|[R][M][Y]yellow|[R][M]genta|'
349 349 """
350 350 parts = []
351 351 for t in text.split(stop):
352 352 if not t:
353 353 continue
354 354 parts.extend([start, t, stop])
355 355 return ''.join(parts)
356 356
357 357 def _render_effects(ui, text, effects):
358 358 'Wrap text in commands to turn on each effect.'
359 359 if not text:
360 360 return text
361 361 if ui._terminfoparams:
362 362 start = ''.join(_effect_str(ui, effect)
363 363 for effect in ['none'] + effects.split())
364 364 stop = _effect_str(ui, 'none')
365 365 else:
366 366 activeeffects = _activeeffects(ui)
367 367 start = [pycompat.bytestr(activeeffects[e])
368 368 for e in ['none'] + effects.split()]
369 369 start = '\033[' + ';'.join(start) + 'm'
370 370 stop = '\033[' + pycompat.bytestr(activeeffects['none']) + 'm'
371 371 return _mergeeffects(text, start, stop)
372 372
373 373 _ansieffectre = re.compile(br'\x1b\[[0-9;]*m')
374 374
375 375 def stripeffects(text):
376 376 """Strip ANSI control codes which could be inserted by colorlabel()"""
377 377 return _ansieffectre.sub('', text)
378 378
379 379 def colorlabel(ui, msg, label):
380 380 """add color control code according to the mode"""
381 381 if ui._colormode == 'debug':
382 382 if label and msg:
383 383 if msg.endswith('\n'):
384 384 msg = "[%s|%s]\n" % (label, msg[:-1])
385 385 else:
386 386 msg = "[%s|%s]" % (label, msg)
387 387 elif ui._colormode is not None:
388 388 effects = []
389 389 for l in label.split():
390 390 s = ui._styles.get(l, '')
391 391 if s:
392 392 effects.append(s)
393 393 elif valideffect(ui, l):
394 394 effects.append(l)
395 395 effects = ' '.join(effects)
396 396 if effects:
397 397 msg = '\n'.join([_render_effects(ui, line, effects)
398 398 for line in msg.split('\n')])
399 399 return msg
400 400
401 401 w32effects = None
402 402 if pycompat.iswindows:
403 403 import ctypes
404 404
405 405 _kernel32 = ctypes.windll.kernel32
406 406
407 407 _WORD = ctypes.c_ushort
408 408
409 409 _INVALID_HANDLE_VALUE = -1
410 410
411 411 class _COORD(ctypes.Structure):
412 412 _fields_ = [(r'X', ctypes.c_short),
413 413 (r'Y', ctypes.c_short)]
414 414
415 415 class _SMALL_RECT(ctypes.Structure):
416 416 _fields_ = [(r'Left', ctypes.c_short),
417 417 (r'Top', ctypes.c_short),
418 418 (r'Right', ctypes.c_short),
419 419 (r'Bottom', ctypes.c_short)]
420 420
421 421 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
422 422 _fields_ = [(r'dwSize', _COORD),
423 423 (r'dwCursorPosition', _COORD),
424 424 (r'wAttributes', _WORD),
425 425 (r'srWindow', _SMALL_RECT),
426 426 (r'dwMaximumWindowSize', _COORD)]
427 427
428 428 _STD_OUTPUT_HANDLE = 0xfffffff5 # (DWORD)-11
429 429 _STD_ERROR_HANDLE = 0xfffffff4 # (DWORD)-12
430 430
431 431 _FOREGROUND_BLUE = 0x0001
432 432 _FOREGROUND_GREEN = 0x0002
433 433 _FOREGROUND_RED = 0x0004
434 434 _FOREGROUND_INTENSITY = 0x0008
435 435
436 436 _BACKGROUND_BLUE = 0x0010
437 437 _BACKGROUND_GREEN = 0x0020
438 438 _BACKGROUND_RED = 0x0040
439 439 _BACKGROUND_INTENSITY = 0x0080
440 440
441 441 _COMMON_LVB_REVERSE_VIDEO = 0x4000
442 442 _COMMON_LVB_UNDERSCORE = 0x8000
443 443
444 444 # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
445 445 w32effects = {
446 446 'none': -1,
447 447 'black': 0,
448 448 'red': _FOREGROUND_RED,
449 449 'green': _FOREGROUND_GREEN,
450 450 'yellow': _FOREGROUND_RED | _FOREGROUND_GREEN,
451 451 'blue': _FOREGROUND_BLUE,
452 452 'magenta': _FOREGROUND_BLUE | _FOREGROUND_RED,
453 453 'cyan': _FOREGROUND_BLUE | _FOREGROUND_GREEN,
454 454 'white': _FOREGROUND_RED | _FOREGROUND_GREEN | _FOREGROUND_BLUE,
455 455 'bold': _FOREGROUND_INTENSITY,
456 456 'black_background': 0x100, # unused value > 0x0f
457 457 'red_background': _BACKGROUND_RED,
458 458 'green_background': _BACKGROUND_GREEN,
459 459 'yellow_background': _BACKGROUND_RED | _BACKGROUND_GREEN,
460 460 'blue_background': _BACKGROUND_BLUE,
461 461 'purple_background': _BACKGROUND_BLUE | _BACKGROUND_RED,
462 462 'cyan_background': _BACKGROUND_BLUE | _BACKGROUND_GREEN,
463 463 'white_background': (_BACKGROUND_RED | _BACKGROUND_GREEN |
464 464 _BACKGROUND_BLUE),
465 465 'bold_background': _BACKGROUND_INTENSITY,
466 466 'underline': _COMMON_LVB_UNDERSCORE, # double-byte charsets only
467 467 'inverse': _COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
468 468 }
469 469
470 470 passthrough = {_FOREGROUND_INTENSITY,
471 471 _BACKGROUND_INTENSITY,
472 472 _COMMON_LVB_UNDERSCORE,
473 473 _COMMON_LVB_REVERSE_VIDEO}
474 474
475 475 stdout = _kernel32.GetStdHandle(
476 476 _STD_OUTPUT_HANDLE) # don't close the handle returned
477 477 if stdout is None or stdout == _INVALID_HANDLE_VALUE:
478 478 w32effects = None
479 479 else:
480 480 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
481 481 if not _kernel32.GetConsoleScreenBufferInfo(
482 482 stdout, ctypes.byref(csbi)):
483 483 # stdout may not support GetConsoleScreenBufferInfo()
484 484 # when called from subprocess or redirected
485 485 w32effects = None
486 486 else:
487 487 origattr = csbi.wAttributes
488 488 ansire = re.compile(br'\033\[([^m]*)m([^\033]*)(.*)',
489 489 re.MULTILINE | re.DOTALL)
490 490
491 491 def win32print(ui, writefunc, text, **opts):
492 492 label = opts.get(r'label', '')
493 493 attr = origattr
494 494
495 495 def mapcolor(val, attr):
496 496 if val == -1:
497 497 return origattr
498 498 elif val in passthrough:
499 499 return attr | val
500 500 elif val > 0x0f:
501 501 return (val & 0x70) | (attr & 0x8f)
502 502 else:
503 503 return (val & 0x07) | (attr & 0xf8)
504 504
505 505 # determine console attributes based on labels
506 506 for l in label.split():
507 507 style = ui._styles.get(l, '')
508 508 for effect in style.split():
509 509 try:
510 510 attr = mapcolor(w32effects[effect], attr)
511 511 except KeyError:
512 512 # w32effects could not have certain attributes so we skip
513 513 # them if not found
514 514 pass
515 515 # hack to ensure regexp finds data
516 516 if not text.startswith(b'\033['):
517 517 text = b'\033[m' + text
518 518
519 519 # Look for ANSI-like codes embedded in text
520 520 m = re.match(ansire, text)
521 521
522 522 try:
523 523 while m:
524 524 for sattr in m.group(1).split(b';'):
525 525 if sattr:
526 526 attr = mapcolor(int(sattr), attr)
527 527 ui.flush()
528 528 _kernel32.SetConsoleTextAttribute(stdout, attr)
529 529 writefunc(m.group(2))
530 530 m = re.match(ansire, m.group(3))
531 531 finally:
532 532 # Explicitly reset original attributes
533 533 ui.flush()
534 534 _kernel32.SetConsoleTextAttribute(stdout, origattr)
@@ -1,533 +1,533 b''
1 1 $ hg init t
2 2 $ cd t
3 3 $ echo import > port
4 4 $ hg add port
5 5 $ hg commit -m 0 -u spam -d '0 0'
6 6 $ echo export >> port
7 7 $ hg commit -m 1 -u eggs -d '1 0'
8 8 $ echo export > port
9 9 $ echo vaportight >> port
10 10 $ echo 'import/export' >> port
11 11 $ hg commit -m 2 -u spam -d '2 0'
12 12 $ echo 'import/export' >> port
13 13 $ hg commit -m 3 -u eggs -d '3 0'
14 14 $ head -n 3 port > port1
15 15 $ mv port1 port
16 16 $ hg commit -m 4 -u spam -d '4 0'
17 17
18 18 pattern error
19 19
20 20 $ hg grep '**test**'
21 21 grep: invalid match pattern: nothing to repeat* (glob)
22 22 [1]
23 23
24 24 simple
25 25
26 26 $ hg grep -r tip:0 '.*'
27 27 port:4:export
28 28 port:4:vaportight
29 29 port:4:import/export
30 30 $ hg grep -r tip:0 port port
31 31 port:4:export
32 32 port:4:vaportight
33 33 port:4:import/export
34 34
35 35 simple from subdirectory
36 36
37 37 $ mkdir dir
38 38 $ cd dir
39 39 $ hg grep -r tip:0 port
40 40 port:4:export
41 41 port:4:vaportight
42 42 port:4:import/export
43 43 $ hg grep -r tip:0 port --config ui.relative-paths=yes
44 44 ../port:4:export
45 45 ../port:4:vaportight
46 46 ../port:4:import/export
47 47 $ cd ..
48 48
49 49 simple with color
50 50
51 51 $ hg --config extensions.color= grep --config color.mode=ansi \
52 52 > --color=always port port -r tip:0
53 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m4\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
54 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m4\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc)
55 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m4\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
53 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m4\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
54 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m4\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc)
55 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m4\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
56 56
57 57 simple templated
58 58
59 59 $ hg grep port -r tip:0 \
60 60 > -T '{path}:{rev}:{node|short}:{texts % "{if(matched, text|upper, text)}"}\n'
61 61 port:4:914fa752cdea:exPORT
62 62 port:4:914fa752cdea:vaPORTight
63 63 port:4:914fa752cdea:imPORT/exPORT
64 64
65 65 $ hg grep port -r tip:0 -T '{path}:{rev}:{texts}\n'
66 66 port:4:export
67 67 port:4:vaportight
68 68 port:4:import/export
69 69
70 70 $ hg grep port -r tip:0 -T '{path}:{tags}:{texts}\n'
71 71 port:tip:export
72 72 port:tip:vaportight
73 73 port:tip:import/export
74 74
75 75 simple JSON (no "change" field)
76 76
77 77 $ hg grep -r tip:0 -Tjson port
78 78 [
79 79 {
80 80 "date": [4, 0],
81 81 "lineno": 1,
82 82 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
83 83 "path": "port",
84 84 "rev": 4,
85 85 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
86 86 "user": "spam"
87 87 },
88 88 {
89 89 "date": [4, 0],
90 90 "lineno": 2,
91 91 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
92 92 "path": "port",
93 93 "rev": 4,
94 94 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
95 95 "user": "spam"
96 96 },
97 97 {
98 98 "date": [4, 0],
99 99 "lineno": 3,
100 100 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
101 101 "path": "port",
102 102 "rev": 4,
103 103 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
104 104 "user": "spam"
105 105 }
106 106 ]
107 107
108 108 simple JSON without matching lines
109 109
110 110 $ hg grep -r tip:0 -Tjson -l port
111 111 [
112 112 {
113 113 "date": [4, 0],
114 114 "lineno": 1,
115 115 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
116 116 "path": "port",
117 117 "rev": 4,
118 118 "user": "spam"
119 119 }
120 120 ]
121 121
122 122 all
123 123
124 124 $ hg grep --traceback --all -nu port port
125 125 port:4:4:-:spam:import/export
126 126 port:3:4:+:eggs:import/export
127 127 port:2:1:-:spam:import
128 128 port:2:2:-:spam:export
129 129 port:2:1:+:spam:export
130 130 port:2:2:+:spam:vaportight
131 131 port:2:3:+:spam:import/export
132 132 port:1:2:+:eggs:export
133 133 port:0:1:+:spam:import
134 134
135 135 all JSON
136 136
137 137 $ hg grep --all -Tjson port port
138 138 [
139 139 {
140 140 "change": "-",
141 141 "date": [4, 0],
142 142 "lineno": 4,
143 143 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
144 144 "path": "port",
145 145 "rev": 4,
146 146 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
147 147 "user": "spam"
148 148 },
149 149 {
150 150 "change": "+",
151 151 "date": [3, 0],
152 152 "lineno": 4,
153 153 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
154 154 "path": "port",
155 155 "rev": 3,
156 156 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
157 157 "user": "eggs"
158 158 },
159 159 {
160 160 "change": "-",
161 161 "date": [2, 0],
162 162 "lineno": 1,
163 163 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
164 164 "path": "port",
165 165 "rev": 2,
166 166 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
167 167 "user": "spam"
168 168 },
169 169 {
170 170 "change": "-",
171 171 "date": [2, 0],
172 172 "lineno": 2,
173 173 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
174 174 "path": "port",
175 175 "rev": 2,
176 176 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
177 177 "user": "spam"
178 178 },
179 179 {
180 180 "change": "+",
181 181 "date": [2, 0],
182 182 "lineno": 1,
183 183 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
184 184 "path": "port",
185 185 "rev": 2,
186 186 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
187 187 "user": "spam"
188 188 },
189 189 {
190 190 "change": "+",
191 191 "date": [2, 0],
192 192 "lineno": 2,
193 193 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
194 194 "path": "port",
195 195 "rev": 2,
196 196 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
197 197 "user": "spam"
198 198 },
199 199 {
200 200 "change": "+",
201 201 "date": [2, 0],
202 202 "lineno": 3,
203 203 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
204 204 "path": "port",
205 205 "rev": 2,
206 206 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
207 207 "user": "spam"
208 208 },
209 209 {
210 210 "change": "+",
211 211 "date": [1, 0],
212 212 "lineno": 2,
213 213 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
214 214 "path": "port",
215 215 "rev": 1,
216 216 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
217 217 "user": "eggs"
218 218 },
219 219 {
220 220 "change": "+",
221 221 "date": [0, 0],
222 222 "lineno": 1,
223 223 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
224 224 "path": "port",
225 225 "rev": 0,
226 226 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
227 227 "user": "spam"
228 228 }
229 229 ]
230 230
231 231 other
232 232
233 233 $ hg grep -r tip:0 -l port port
234 234 port:4
235 235 $ hg grep -r tip:0 import port
236 236 port:4:import/export
237 237
238 238 $ hg cp port port2
239 239 $ hg commit -m 4 -u spam -d '5 0'
240 240
241 241 follow
242 242
243 243 $ hg grep -r tip:0 --traceback -f 'import\n\Z' port2
244 244 port:0:import
245 245
246 246 $ echo deport >> port2
247 247 $ hg commit -m 5 -u eggs -d '6 0'
248 248 $ hg grep -f --all -nu port port2
249 249 port2:6:4:+:eggs:deport
250 250 port:4:4:-:spam:import/export
251 251 port:3:4:+:eggs:import/export
252 252 port:2:1:-:spam:import
253 253 port:2:2:-:spam:export
254 254 port:2:1:+:spam:export
255 255 port:2:2:+:spam:vaportight
256 256 port:2:3:+:spam:import/export
257 257 port:1:2:+:eggs:export
258 258 port:0:1:+:spam:import
259 259
260 260 $ hg up -q null
261 261 $ hg grep -r 'reverse(:.)' -f port
262 262 port:0:import
263 263
264 264 Test wdir
265 265 (at least, this shouldn't crash)
266 266
267 267 $ hg up -q
268 268 $ echo wport >> port2
269 269 $ hg stat
270 270 M port2
271 271 $ hg grep -r 'wdir()' port
272 272 port2:2147483647:export
273 273 port2:2147483647:vaportight
274 274 port2:2147483647:import/export
275 275 port2:2147483647:deport
276 276 port2:2147483647:wport
277 277
278 278 $ cd ..
279 279 $ hg init t2
280 280 $ cd t2
281 281 $ hg grep -r tip:0 foobar foo
282 282 [1]
283 283 $ hg grep -r tip:0 foobar
284 284 [1]
285 285 $ echo blue >> color
286 286 $ echo black >> color
287 287 $ hg add color
288 288 $ hg ci -m 0
289 289 $ echo orange >> color
290 290 $ hg ci -m 1
291 291 $ echo black > color
292 292 $ hg ci -m 2
293 293 $ echo orange >> color
294 294 $ echo blue >> color
295 295 $ hg ci -m 3
296 296 $ hg grep -r tip:0 orange
297 297 color:3:orange
298 298 $ hg grep --all orange
299 299 color:3:+:orange
300 300 color:2:-:orange
301 301 color:1:+:orange
302 302 $ hg grep --diff orange --color=debug
303 303 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.inserted grep.change|+][grep.sep|:][grep.match|orange]
304 304 [grep.filename|color][grep.sep|:][grep.rev|2][grep.sep|:][grep.deleted grep.change|-][grep.sep|:][grep.match|orange]
305 305 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.inserted grep.change|+][grep.sep|:][grep.match|orange]
306 306
307 307 $ hg grep --diff orange --color=yes
308 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m3\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32;1m+\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
309 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m2\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1m-\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
310 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m1\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32;1m+\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
308 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32;1m+\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
309 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m2\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1m-\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
310 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m1\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32;1m+\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
311 311
312 312 $ hg grep --diff orange
313 313 color:3:+:orange
314 314 color:2:-:orange
315 315 color:1:+:orange
316 316
317 317 test substring match: '^' should only match at the beginning
318 318
319 319 $ hg grep -r tip:0 '^.' --config extensions.color= --color debug
320 320 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lack
321 321 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|o]range
322 322 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lue
323 323
324 324 match in last "line" without newline
325 325
326 326 $ "$PYTHON" -c 'fp = open("noeol", "wb"); fp.write(b"no infinite loop"); fp.close();'
327 327 $ hg ci -Amnoeol
328 328 adding noeol
329 329 $ hg grep -r tip:0 loop
330 330 noeol:4:no infinite loop
331 331
332 332 $ cd ..
333 333
334 334 Issue685: traceback in grep -r after rename
335 335
336 336 Got a traceback when using grep on a single
337 337 revision with renamed files.
338 338
339 339 $ hg init issue685
340 340 $ cd issue685
341 341 $ echo octarine > color
342 342 $ hg ci -Amcolor
343 343 adding color
344 344 $ hg rename color colour
345 345 $ hg ci -Am rename
346 346 $ hg grep -r tip:0 octarine
347 347 colour:1:octarine
348 348 color:0:octarine
349 349
350 350 Used to crash here
351 351
352 352 $ hg grep -r 1 octarine
353 353 colour:1:octarine
354 354 $ cd ..
355 355
356 356
357 357 Issue337: test that grep follows parent-child relationships instead
358 358 of just using revision numbers.
359 359
360 360 $ hg init issue337
361 361 $ cd issue337
362 362
363 363 $ echo white > color
364 364 $ hg commit -A -m "0 white"
365 365 adding color
366 366
367 367 $ echo red > color
368 368 $ hg commit -A -m "1 red"
369 369
370 370 $ hg update 0
371 371 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
372 372 $ echo black > color
373 373 $ hg commit -A -m "2 black"
374 374 created new head
375 375
376 376 $ hg update --clean 1
377 377 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
378 378 $ echo blue > color
379 379 $ hg commit -A -m "3 blue"
380 380
381 381 $ hg grep --all red
382 382 color:3:-:red
383 383 color:1:+:red
384 384
385 385 $ hg grep --diff red
386 386 color:3:-:red
387 387 color:1:+:red
388 388
389 389 Issue3885: test that changing revision order does not alter the
390 390 revisions printed, just their order.
391 391
392 392 $ hg grep --all red -r "all()"
393 393 color:1:+:red
394 394 color:3:-:red
395 395
396 396 $ hg grep --all red -r "reverse(all())"
397 397 color:3:-:red
398 398 color:1:+:red
399 399
400 400 $ hg grep --diff red -r "all()"
401 401 color:1:+:red
402 402 color:3:-:red
403 403
404 404 $ hg grep --diff red -r "reverse(all())"
405 405 color:3:-:red
406 406 color:1:+:red
407 407
408 408 $ cd ..
409 409
410 410 $ hg init a
411 411 $ cd a
412 412 $ cp "$TESTDIR/binfile.bin" .
413 413 $ hg add binfile.bin
414 414 $ hg ci -m 'add binfile.bin'
415 415 $ hg grep "MaCam" --all
416 416 binfile.bin:0:+: Binary file matches
417 417
418 418 $ hg grep "MaCam" --diff
419 419 binfile.bin:0:+: Binary file matches
420 420
421 421 $ cd ..
422 422
423 423 Test for showing working of allfiles flag
424 424
425 425 $ hg init sng
426 426 $ cd sng
427 427 $ echo "unmod" >> um
428 428 $ hg ci -A -m "adds unmod to um"
429 429 adding um
430 430 $ echo "something else" >> new
431 431 $ hg ci -A -m "second commit"
432 432 adding new
433 433 $ hg grep -r "." "unmod"
434 434 [1]
435 435 $ hg grep -r "." "unmod" --all-files
436 436 um:1:unmod
437 437
438 438 With --all-files, the working directory is searched by default
439 439
440 440 $ echo modified >> new
441 441 $ hg grep --all-files mod
442 442 new:modified
443 443 um:unmod
444 444
445 445 which can be overridden by -rREV
446 446
447 447 $ hg grep --all-files -r. mod
448 448 um:1:unmod
449 449
450 450 commands.all-files can be negated by --no-all-files
451 451
452 452 $ hg grep --config commands.grep.all-files=True mod
453 453 new:modified
454 454 um:unmod
455 455 $ hg grep --config commands.grep.all-files=True --no-all-files mod
456 456 um:0:unmod
457 457
458 458 --diff --all-files makes no sense since --diff is the option to grep history
459 459
460 460 $ hg grep --diff --all-files um
461 461 abort: --diff and --all-files are mutually exclusive
462 462 [255]
463 463
464 464 but --diff should precede the commands.grep.all-files option
465 465
466 466 $ hg grep --config commands.grep.all-files=True --diff mod
467 467 um:0:+:unmod
468 468
469 469 $ cd ..
470 470
471 471 Fix_Wdir(): test that passing wdir() t -r flag does greps on the
472 472 files modified in the working directory
473 473
474 474 $ cd a
475 475 $ echo "abracadara" >> a
476 476 $ hg add a
477 477 $ hg grep -r "wdir()" "abra"
478 478 a:2147483647:abracadara
479 479
480 480 $ cd ..
481 481
482 482 Change Default of grep by ui.tweakdefaults, that is, the files not in current
483 483 working directory should not be grepp-ed on
484 484
485 485 $ hg init ab
486 486 $ cd ab
487 487 $ cat <<'EOF' >> .hg/hgrc
488 488 > [ui]
489 489 > tweakdefaults = True
490 490 > EOF
491 491 $ echo "some text">>file1
492 492 $ hg add file1
493 493 $ hg commit -m "adds file1"
494 494 $ hg mv file1 file2
495 495
496 496 wdir revision is hidden by default:
497 497
498 498 $ hg grep "some"
499 499 file2:some text
500 500
501 501 but it should be available in template dict:
502 502
503 503 $ hg grep "some" -Tjson
504 504 [
505 505 {
506 506 "date": [0, 0],
507 507 "lineno": 1,
508 508 "node": "ffffffffffffffffffffffffffffffffffffffff",
509 509 "path": "file2",
510 510 "rev": 2147483647,
511 511 "texts": [{"matched": true, "text": "some"}, {"matched": false, "text": " text"}],
512 512 "user": "test"
513 513 }
514 514 ]
515 515
516 516 $ cd ..
517 517
518 518 test -rMULTIREV with --all-files
519 519
520 520 $ cd sng
521 521 $ hg rm um
522 522 $ hg commit -m "deletes um"
523 523 $ hg grep -r "0:2" "unmod" --all-files
524 524 um:0:unmod
525 525 um:1:unmod
526 526 $ hg grep -r "0:2" "unmod" --all-files um
527 527 um:0:unmod
528 528 um:1:unmod
529 529 $ hg grep -r "0:2" "unmod" --all-files "glob:**/um" # Check that patterns also work
530 530 um:0:unmod
531 531 um:1:unmod
532 532 $ cd ..
533 533
General Comments 0
You need to be logged in to leave comments. Login now