Show More
@@ -174,7 +174,7 b' def revrange(repo, revs):' | |||||
174 | pass |
|
174 | pass | |
175 |
|
175 | |||
176 | # fall through to new-style queries if old-style fails |
|
176 | # fall through to new-style queries if old-style fails | |
177 | m = revset.match(spec) |
|
177 | m = revset.match(repo.ui, spec) | |
178 | for r in m(repo, range(len(repo))): |
|
178 | for r in m(repo, range(len(repo))): | |
179 | if r not in seen: |
|
179 | if r not in seen: | |
180 | l.append(r) |
|
180 | l.append(r) |
@@ -1296,7 +1296,10 b' def debugrevspec(ui, repo, expr):' | |||||
1296 | if ui.verbose: |
|
1296 | if ui.verbose: | |
1297 | tree = revset.parse(expr)[0] |
|
1297 | tree = revset.parse(expr)[0] | |
1298 | ui.note(tree, "\n") |
|
1298 | ui.note(tree, "\n") | |
1299 | func = revset.match(expr) |
|
1299 | newtree = revset.findaliases(ui, tree) | |
|
1300 | if newtree != tree: | |||
|
1301 | ui.note(newtree, "\n") | |||
|
1302 | func = revset.match(ui, expr) | |||
1300 | for c in func(repo, range(len(repo))): |
|
1303 | for c in func(repo, range(len(repo))): | |
1301 | ui.write("%s\n" % c) |
|
1304 | ui.write("%s\n" % c) | |
1302 |
|
1305 |
@@ -61,6 +61,26 b' The following predicates are supported:' | |||||
61 |
|
61 | |||
62 | .. predicatesmarker |
|
62 | .. predicatesmarker | |
63 |
|
63 | |||
|
64 | New predicates (known as "aliases") can be defined, using any combination of | |||
|
65 | existing predicates or other aliases. An alias definition looks like:: | |||
|
66 | ||||
|
67 | <alias> = <definition> | |||
|
68 | ||||
|
69 | in the ``revsetalias`` section of ``.hgrc``. Arguments of the form `$1`, `$2`, | |||
|
70 | etc. are substituted from the alias into the definition. | |||
|
71 | ||||
|
72 | For example, | |||
|
73 | ||||
|
74 | :: | |||
|
75 | ||||
|
76 | [revsetalias] | |||
|
77 | h = heads() | |||
|
78 | d($1) = sort($1, date) | |||
|
79 | rs($1, $2) = reverse(sort($1, $2)) | |||
|
80 | ||||
|
81 | defines three aliases, ``h``, ``d``, and ``rs``. ``rs(0:tip, author)`` is | |||
|
82 | exactly equivalent to ``reverse(sort(0:tip, author))``. | |||
|
83 | ||||
64 | Command line equivalents for :hg:`log`:: |
|
84 | Command line equivalents for :hg:`log`:: | |
65 |
|
85 | |||
66 | -f -> ::. |
|
86 | -f -> ::. |
@@ -889,14 +889,89 b' def optimize(x, small):' | |||||
889 | return w + wa, (op, x[1], ta) |
|
889 | return w + wa, (op, x[1], ta) | |
890 | return 1, x |
|
890 | return 1, x | |
891 |
|
891 | |||
|
892 | class revsetalias(object): | |||
|
893 | funcre = re.compile('^([^(]+)\(([^)]+)\)$') | |||
|
894 | args = () | |||
|
895 | ||||
|
896 | def __init__(self, token, value): | |||
|
897 | '''Aliases like: | |||
|
898 | ||||
|
899 | h = heads(default) | |||
|
900 | b($1) = ancestors($1) - ancestors(default) | |||
|
901 | ''' | |||
|
902 | if isinstance(token, tuple): | |||
|
903 | self.type, self.name = token | |||
|
904 | else: | |||
|
905 | m = self.funcre.search(token) | |||
|
906 | if m: | |||
|
907 | self.type = 'func' | |||
|
908 | self.name = m.group(1) | |||
|
909 | self.args = [x.strip() for x in m.group(2).split(',')] | |||
|
910 | else: | |||
|
911 | self.type = 'symbol' | |||
|
912 | self.name = token | |||
|
913 | ||||
|
914 | if isinstance(value, str): | |||
|
915 | for arg in self.args: | |||
|
916 | value = value.replace(arg, repr(arg)) | |||
|
917 | self.replacement, pos = parse(value) | |||
|
918 | if pos != len(value): | |||
|
919 | raise error.ParseError('invalid token', pos) | |||
|
920 | else: | |||
|
921 | self.replacement = value | |||
|
922 | ||||
|
923 | def match(self, tree): | |||
|
924 | if not tree: | |||
|
925 | return False | |||
|
926 | if tree == (self.type, self.name): | |||
|
927 | return True | |||
|
928 | if tree[0] != self.type: | |||
|
929 | return False | |||
|
930 | if len(tree) > 1 and tree[1] != ('symbol', self.name): | |||
|
931 | return False | |||
|
932 | # 'func' + funcname + args | |||
|
933 | if ((self.args and len(tree) != 3) or | |||
|
934 | (len(self.args) == 1 and tree[2][0] == 'list') or | |||
|
935 | (len(self.args) > 1 and (tree[2][0] != 'list' or | |||
|
936 | len(tree[2]) - 1 != len(self.args)))): | |||
|
937 | raise error.ParseError('invalid amount of arguments', len(tree) - 2) | |||
|
938 | return True | |||
|
939 | ||||
|
940 | def replace(self, tree): | |||
|
941 | if tree == (self.type, self.name): | |||
|
942 | return self.replacement | |||
|
943 | result = self.replacement | |||
|
944 | def getsubtree(i): | |||
|
945 | if tree[2][0] == 'list': | |||
|
946 | return tree[2][i + 1] | |||
|
947 | return tree[i + 2] | |||
|
948 | for i, v in enumerate(self.args): | |||
|
949 | valalias = revsetalias(('string', v), getsubtree(i)) | |||
|
950 | result = valalias.process(result) | |||
|
951 | return result | |||
|
952 | ||||
|
953 | def process(self, tree): | |||
|
954 | if self.match(tree): | |||
|
955 | return self.replace(tree) | |||
|
956 | if isinstance(tree, tuple): | |||
|
957 | return tuple(map(self.process, tree)) | |||
|
958 | return tree | |||
|
959 | ||||
|
960 | def findaliases(ui, tree): | |||
|
961 | for k, v in ui.configitems('revsetalias'): | |||
|
962 | alias = revsetalias(k, v) | |||
|
963 | tree = alias.process(tree) | |||
|
964 | return tree | |||
|
965 | ||||
892 | parse = parser.parser(tokenize, elements).parse |
|
966 | parse = parser.parser(tokenize, elements).parse | |
893 |
|
967 | |||
894 | def match(spec): |
|
968 | def match(ui, spec): | |
895 | if not spec: |
|
969 | if not spec: | |
896 | raise error.ParseError(_("empty query")) |
|
970 | raise error.ParseError(_("empty query")) | |
897 | tree, pos = parse(spec) |
|
971 | tree, pos = parse(spec) | |
898 | if (pos != len(spec)): |
|
972 | if (pos != len(spec)): | |
899 | raise error.ParseError("invalid token", pos) |
|
973 | raise error.ParseError("invalid token", pos) | |
|
974 | tree = findaliases(ui, tree) | |||
900 | weight, tree = optimize(tree, True) |
|
975 | weight, tree = optimize(tree, True) | |
901 | def mfunc(repo, subset): |
|
976 | def mfunc(repo, subset): | |
902 | return getset(repo, subset, tree) |
|
977 | return getset(repo, subset, tree) |
@@ -2,7 +2,7 b'' | |||||
2 | $ export HGENCODING |
|
2 | $ export HGENCODING | |
3 |
|
3 | |||
4 | $ try() { |
|
4 | $ try() { | |
5 |
> hg debugrevspec --debug |
|
5 | > hg debugrevspec --debug "$@" | |
6 | > } |
|
6 | > } | |
7 |
|
7 | |||
8 | $ log() { |
|
8 | $ log() { | |
@@ -411,3 +411,27 b' parentrevspec' | |||||
411 | $ log 'tip^foo' |
|
411 | $ log 'tip^foo' | |
412 | hg: parse error: ^ expects a number 0, 1, or 2 |
|
412 | hg: parse error: ^ expects a number 0, 1, or 2 | |
413 | [255] |
|
413 | [255] | |
|
414 | ||||
|
415 | aliases: | |||
|
416 | ||||
|
417 | $ echo '[revsetalias]' >> .hg/hgrc | |||
|
418 | $ echo 'm = merge()' >> .hg/hgrc | |||
|
419 | $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc | |||
|
420 | $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc | |||
|
421 | ||||
|
422 | $ try m | |||
|
423 | ('symbol', 'm') | |||
|
424 | ('func', ('symbol', 'merge'), None) | |||
|
425 | 6 | |||
|
426 | $ try 'd(2:5)' | |||
|
427 | ('func', ('symbol', 'd'), ('range', ('symbol', '2'), ('symbol', '5'))) | |||
|
428 | ('func', ('symbol', 'reverse'), ('func', ('symbol', 'sort'), ('list', ('range', ('symbol', '2'), ('symbol', '5')), ('symbol', 'date')))) | |||
|
429 | 4 | |||
|
430 | 5 | |||
|
431 | 3 | |||
|
432 | 2 | |||
|
433 | $ try 'rs(2 or 3, date)' | |||
|
434 | ('func', ('symbol', 'rs'), ('list', ('or', ('symbol', '2'), ('symbol', '3')), ('symbol', 'date'))) | |||
|
435 | ('func', ('symbol', 'reverse'), ('func', ('symbol', 'sort'), ('list', ('or', ('symbol', '2'), ('symbol', '3')), ('symbol', 'date')))) | |||
|
436 | 3 | |||
|
437 | 2 |
General Comments 0
You need to be logged in to leave comments.
Login now