comparison mercurial/commands.py @ 29858:33461139c31c

grep: add formatter support Several fields are renamed to be consistent with the annotate command, which doesn't mean the last call for the name unification [1]. Actually, I'd rather rename line_number to linenumber, linenum, lineno or line, but I want to port the grep command to formatter first. [1]: https://www.mercurial-scm.org/wiki/GenericTemplatingPlan#Dictionary I don't have any better name for the list of matched/unmatched texts, so they are just called as "texts".
author Yuya Nishihara <yuya@tcha.org>
date Thu, 18 Aug 2016 15:13:56 +0900
parents 0418cdf67efb
children 307b20e5e505
comparison
equal deleted inserted replaced
29857:0418cdf67efb 29858:33461139c31c
4281 ('n', 'line-number', None, _('print matching line numbers')), 4281 ('n', 'line-number', None, _('print matching line numbers')),
4282 ('r', 'rev', [], 4282 ('r', 'rev', [],
4283 _('only search files changed within revision range'), _('REV')), 4283 _('only search files changed within revision range'), _('REV')),
4284 ('u', 'user', None, _('list the author (long with -v)')), 4284 ('u', 'user', None, _('list the author (long with -v)')),
4285 ('d', 'date', None, _('list the date (short with -q)')), 4285 ('d', 'date', None, _('list the date (short with -q)')),
4286 ] + walkopts, 4286 ] + formatteropts + walkopts,
4287 _('[OPTION]... PATTERN [FILE]...'), 4287 _('[OPTION]... PATTERN [FILE]...'),
4288 inferrepo=True) 4288 inferrepo=True)
4289 def grep(ui, repo, pattern, *pats, **opts): 4289 def grep(ui, repo, pattern, *pats, **opts):
4290 """search for a pattern in specified files and revisions 4290 """search for a pattern in specified files and revisions
4291 4291
4378 for i in xrange(alo, ahi): 4378 for i in xrange(alo, ahi):
4379 yield ('-', a[i]) 4379 yield ('-', a[i])
4380 for i in xrange(blo, bhi): 4380 for i in xrange(blo, bhi):
4381 yield ('+', b[i]) 4381 yield ('+', b[i])
4382 4382
4383 def display(fn, ctx, pstates, states): 4383 def display(fm, fn, ctx, pstates, states):
4384 rev = ctx.rev() 4384 rev = ctx.rev()
4385 if fm:
4386 formatuser = str
4387 else:
4388 formatuser = ui.shortuser
4385 if ui.quiet: 4389 if ui.quiet:
4386 datefunc = util.shortdate 4390 datefmt = '%Y-%m-%d'
4387 else: 4391 else:
4388 datefunc = util.datestr 4392 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
4389 found = False 4393 found = False
4390 @util.cachefunc 4394 @util.cachefunc
4391 def binary(): 4395 def binary():
4392 flog = getfile(fn) 4396 flog = getfile(fn)
4393 return util.binary(flog.read(ctx.filenode(fn))) 4397 return util.binary(flog.read(ctx.filenode(fn)))
4394 4398
4399 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
4395 if opts.get('all'): 4400 if opts.get('all'):
4396 iter = difflinestates(pstates, states) 4401 iter = difflinestates(pstates, states)
4397 else: 4402 else:
4398 iter = [('', l) for l in states] 4403 iter = [('', l) for l in states]
4399 for change, l in iter: 4404 for change, l in iter:
4405 fm.startitem()
4406 fm.data(node=fm.hexfunc(ctx.node()))
4400 cols = [ 4407 cols = [
4401 ('filename', fn, True), 4408 ('filename', fn, True),
4402 ('rev', str(rev), True), 4409 ('rev', rev, True),
4403 ('linenumber', str(l.linenum), opts.get('line_number')), 4410 ('linenumber', l.linenum, opts.get('line_number')),
4404 ] 4411 ]
4405 if opts.get('all'): 4412 if opts.get('all'):
4406 cols.append(('change', change, True)) 4413 cols.append(('change', change, True))
4407 cols.extend([ 4414 cols.extend([
4408 ('user', ui.shortuser(ctx.user()), opts.get('user')), 4415 ('user', formatuser(ctx.user()), opts.get('user')),
4409 ('date', datefunc(ctx.date()), opts.get('date')), 4416 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
4410 ]) 4417 ])
4411 lastcol = next(name for name, data, cond in reversed(cols) if cond) 4418 lastcol = next(name for name, data, cond in reversed(cols) if cond)
4412 for name, data, cond in cols: 4419 for name, data, cond in cols:
4413 if cond: 4420 field = fieldnamemap.get(name, name)
4414 ui.write(data, label='grep.%s' % name) 4421 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
4415 if cond and name != lastcol: 4422 if cond and name != lastcol:
4416 ui.write(sep, label='grep.sep') 4423 fm.plain(sep, label='grep.sep')
4417 if not opts.get('files_with_matches'): 4424 if not opts.get('files_with_matches'):
4418 ui.write(sep, label='grep.sep') 4425 fm.plain(sep, label='grep.sep')
4419 if not opts.get('text') and binary(): 4426 if not opts.get('text') and binary():
4420 ui.write(_(" Binary file matches")) 4427 fm.plain(_(" Binary file matches"))
4421 else: 4428 else:
4422 displaymatches(l) 4429 displaymatches(fm.nested('texts'), l)
4423 ui.write(eol) 4430 fm.plain(eol)
4424 found = True 4431 found = True
4425 if opts.get('files_with_matches'): 4432 if opts.get('files_with_matches'):
4426 break 4433 break
4427 return found 4434 return found
4428 4435
4429 def displaymatches(l): 4436 def displaymatches(fm, l):
4430 p = 0 4437 p = 0
4431 for s, e in l.findpos(): 4438 for s, e in l.findpos():
4432 ui.write(l.line[p:s]) 4439 if p < s:
4433 ui.write(l.line[s:e], label='grep.match') 4440 fm.startitem()
4441 fm.write('text', '%s', l.line[p:s])
4442 fm.data(matched=False)
4443 fm.startitem()
4444 fm.write('text', '%s', l.line[s:e], label='grep.match')
4445 fm.data(matched=True)
4434 p = e 4446 p = e
4435 ui.write(l.line[p:]) 4447 if p < len(l.line):
4448 fm.startitem()
4449 fm.write('text', '%s', l.line[p:])
4450 fm.data(matched=False)
4451 fm.end()
4436 4452
4437 skip = {} 4453 skip = {}
4438 revfiles = {} 4454 revfiles = {}
4439 matchfn = scmutil.match(repo[None], pats, opts) 4455 matchfn = scmutil.match(repo[None], pats, opts)
4440 found = False 4456 found = False
4473 fnode = pctx.filenode(pfn) 4489 fnode = pctx.filenode(pfn)
4474 grepbody(pfn, parent, flog.read(fnode)) 4490 grepbody(pfn, parent, flog.read(fnode))
4475 except error.LookupError: 4491 except error.LookupError:
4476 pass 4492 pass
4477 4493
4494 fm = ui.formatter('grep', opts)
4478 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep): 4495 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4479 rev = ctx.rev() 4496 rev = ctx.rev()
4480 parent = ctx.p1().rev() 4497 parent = ctx.p1().rev()
4481 for fn in sorted(revfiles.get(rev, [])): 4498 for fn in sorted(revfiles.get(rev, [])):
4482 states = matches[rev][fn] 4499 states = matches[rev][fn]
4485 if copy: 4502 if copy:
4486 skip[copy] = True 4503 skip[copy] = True
4487 continue 4504 continue
4488 pstates = matches.get(parent, {}).get(copy or fn, []) 4505 pstates = matches.get(parent, {}).get(copy or fn, [])
4489 if pstates or states: 4506 if pstates or states:
4490 r = display(fn, ctx, pstates, states) 4507 r = display(fm, fn, ctx, pstates, states)
4491 found = found or r 4508 found = found or r
4492 if r and not opts.get('all'): 4509 if r and not opts.get('all'):
4493 skip[fn] = True 4510 skip[fn] = True
4494 if copy: 4511 if copy:
4495 skip[copy] = True 4512 skip[copy] = True
4496 del matches[rev] 4513 del matches[rev]
4497 del revfiles[rev] 4514 del revfiles[rev]
4515 fm.end()
4498 4516
4499 return not found 4517 return not found
4500 4518
4501 @command('heads', 4519 @command('heads',
4502 [('r', 'rev', '', 4520 [('r', 'rev', '',