Mercurial > public > mercurial-scm > hg-stable
diff mercurial/fileset.py @ 35741:73432eee0ac4
fileset: add kind:pat operator
":" isn't taken as a symbol character but an infix operator so we can write
e.g. "path:'foo bar'" as well as "'path:foo bar'". An invalid pattern kind
is rejected in the former form as we know a kind is specified explicitly.
The binding strength is copied from "x:y" range operator of revset. Perhaps
it can be adjusted later if we want to parse "foo:bar()" as "(foo:bar)()",
not "foo:(bar())". We can also add "kind:" postfix operator if we want.
One possible confusion is that the scope of the leading "set:" vs "kind:pat"
operator. The former is consumed by a matcher so applies to the whole fileset
expression:
$ hg files 'set:foo() or kind:bar or baz'
^^^^^^^^^^^^^^^^^^^^^^^^
Whereas the scope of kind:pat operator is narrow:
$ hg files 'set:foo() or kind:bar or baz'
^^^
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sun, 14 Jan 2018 13:29:15 +0900 |
parents | 9eb5c400f488 |
children | 7b2b82f891bf |
line wrap: on
line diff
--- a/mercurial/fileset.py Sun Jan 14 13:33:56 2018 +0900 +++ b/mercurial/fileset.py Sun Jan 14 13:29:15 2018 +0900 @@ -24,6 +24,7 @@ elements = { # token-type: binding-strength, primary, prefix, infix, suffix "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None), + ":": (15, None, None, ("kindpat", 15), None), "-": (5, None, ("negate", 19), ("minus", 5), None), "not": (10, None, ("not", 10), None, None), "!": (10, None, ("not", 10), None, None), @@ -50,7 +51,7 @@ c = program[pos] if c.isspace(): # skip inter-token whitespace pass - elif c in "(),-|&+!": # handle simple operators + elif c in "(),-:|&+!": # handle simple operators yield (c, None, pos) elif (c in '"\'' or c == 'r' and program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings @@ -110,6 +111,18 @@ return x[1] raise error.ParseError(err) +def _getkindpat(x, y, allkinds, err): + kind = getsymbol(x) + pat = getstring(y, err) + if kind not in allkinds: + raise error.ParseError(_("invalid pattern kind: %s") % kind) + return '%s:%s' % (kind, pat) + +def getpattern(x, allkinds, err): + if x and x[0] == 'kindpat': + return _getkindpat(x[1], x[2], allkinds, err) + return getstring(x, err) + def getset(mctx, x): if not x: raise error.ParseError(_("missing argument")) @@ -119,6 +132,10 @@ m = mctx.matcher([x]) return [f for f in mctx.subset if m(f)] +def kindpatset(mctx, x, y): + return stringset(mctx, _getkindpat(x, y, matchmod.allpatternkinds, + _("pattern must be a string"))) + def andset(mctx, x, y): return getset(mctx.narrow(getset(mctx, x)), y) @@ -507,8 +524,9 @@ ctx = mctx.ctx sstate = sorted(ctx.substate) if x: - # i18n: "subrepo" is a keyword - pat = getstring(x, _("subrepo requires a pattern or no arguments")) + pat = getpattern(x, matchmod.allpatternkinds, + # i18n: "subrepo" is a keyword + _("subrepo requires a pattern or no arguments")) fast = not matchmod.patkind(pat) if fast: def m(s): @@ -522,6 +540,7 @@ methods = { 'string': stringset, 'symbol': stringset, + 'kindpat': kindpatset, 'and': andset, 'or': orset, 'minus': minusset,