comparison mercurial/revset.py @ 45725:99b8b73eb622

revset: add diff(pattern) predicate for "grep --diff" I find this is useful in GUI log viewer since the tool only needs to support "log -rREV" command. This is basic implementation. Windowed search is not implemented since it wouldn't work pretty well with the smartset API. And filename matcher is not supported because the syntax isn't determined. My idea is to add handling of diff(pattern, file(..)) and diff(pattern, follow(..)), which will then be evolved to a full revset+matcher combinator support: x & diff(pattern, y & z) ===== y & z builds (revs(y) & revs(z), matcher(y) & matcher(z)) pair, and narrows the search space of diff() ==================== diff() returns matched (revs, matcher) pair ======================== revs and matcher will be combined respectively by &-operator, and the matcher will optionally be used to filter "hg log -p" output The predicate name "diff()" wouldn't be great, but grep() is already used. Another options I can think of are "grepdiff()" and "containsdiff()". Naming suggestions are welcome.
author Yuya Nishihara <yuya@tcha.org>
date Tue, 08 Sep 2020 18:16:24 +0900
parents b90d7e7f39db
children c00595736595
comparison
equal deleted inserted replaced
45724:ac39a8a214b1 45725:99b8b73eb622
15 dagop, 15 dagop,
16 destutil, 16 destutil,
17 diffutil, 17 diffutil,
18 encoding, 18 encoding,
19 error, 19 error,
20 grep as grepmod,
20 hbisect, 21 hbisect,
21 match as matchmod, 22 match as matchmod,
22 node, 23 node,
23 obsolete as obsmod, 24 obsolete as obsmod,
24 obsutil, 25 obsutil,
991 dests.__contains__, 992 dests.__contains__,
992 condrepr=lambda: b'<destination %r>' % _sortedb(dests), 993 condrepr=lambda: b'<destination %r>' % _sortedb(dests),
993 ) 994 )
994 995
995 996
997 @predicate(b'diff(pattern)', weight=110)
998 def diff(repo, subset, x):
999 """Search revision differences for when the pattern was added or removed.
1000
1001 The pattern may be a substring literal or a regular expression. See
1002 :hg:`help revisions.patterns`.
1003 """
1004 args = getargsdict(x, b'diff', b'pattern')
1005 if b'pattern' not in args:
1006 # i18n: "diff" is a keyword
1007 raise error.ParseError(_(b'diff takes at least 1 argument'))
1008
1009 pattern = getstring(args[b'pattern'], _(b'diff requires a string pattern'))
1010 regexp = stringutil.substringregexp(pattern, re.M)
1011
1012 # TODO: add support for file pattern and --follow. For example,
1013 # diff(pattern[, set]) where set may be file(pattern) or follow(pattern),
1014 # and we'll eventually add a support for narrowing files by revset?
1015 fmatch = matchmod.always()
1016
1017 def makefilematcher(ctx):
1018 return fmatch
1019
1020 # TODO: search in a windowed way
1021 searcher = grepmod.grepsearcher(repo.ui, repo, regexp, diff=True)
1022
1023 def testdiff(rev):
1024 # consume the generator to discard revfiles/matches cache
1025 found = False
1026 for fn, ctx, pstates, states in searcher.searchfiles(
1027 baseset([rev]), makefilematcher
1028 ):
1029 if next(grepmod.difflinestates(pstates, states), None):
1030 found = True
1031 return found
1032
1033 return subset.filter(testdiff, condrepr=(b'<diff %r>', pattern))
1034
1035
996 @predicate(b'contentdivergent()', safe=True) 1036 @predicate(b'contentdivergent()', safe=True)
997 def contentdivergent(repo, subset, x): 1037 def contentdivergent(repo, subset, x):
998 """ 1038 """
999 Final successors of changesets with an alternative set of final 1039 Final successors of changesets with an alternative set of final
1000 successors. (EXPERIMENTAL) 1040 successors. (EXPERIMENTAL)