Mercurial > public > mercurial-scm > hg
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', '', |