##// END OF EJS Templates
revsets: let p1() and p2() return parents of working dir...
Kevin Bullock -
r12928:a5f7f1e9 default
parent child Browse files
Show More
@@ -0,0 +1,42 b''
1 $ HGENCODING=utf-8
2 $ export HGENCODING
3
4 $ try() {
5 > hg debugrevspec --debug $@
6 > }
7
8 $ log() {
9 > hg log --template '{rev}\n' -r "$1"
10 > }
11
12 $ hg init repo
13 $ cd repo
14
15 $ try 'p1()'
16 ('func', ('symbol', 'p1'), None)
17 -1
18 $ try 'p2()'
19 ('func', ('symbol', 'p2'), None)
20
21 null revision
22 $ log 'p1()'
23 $ log 'p2()'
24
25 working dir with a single parent
26 $ echo a > a
27 $ hg ci -Aqm0
28 $ log 'p1()'
29 0
30 $ log 'p2()'
31
32 merge in progress
33 $ echo b > b
34 $ hg ci -Aqm1
35 $ hg up -q 0
36 $ echo c > c
37 $ hg ci -Aqm2
38 $ hg merge -q
39 $ log 'p1()'
40 2
41 $ log 'p2()'
42 1
@@ -1,797 +1,807 b''
1 # revset.py - revision set queries for mercurial
1 # revset.py - revision set queries for mercurial
2 #
2 #
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import re
8 import re
9 import parser, util, error, discovery
9 import parser, util, error, discovery
10 import match as matchmod
10 import match as matchmod
11 from i18n import _, gettext
11 from i18n import _, gettext
12
12
13 elements = {
13 elements = {
14 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
14 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
15 "-": (5, ("negate", 19), ("minus", 5)),
15 "-": (5, ("negate", 19), ("minus", 5)),
16 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
16 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
17 ("dagrangepost", 17)),
17 ("dagrangepost", 17)),
18 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
18 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
19 ("dagrangepost", 17)),
19 ("dagrangepost", 17)),
20 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
20 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
21 "not": (10, ("not", 10)),
21 "not": (10, ("not", 10)),
22 "!": (10, ("not", 10)),
22 "!": (10, ("not", 10)),
23 "and": (5, None, ("and", 5)),
23 "and": (5, None, ("and", 5)),
24 "&": (5, None, ("and", 5)),
24 "&": (5, None, ("and", 5)),
25 "or": (4, None, ("or", 4)),
25 "or": (4, None, ("or", 4)),
26 "|": (4, None, ("or", 4)),
26 "|": (4, None, ("or", 4)),
27 "+": (4, None, ("or", 4)),
27 "+": (4, None, ("or", 4)),
28 ",": (2, None, ("list", 2)),
28 ",": (2, None, ("list", 2)),
29 ")": (0, None, None),
29 ")": (0, None, None),
30 "symbol": (0, ("symbol",), None),
30 "symbol": (0, ("symbol",), None),
31 "string": (0, ("string",), None),
31 "string": (0, ("string",), None),
32 "end": (0, None, None),
32 "end": (0, None, None),
33 }
33 }
34
34
35 keywords = set(['and', 'or', 'not'])
35 keywords = set(['and', 'or', 'not'])
36
36
37 def tokenize(program):
37 def tokenize(program):
38 pos, l = 0, len(program)
38 pos, l = 0, len(program)
39 while pos < l:
39 while pos < l:
40 c = program[pos]
40 c = program[pos]
41 if c.isspace(): # skip inter-token whitespace
41 if c.isspace(): # skip inter-token whitespace
42 pass
42 pass
43 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
43 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
44 yield ('::', None, pos)
44 yield ('::', None, pos)
45 pos += 1 # skip ahead
45 pos += 1 # skip ahead
46 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
46 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
47 yield ('..', None, pos)
47 yield ('..', None, pos)
48 pos += 1 # skip ahead
48 pos += 1 # skip ahead
49 elif c in "():,-|&+!": # handle simple operators
49 elif c in "():,-|&+!": # handle simple operators
50 yield (c, None, pos)
50 yield (c, None, pos)
51 elif (c in '"\'' or c == 'r' and
51 elif (c in '"\'' or c == 'r' and
52 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
52 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
53 if c == 'r':
53 if c == 'r':
54 pos += 1
54 pos += 1
55 c = program[pos]
55 c = program[pos]
56 decode = lambda x: x
56 decode = lambda x: x
57 else:
57 else:
58 decode = lambda x: x.decode('string-escape')
58 decode = lambda x: x.decode('string-escape')
59 pos += 1
59 pos += 1
60 s = pos
60 s = pos
61 while pos < l: # find closing quote
61 while pos < l: # find closing quote
62 d = program[pos]
62 d = program[pos]
63 if d == '\\': # skip over escaped characters
63 if d == '\\': # skip over escaped characters
64 pos += 2
64 pos += 2
65 continue
65 continue
66 if d == c:
66 if d == c:
67 yield ('string', decode(program[s:pos]), s)
67 yield ('string', decode(program[s:pos]), s)
68 break
68 break
69 pos += 1
69 pos += 1
70 else:
70 else:
71 raise error.ParseError(_("unterminated string"), s)
71 raise error.ParseError(_("unterminated string"), s)
72 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
72 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
73 s = pos
73 s = pos
74 pos += 1
74 pos += 1
75 while pos < l: # find end of symbol
75 while pos < l: # find end of symbol
76 d = program[pos]
76 d = program[pos]
77 if not (d.isalnum() or d in "._" or ord(d) > 127):
77 if not (d.isalnum() or d in "._" or ord(d) > 127):
78 break
78 break
79 if d == '.' and program[pos - 1] == '.': # special case for ..
79 if d == '.' and program[pos - 1] == '.': # special case for ..
80 pos -= 1
80 pos -= 1
81 break
81 break
82 pos += 1
82 pos += 1
83 sym = program[s:pos]
83 sym = program[s:pos]
84 if sym in keywords: # operator keywords
84 if sym in keywords: # operator keywords
85 yield (sym, None, s)
85 yield (sym, None, s)
86 else:
86 else:
87 yield ('symbol', sym, s)
87 yield ('symbol', sym, s)
88 pos -= 1
88 pos -= 1
89 else:
89 else:
90 raise error.ParseError(_("syntax error"), pos)
90 raise error.ParseError(_("syntax error"), pos)
91 pos += 1
91 pos += 1
92 yield ('end', None, pos)
92 yield ('end', None, pos)
93
93
94 # helpers
94 # helpers
95
95
96 def getstring(x, err):
96 def getstring(x, err):
97 if x and (x[0] == 'string' or x[0] == 'symbol'):
97 if x and (x[0] == 'string' or x[0] == 'symbol'):
98 return x[1]
98 return x[1]
99 raise error.ParseError(err)
99 raise error.ParseError(err)
100
100
101 def getlist(x):
101 def getlist(x):
102 if not x:
102 if not x:
103 return []
103 return []
104 if x[0] == 'list':
104 if x[0] == 'list':
105 return getlist(x[1]) + [x[2]]
105 return getlist(x[1]) + [x[2]]
106 return [x]
106 return [x]
107
107
108 def getargs(x, min, max, err):
108 def getargs(x, min, max, err):
109 l = getlist(x)
109 l = getlist(x)
110 if len(l) < min or len(l) > max:
110 if len(l) < min or len(l) > max:
111 raise error.ParseError(err)
111 raise error.ParseError(err)
112 return l
112 return l
113
113
114 def getset(repo, subset, x):
114 def getset(repo, subset, x):
115 if not x:
115 if not x:
116 raise error.ParseError(_("missing argument"))
116 raise error.ParseError(_("missing argument"))
117 return methods[x[0]](repo, subset, *x[1:])
117 return methods[x[0]](repo, subset, *x[1:])
118
118
119 # operator methods
119 # operator methods
120
120
121 def stringset(repo, subset, x):
121 def stringset(repo, subset, x):
122 x = repo[x].rev()
122 x = repo[x].rev()
123 if x == -1 and len(subset) == len(repo):
123 if x == -1 and len(subset) == len(repo):
124 return [-1]
124 return [-1]
125 if x in subset:
125 if x in subset:
126 return [x]
126 return [x]
127 return []
127 return []
128
128
129 def symbolset(repo, subset, x):
129 def symbolset(repo, subset, x):
130 if x in symbols:
130 if x in symbols:
131 raise error.ParseError(_("can't use %s here") % x)
131 raise error.ParseError(_("can't use %s here") % x)
132 return stringset(repo, subset, x)
132 return stringset(repo, subset, x)
133
133
134 def rangeset(repo, subset, x, y):
134 def rangeset(repo, subset, x, y):
135 m = getset(repo, subset, x)
135 m = getset(repo, subset, x)
136 if not m:
136 if not m:
137 m = getset(repo, range(len(repo)), x)
137 m = getset(repo, range(len(repo)), x)
138
138
139 n = getset(repo, subset, y)
139 n = getset(repo, subset, y)
140 if not n:
140 if not n:
141 n = getset(repo, range(len(repo)), y)
141 n = getset(repo, range(len(repo)), y)
142
142
143 if not m or not n:
143 if not m or not n:
144 return []
144 return []
145 m, n = m[0], n[-1]
145 m, n = m[0], n[-1]
146
146
147 if m < n:
147 if m < n:
148 r = range(m, n + 1)
148 r = range(m, n + 1)
149 else:
149 else:
150 r = range(m, n - 1, -1)
150 r = range(m, n - 1, -1)
151 s = set(subset)
151 s = set(subset)
152 return [x for x in r if x in s]
152 return [x for x in r if x in s]
153
153
154 def andset(repo, subset, x, y):
154 def andset(repo, subset, x, y):
155 return getset(repo, getset(repo, subset, x), y)
155 return getset(repo, getset(repo, subset, x), y)
156
156
157 def orset(repo, subset, x, y):
157 def orset(repo, subset, x, y):
158 s = set(getset(repo, subset, x))
158 s = set(getset(repo, subset, x))
159 s |= set(getset(repo, [r for r in subset if r not in s], y))
159 s |= set(getset(repo, [r for r in subset if r not in s], y))
160 return [r for r in subset if r in s]
160 return [r for r in subset if r in s]
161
161
162 def notset(repo, subset, x):
162 def notset(repo, subset, x):
163 s = set(getset(repo, subset, x))
163 s = set(getset(repo, subset, x))
164 return [r for r in subset if r not in s]
164 return [r for r in subset if r not in s]
165
165
166 def listset(repo, subset, a, b):
166 def listset(repo, subset, a, b):
167 raise error.ParseError(_("can't use a list in this context"))
167 raise error.ParseError(_("can't use a list in this context"))
168
168
169 def func(repo, subset, a, b):
169 def func(repo, subset, a, b):
170 if a[0] == 'symbol' and a[1] in symbols:
170 if a[0] == 'symbol' and a[1] in symbols:
171 return symbols[a[1]](repo, subset, b)
171 return symbols[a[1]](repo, subset, b)
172 raise error.ParseError(_("not a function: %s") % a[1])
172 raise error.ParseError(_("not a function: %s") % a[1])
173
173
174 # functions
174 # functions
175
175
176 def node(repo, subset, x):
176 def node(repo, subset, x):
177 """``id(string)``
177 """``id(string)``
178 Revision non-ambiguously specified by the given hex string prefix.
178 Revision non-ambiguously specified by the given hex string prefix.
179 """
179 """
180 # i18n: "id" is a keyword
180 # i18n: "id" is a keyword
181 l = getargs(x, 1, 1, _("id requires one argument"))
181 l = getargs(x, 1, 1, _("id requires one argument"))
182 # i18n: "id" is a keyword
182 # i18n: "id" is a keyword
183 n = getstring(l[0], _("id requires a string"))
183 n = getstring(l[0], _("id requires a string"))
184 if len(n) == 40:
184 if len(n) == 40:
185 rn = repo[n].rev()
185 rn = repo[n].rev()
186 else:
186 else:
187 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
187 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
188 return [r for r in subset if r == rn]
188 return [r for r in subset if r == rn]
189
189
190 def rev(repo, subset, x):
190 def rev(repo, subset, x):
191 """``rev(number)``
191 """``rev(number)``
192 Revision with the given numeric identifier.
192 Revision with the given numeric identifier.
193 """
193 """
194 # i18n: "rev" is a keyword
194 # i18n: "rev" is a keyword
195 l = getargs(x, 1, 1, _("rev requires one argument"))
195 l = getargs(x, 1, 1, _("rev requires one argument"))
196 try:
196 try:
197 # i18n: "rev" is a keyword
197 # i18n: "rev" is a keyword
198 l = int(getstring(l[0], _("rev requires a number")))
198 l = int(getstring(l[0], _("rev requires a number")))
199 except ValueError:
199 except ValueError:
200 # i18n: "rev" is a keyword
200 # i18n: "rev" is a keyword
201 raise error.ParseError(_("rev expects a number"))
201 raise error.ParseError(_("rev expects a number"))
202 return [r for r in subset if r == l]
202 return [r for r in subset if r == l]
203
203
204 def p1(repo, subset, x):
204 def p1(repo, subset, x):
205 """``p1(set)``
205 """``p1([set])``
206 First parent of changesets in set.
206 First parent of changesets in set, or the working directory.
207 """
207 """
208 if x is None:
209 return [repo[x].parents()[0].rev()]
210
208 ps = set()
211 ps = set()
209 cl = repo.changelog
212 cl = repo.changelog
210 for r in getset(repo, range(len(repo)), x):
213 for r in getset(repo, range(len(repo)), x):
211 ps.add(cl.parentrevs(r)[0])
214 ps.add(cl.parentrevs(r)[0])
212 return [r for r in subset if r in ps]
215 return [r for r in subset if r in ps]
213
216
214 def p2(repo, subset, x):
217 def p2(repo, subset, x):
215 """``p2(set)``
218 """``p2([set])``
216 Second parent of changesets in set.
219 Second parent of changesets in set, or the working directory.
217 """
220 """
221 if x is None:
222 ps = repo[x].parents()
223 try:
224 return [ps[1].rev()]
225 except IndexError:
226 return []
227
218 ps = set()
228 ps = set()
219 cl = repo.changelog
229 cl = repo.changelog
220 for r in getset(repo, range(len(repo)), x):
230 for r in getset(repo, range(len(repo)), x):
221 ps.add(cl.parentrevs(r)[1])
231 ps.add(cl.parentrevs(r)[1])
222 return [r for r in subset if r in ps]
232 return [r for r in subset if r in ps]
223
233
224 def parents(repo, subset, x):
234 def parents(repo, subset, x):
225 """``parents(set)``
235 """``parents(set)``
226 The set of all parents for all changesets in set.
236 The set of all parents for all changesets in set.
227 """
237 """
228 ps = set()
238 ps = set()
229 cl = repo.changelog
239 cl = repo.changelog
230 for r in getset(repo, range(len(repo)), x):
240 for r in getset(repo, range(len(repo)), x):
231 ps.update(cl.parentrevs(r))
241 ps.update(cl.parentrevs(r))
232 return [r for r in subset if r in ps]
242 return [r for r in subset if r in ps]
233
243
234 def maxrev(repo, subset, x):
244 def maxrev(repo, subset, x):
235 """``max(set)``
245 """``max(set)``
236 Changeset with highest revision number in set.
246 Changeset with highest revision number in set.
237 """
247 """
238 s = getset(repo, subset, x)
248 s = getset(repo, subset, x)
239 if s:
249 if s:
240 m = max(s)
250 m = max(s)
241 if m in subset:
251 if m in subset:
242 return [m]
252 return [m]
243 return []
253 return []
244
254
245 def minrev(repo, subset, x):
255 def minrev(repo, subset, x):
246 """``min(set)``
256 """``min(set)``
247 Changeset with lowest revision number in set.
257 Changeset with lowest revision number in set.
248 """
258 """
249 s = getset(repo, subset, x)
259 s = getset(repo, subset, x)
250 if s:
260 if s:
251 m = min(s)
261 m = min(s)
252 if m in subset:
262 if m in subset:
253 return [m]
263 return [m]
254 return []
264 return []
255
265
256 def limit(repo, subset, x):
266 def limit(repo, subset, x):
257 """``limit(set, n)``
267 """``limit(set, n)``
258 First n members of set.
268 First n members of set.
259 """
269 """
260 # i18n: "limit" is a keyword
270 # i18n: "limit" is a keyword
261 l = getargs(x, 2, 2, _("limit requires two arguments"))
271 l = getargs(x, 2, 2, _("limit requires two arguments"))
262 try:
272 try:
263 # i18n: "limit" is a keyword
273 # i18n: "limit" is a keyword
264 lim = int(getstring(l[1], _("limit requires a number")))
274 lim = int(getstring(l[1], _("limit requires a number")))
265 except ValueError:
275 except ValueError:
266 # i18n: "limit" is a keyword
276 # i18n: "limit" is a keyword
267 raise error.ParseError(_("limit expects a number"))
277 raise error.ParseError(_("limit expects a number"))
268 return getset(repo, subset, l[0])[:lim]
278 return getset(repo, subset, l[0])[:lim]
269
279
270 def children(repo, subset, x):
280 def children(repo, subset, x):
271 """``children(set)``
281 """``children(set)``
272 Child changesets of changesets in set.
282 Child changesets of changesets in set.
273 """
283 """
274 cs = set()
284 cs = set()
275 cl = repo.changelog
285 cl = repo.changelog
276 s = set(getset(repo, range(len(repo)), x))
286 s = set(getset(repo, range(len(repo)), x))
277 for r in xrange(0, len(repo)):
287 for r in xrange(0, len(repo)):
278 for p in cl.parentrevs(r):
288 for p in cl.parentrevs(r):
279 if p in s:
289 if p in s:
280 cs.add(r)
290 cs.add(r)
281 return [r for r in subset if r in cs]
291 return [r for r in subset if r in cs]
282
292
283 def branch(repo, subset, x):
293 def branch(repo, subset, x):
284 """``branch(set)``
294 """``branch(set)``
285 All changesets belonging to the branches of changesets in set.
295 All changesets belonging to the branches of changesets in set.
286 """
296 """
287 s = getset(repo, range(len(repo)), x)
297 s = getset(repo, range(len(repo)), x)
288 b = set()
298 b = set()
289 for r in s:
299 for r in s:
290 b.add(repo[r].branch())
300 b.add(repo[r].branch())
291 s = set(s)
301 s = set(s)
292 return [r for r in subset if r in s or repo[r].branch() in b]
302 return [r for r in subset if r in s or repo[r].branch() in b]
293
303
294 def ancestor(repo, subset, x):
304 def ancestor(repo, subset, x):
295 """``ancestor(single, single)``
305 """``ancestor(single, single)``
296 Greatest common ancestor of the two changesets.
306 Greatest common ancestor of the two changesets.
297 """
307 """
298 # i18n: "ancestor" is a keyword
308 # i18n: "ancestor" is a keyword
299 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
309 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
300 r = range(len(repo))
310 r = range(len(repo))
301 a = getset(repo, r, l[0])
311 a = getset(repo, r, l[0])
302 b = getset(repo, r, l[1])
312 b = getset(repo, r, l[1])
303 if len(a) != 1 or len(b) != 1:
313 if len(a) != 1 or len(b) != 1:
304 # i18n: "ancestor" is a keyword
314 # i18n: "ancestor" is a keyword
305 raise error.ParseError(_("ancestor arguments must be single revisions"))
315 raise error.ParseError(_("ancestor arguments must be single revisions"))
306 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
316 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
307
317
308 return [r for r in an if r in subset]
318 return [r for r in an if r in subset]
309
319
310 def ancestors(repo, subset, x):
320 def ancestors(repo, subset, x):
311 """``ancestors(set)``
321 """``ancestors(set)``
312 Changesets that are ancestors of a changeset in set.
322 Changesets that are ancestors of a changeset in set.
313 """
323 """
314 args = getset(repo, range(len(repo)), x)
324 args = getset(repo, range(len(repo)), x)
315 if not args:
325 if not args:
316 return []
326 return []
317 s = set(repo.changelog.ancestors(*args)) | set(args)
327 s = set(repo.changelog.ancestors(*args)) | set(args)
318 return [r for r in subset if r in s]
328 return [r for r in subset if r in s]
319
329
320 def descendants(repo, subset, x):
330 def descendants(repo, subset, x):
321 """``descendants(set)``
331 """``descendants(set)``
322 Changesets which are descendants of changesets in set.
332 Changesets which are descendants of changesets in set.
323 """
333 """
324 args = getset(repo, range(len(repo)), x)
334 args = getset(repo, range(len(repo)), x)
325 if not args:
335 if not args:
326 return []
336 return []
327 s = set(repo.changelog.descendants(*args)) | set(args)
337 s = set(repo.changelog.descendants(*args)) | set(args)
328 return [r for r in subset if r in s]
338 return [r for r in subset if r in s]
329
339
330 def follow(repo, subset, x):
340 def follow(repo, subset, x):
331 """``follow()``
341 """``follow()``
332 An alias for ``::.`` (ancestors of the working copy's first parent).
342 An alias for ``::.`` (ancestors of the working copy's first parent).
333 """
343 """
334 # i18n: "follow" is a keyword
344 # i18n: "follow" is a keyword
335 getargs(x, 0, 0, _("follow takes no arguments"))
345 getargs(x, 0, 0, _("follow takes no arguments"))
336 p = repo['.'].rev()
346 p = repo['.'].rev()
337 s = set(repo.changelog.ancestors(p)) | set([p])
347 s = set(repo.changelog.ancestors(p)) | set([p])
338 return [r for r in subset if r in s]
348 return [r for r in subset if r in s]
339
349
340 def date(repo, subset, x):
350 def date(repo, subset, x):
341 """``date(interval)``
351 """``date(interval)``
342 Changesets within the interval, see :hg:`help dates`.
352 Changesets within the interval, see :hg:`help dates`.
343 """
353 """
344 # i18n: "date" is a keyword
354 # i18n: "date" is a keyword
345 ds = getstring(x, _("date requires a string"))
355 ds = getstring(x, _("date requires a string"))
346 dm = util.matchdate(ds)
356 dm = util.matchdate(ds)
347 return [r for r in subset if dm(repo[r].date()[0])]
357 return [r for r in subset if dm(repo[r].date()[0])]
348
358
349 def keyword(repo, subset, x):
359 def keyword(repo, subset, x):
350 """``keyword(string)``
360 """``keyword(string)``
351 Search commit message, user name, and names of changed files for
361 Search commit message, user name, and names of changed files for
352 string.
362 string.
353 """
363 """
354 # i18n: "keyword" is a keyword
364 # i18n: "keyword" is a keyword
355 kw = getstring(x, _("keyword requires a string")).lower()
365 kw = getstring(x, _("keyword requires a string")).lower()
356 l = []
366 l = []
357 for r in subset:
367 for r in subset:
358 c = repo[r]
368 c = repo[r]
359 t = " ".join(c.files() + [c.user(), c.description()])
369 t = " ".join(c.files() + [c.user(), c.description()])
360 if kw in t.lower():
370 if kw in t.lower():
361 l.append(r)
371 l.append(r)
362 return l
372 return l
363
373
364 def grep(repo, subset, x):
374 def grep(repo, subset, x):
365 """``grep(regex)``
375 """``grep(regex)``
366 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
376 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
367 to ensure special escape characters are handled correctly.
377 to ensure special escape characters are handled correctly.
368 """
378 """
369 try:
379 try:
370 # i18n: "grep" is a keyword
380 # i18n: "grep" is a keyword
371 gr = re.compile(getstring(x, _("grep requires a string")))
381 gr = re.compile(getstring(x, _("grep requires a string")))
372 except re.error, e:
382 except re.error, e:
373 raise error.ParseError(_('invalid match pattern: %s') % e)
383 raise error.ParseError(_('invalid match pattern: %s') % e)
374 l = []
384 l = []
375 for r in subset:
385 for r in subset:
376 c = repo[r]
386 c = repo[r]
377 for e in c.files() + [c.user(), c.description()]:
387 for e in c.files() + [c.user(), c.description()]:
378 if gr.search(e):
388 if gr.search(e):
379 l.append(r)
389 l.append(r)
380 continue
390 continue
381 return l
391 return l
382
392
383 def author(repo, subset, x):
393 def author(repo, subset, x):
384 """``author(string)``
394 """``author(string)``
385 Alias for ``user(string)``.
395 Alias for ``user(string)``.
386 """
396 """
387 # i18n: "author" is a keyword
397 # i18n: "author" is a keyword
388 n = getstring(x, _("author requires a string")).lower()
398 n = getstring(x, _("author requires a string")).lower()
389 return [r for r in subset if n in repo[r].user().lower()]
399 return [r for r in subset if n in repo[r].user().lower()]
390
400
391 def user(repo, subset, x):
401 def user(repo, subset, x):
392 """``user(string)``
402 """``user(string)``
393 User name is string.
403 User name is string.
394 """
404 """
395 return author(repo, subset, x)
405 return author(repo, subset, x)
396
406
397 def hasfile(repo, subset, x):
407 def hasfile(repo, subset, x):
398 """``file(pattern)``
408 """``file(pattern)``
399 Changesets affecting files matched by pattern.
409 Changesets affecting files matched by pattern.
400 """
410 """
401 # i18n: "file" is a keyword
411 # i18n: "file" is a keyword
402 pat = getstring(x, _("file requires a pattern"))
412 pat = getstring(x, _("file requires a pattern"))
403 m = matchmod.match(repo.root, repo.getcwd(), [pat])
413 m = matchmod.match(repo.root, repo.getcwd(), [pat])
404 s = []
414 s = []
405 for r in subset:
415 for r in subset:
406 for f in repo[r].files():
416 for f in repo[r].files():
407 if m(f):
417 if m(f):
408 s.append(r)
418 s.append(r)
409 continue
419 continue
410 return s
420 return s
411
421
412 def contains(repo, subset, x):
422 def contains(repo, subset, x):
413 """``contains(pattern)``
423 """``contains(pattern)``
414 Revision contains pattern.
424 Revision contains pattern.
415 """
425 """
416 # i18n: "contains" is a keyword
426 # i18n: "contains" is a keyword
417 pat = getstring(x, _("contains requires a pattern"))
427 pat = getstring(x, _("contains requires a pattern"))
418 m = matchmod.match(repo.root, repo.getcwd(), [pat])
428 m = matchmod.match(repo.root, repo.getcwd(), [pat])
419 s = []
429 s = []
420 if m.files() == [pat]:
430 if m.files() == [pat]:
421 for r in subset:
431 for r in subset:
422 if pat in repo[r]:
432 if pat in repo[r]:
423 s.append(r)
433 s.append(r)
424 continue
434 continue
425 else:
435 else:
426 for r in subset:
436 for r in subset:
427 for f in repo[r].manifest():
437 for f in repo[r].manifest():
428 if m(f):
438 if m(f):
429 s.append(r)
439 s.append(r)
430 continue
440 continue
431 return s
441 return s
432
442
433 def checkstatus(repo, subset, pat, field):
443 def checkstatus(repo, subset, pat, field):
434 m = matchmod.match(repo.root, repo.getcwd(), [pat])
444 m = matchmod.match(repo.root, repo.getcwd(), [pat])
435 s = []
445 s = []
436 fast = (m.files() == [pat])
446 fast = (m.files() == [pat])
437 for r in subset:
447 for r in subset:
438 c = repo[r]
448 c = repo[r]
439 if fast:
449 if fast:
440 if pat not in c.files():
450 if pat not in c.files():
441 continue
451 continue
442 else:
452 else:
443 for f in c.files():
453 for f in c.files():
444 if m(f):
454 if m(f):
445 break
455 break
446 else:
456 else:
447 continue
457 continue
448 files = repo.status(c.p1().node(), c.node())[field]
458 files = repo.status(c.p1().node(), c.node())[field]
449 if fast:
459 if fast:
450 if pat in files:
460 if pat in files:
451 s.append(r)
461 s.append(r)
452 continue
462 continue
453 else:
463 else:
454 for f in files:
464 for f in files:
455 if m(f):
465 if m(f):
456 s.append(r)
466 s.append(r)
457 continue
467 continue
458 return s
468 return s
459
469
460 def modifies(repo, subset, x):
470 def modifies(repo, subset, x):
461 """``modifies(pattern)``
471 """``modifies(pattern)``
462 Changesets modifying files matched by pattern.
472 Changesets modifying files matched by pattern.
463 """
473 """
464 # i18n: "modifies" is a keyword
474 # i18n: "modifies" is a keyword
465 pat = getstring(x, _("modifies requires a pattern"))
475 pat = getstring(x, _("modifies requires a pattern"))
466 return checkstatus(repo, subset, pat, 0)
476 return checkstatus(repo, subset, pat, 0)
467
477
468 def adds(repo, subset, x):
478 def adds(repo, subset, x):
469 """``adds(pattern)``
479 """``adds(pattern)``
470 Changesets that add a file matching pattern.
480 Changesets that add a file matching pattern.
471 """
481 """
472 # i18n: "adds" is a keyword
482 # i18n: "adds" is a keyword
473 pat = getstring(x, _("adds requires a pattern"))
483 pat = getstring(x, _("adds requires a pattern"))
474 return checkstatus(repo, subset, pat, 1)
484 return checkstatus(repo, subset, pat, 1)
475
485
476 def removes(repo, subset, x):
486 def removes(repo, subset, x):
477 """``removes(pattern)``
487 """``removes(pattern)``
478 Changesets which remove files matching pattern.
488 Changesets which remove files matching pattern.
479 """
489 """
480 # i18n: "removes" is a keyword
490 # i18n: "removes" is a keyword
481 pat = getstring(x, _("removes requires a pattern"))
491 pat = getstring(x, _("removes requires a pattern"))
482 return checkstatus(repo, subset, pat, 2)
492 return checkstatus(repo, subset, pat, 2)
483
493
484 def merge(repo, subset, x):
494 def merge(repo, subset, x):
485 """``merge()``
495 """``merge()``
486 Changeset is a merge changeset.
496 Changeset is a merge changeset.
487 """
497 """
488 # i18n: "merge" is a keyword
498 # i18n: "merge" is a keyword
489 getargs(x, 0, 0, _("merge takes no arguments"))
499 getargs(x, 0, 0, _("merge takes no arguments"))
490 cl = repo.changelog
500 cl = repo.changelog
491 return [r for r in subset if cl.parentrevs(r)[1] != -1]
501 return [r for r in subset if cl.parentrevs(r)[1] != -1]
492
502
493 def closed(repo, subset, x):
503 def closed(repo, subset, x):
494 """``closed()``
504 """``closed()``
495 Changeset is closed.
505 Changeset is closed.
496 """
506 """
497 # i18n: "closed" is a keyword
507 # i18n: "closed" is a keyword
498 getargs(x, 0, 0, _("closed takes no arguments"))
508 getargs(x, 0, 0, _("closed takes no arguments"))
499 return [r for r in subset if repo[r].extra().get('close')]
509 return [r for r in subset if repo[r].extra().get('close')]
500
510
501 def head(repo, subset, x):
511 def head(repo, subset, x):
502 """``head()``
512 """``head()``
503 Changeset is a named branch head.
513 Changeset is a named branch head.
504 """
514 """
505 # i18n: "head" is a keyword
515 # i18n: "head" is a keyword
506 getargs(x, 0, 0, _("head takes no arguments"))
516 getargs(x, 0, 0, _("head takes no arguments"))
507 hs = set()
517 hs = set()
508 for b, ls in repo.branchmap().iteritems():
518 for b, ls in repo.branchmap().iteritems():
509 hs.update(repo[h].rev() for h in ls)
519 hs.update(repo[h].rev() for h in ls)
510 return [r for r in subset if r in hs]
520 return [r for r in subset if r in hs]
511
521
512 def reverse(repo, subset, x):
522 def reverse(repo, subset, x):
513 """``reverse(set)``
523 """``reverse(set)``
514 Reverse order of set.
524 Reverse order of set.
515 """
525 """
516 l = getset(repo, subset, x)
526 l = getset(repo, subset, x)
517 l.reverse()
527 l.reverse()
518 return l
528 return l
519
529
520 def present(repo, subset, x):
530 def present(repo, subset, x):
521 """``present(set)``
531 """``present(set)``
522 An empty set, if any revision in set isn't found; otherwise,
532 An empty set, if any revision in set isn't found; otherwise,
523 all revisions in set.
533 all revisions in set.
524 """
534 """
525 try:
535 try:
526 return getset(repo, subset, x)
536 return getset(repo, subset, x)
527 except error.RepoLookupError:
537 except error.RepoLookupError:
528 return []
538 return []
529
539
530 def sort(repo, subset, x):
540 def sort(repo, subset, x):
531 """``sort(set[, [-]key...])``
541 """``sort(set[, [-]key...])``
532 Sort set by keys. The default sort order is ascending, specify a key
542 Sort set by keys. The default sort order is ascending, specify a key
533 as ``-key`` to sort in descending order.
543 as ``-key`` to sort in descending order.
534
544
535 The keys can be:
545 The keys can be:
536
546
537 - ``rev`` for the revision number,
547 - ``rev`` for the revision number,
538 - ``branch`` for the branch name,
548 - ``branch`` for the branch name,
539 - ``desc`` for the commit message (description),
549 - ``desc`` for the commit message (description),
540 - ``user`` for user name (``author`` can be used as an alias),
550 - ``user`` for user name (``author`` can be used as an alias),
541 - ``date`` for the commit date
551 - ``date`` for the commit date
542 """
552 """
543 # i18n: "sort" is a keyword
553 # i18n: "sort" is a keyword
544 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
554 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
545 keys = "rev"
555 keys = "rev"
546 if len(l) == 2:
556 if len(l) == 2:
547 keys = getstring(l[1], _("sort spec must be a string"))
557 keys = getstring(l[1], _("sort spec must be a string"))
548
558
549 s = l[0]
559 s = l[0]
550 keys = keys.split()
560 keys = keys.split()
551 l = []
561 l = []
552 def invert(s):
562 def invert(s):
553 return "".join(chr(255 - ord(c)) for c in s)
563 return "".join(chr(255 - ord(c)) for c in s)
554 for r in getset(repo, subset, s):
564 for r in getset(repo, subset, s):
555 c = repo[r]
565 c = repo[r]
556 e = []
566 e = []
557 for k in keys:
567 for k in keys:
558 if k == 'rev':
568 if k == 'rev':
559 e.append(r)
569 e.append(r)
560 elif k == '-rev':
570 elif k == '-rev':
561 e.append(-r)
571 e.append(-r)
562 elif k == 'branch':
572 elif k == 'branch':
563 e.append(c.branch())
573 e.append(c.branch())
564 elif k == '-branch':
574 elif k == '-branch':
565 e.append(invert(c.branch()))
575 e.append(invert(c.branch()))
566 elif k == 'desc':
576 elif k == 'desc':
567 e.append(c.description())
577 e.append(c.description())
568 elif k == '-desc':
578 elif k == '-desc':
569 e.append(invert(c.description()))
579 e.append(invert(c.description()))
570 elif k in 'user author':
580 elif k in 'user author':
571 e.append(c.user())
581 e.append(c.user())
572 elif k in '-user -author':
582 elif k in '-user -author':
573 e.append(invert(c.user()))
583 e.append(invert(c.user()))
574 elif k == 'date':
584 elif k == 'date':
575 e.append(c.date()[0])
585 e.append(c.date()[0])
576 elif k == '-date':
586 elif k == '-date':
577 e.append(-c.date()[0])
587 e.append(-c.date()[0])
578 else:
588 else:
579 raise error.ParseError(_("unknown sort key %r") % k)
589 raise error.ParseError(_("unknown sort key %r") % k)
580 e.append(r)
590 e.append(r)
581 l.append(e)
591 l.append(e)
582 l.sort()
592 l.sort()
583 return [e[-1] for e in l]
593 return [e[-1] for e in l]
584
594
585 def getall(repo, subset, x):
595 def getall(repo, subset, x):
586 """``all()``
596 """``all()``
587 All changesets, the same as ``0:tip``.
597 All changesets, the same as ``0:tip``.
588 """
598 """
589 # i18n: "all" is a keyword
599 # i18n: "all" is a keyword
590 getargs(x, 0, 0, _("all takes no arguments"))
600 getargs(x, 0, 0, _("all takes no arguments"))
591 return subset
601 return subset
592
602
593 def heads(repo, subset, x):
603 def heads(repo, subset, x):
594 """``heads(set)``
604 """``heads(set)``
595 Members of set with no children in set.
605 Members of set with no children in set.
596 """
606 """
597 s = getset(repo, subset, x)
607 s = getset(repo, subset, x)
598 ps = set(parents(repo, subset, x))
608 ps = set(parents(repo, subset, x))
599 return [r for r in s if r not in ps]
609 return [r for r in s if r not in ps]
600
610
601 def roots(repo, subset, x):
611 def roots(repo, subset, x):
602 """``roots(set)``
612 """``roots(set)``
603 Changesets with no parent changeset in set.
613 Changesets with no parent changeset in set.
604 """
614 """
605 s = getset(repo, subset, x)
615 s = getset(repo, subset, x)
606 cs = set(children(repo, subset, x))
616 cs = set(children(repo, subset, x))
607 return [r for r in s if r not in cs]
617 return [r for r in s if r not in cs]
608
618
609 def outgoing(repo, subset, x):
619 def outgoing(repo, subset, x):
610 """``outgoing([path])``
620 """``outgoing([path])``
611 Changesets not found in the specified destination repository, or the
621 Changesets not found in the specified destination repository, or the
612 default push location.
622 default push location.
613 """
623 """
614 import hg # avoid start-up nasties
624 import hg # avoid start-up nasties
615 # i18n: "outgoing" is a keyword
625 # i18n: "outgoing" is a keyword
616 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
626 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
617 # i18n: "outgoing" is a keyword
627 # i18n: "outgoing" is a keyword
618 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
628 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
619 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
629 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
620 dest, branches = hg.parseurl(dest)
630 dest, branches = hg.parseurl(dest)
621 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
631 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
622 if revs:
632 if revs:
623 revs = [repo.lookup(rev) for rev in revs]
633 revs = [repo.lookup(rev) for rev in revs]
624 other = hg.repository(hg.remoteui(repo, {}), dest)
634 other = hg.repository(hg.remoteui(repo, {}), dest)
625 repo.ui.pushbuffer()
635 repo.ui.pushbuffer()
626 o = discovery.findoutgoing(repo, other)
636 o = discovery.findoutgoing(repo, other)
627 repo.ui.popbuffer()
637 repo.ui.popbuffer()
628 cl = repo.changelog
638 cl = repo.changelog
629 o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, revs)[0]])
639 o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, revs)[0]])
630 return [r for r in subset if r in o]
640 return [r for r in subset if r in o]
631
641
632 def tag(repo, subset, x):
642 def tag(repo, subset, x):
633 """``tag(name)``
643 """``tag(name)``
634 The specified tag by name, or all tagged revisions if no name is given.
644 The specified tag by name, or all tagged revisions if no name is given.
635 """
645 """
636 # i18n: "tag" is a keyword
646 # i18n: "tag" is a keyword
637 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
647 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
638 cl = repo.changelog
648 cl = repo.changelog
639 if args:
649 if args:
640 tn = getstring(args[0],
650 tn = getstring(args[0],
641 # i18n: "tag" is a keyword
651 # i18n: "tag" is a keyword
642 _('the argument to tag must be a string'))
652 _('the argument to tag must be a string'))
643 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
653 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
644 else:
654 else:
645 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
655 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
646 return [r for r in subset if r in s]
656 return [r for r in subset if r in s]
647
657
648 def tagged(repo, subset, x):
658 def tagged(repo, subset, x):
649 return tag(repo, subset, x)
659 return tag(repo, subset, x)
650
660
651 symbols = {
661 symbols = {
652 "adds": adds,
662 "adds": adds,
653 "all": getall,
663 "all": getall,
654 "ancestor": ancestor,
664 "ancestor": ancestor,
655 "ancestors": ancestors,
665 "ancestors": ancestors,
656 "author": author,
666 "author": author,
657 "branch": branch,
667 "branch": branch,
658 "children": children,
668 "children": children,
659 "closed": closed,
669 "closed": closed,
660 "contains": contains,
670 "contains": contains,
661 "date": date,
671 "date": date,
662 "descendants": descendants,
672 "descendants": descendants,
663 "file": hasfile,
673 "file": hasfile,
664 "follow": follow,
674 "follow": follow,
665 "grep": grep,
675 "grep": grep,
666 "head": head,
676 "head": head,
667 "heads": heads,
677 "heads": heads,
668 "keyword": keyword,
678 "keyword": keyword,
669 "limit": limit,
679 "limit": limit,
670 "max": maxrev,
680 "max": maxrev,
671 "min": minrev,
681 "min": minrev,
672 "merge": merge,
682 "merge": merge,
673 "modifies": modifies,
683 "modifies": modifies,
674 "id": node,
684 "id": node,
675 "outgoing": outgoing,
685 "outgoing": outgoing,
676 "p1": p1,
686 "p1": p1,
677 "p2": p2,
687 "p2": p2,
678 "parents": parents,
688 "parents": parents,
679 "present": present,
689 "present": present,
680 "removes": removes,
690 "removes": removes,
681 "reverse": reverse,
691 "reverse": reverse,
682 "rev": rev,
692 "rev": rev,
683 "roots": roots,
693 "roots": roots,
684 "sort": sort,
694 "sort": sort,
685 "tag": tag,
695 "tag": tag,
686 "tagged": tagged,
696 "tagged": tagged,
687 "user": user,
697 "user": user,
688 }
698 }
689
699
690 methods = {
700 methods = {
691 "range": rangeset,
701 "range": rangeset,
692 "string": stringset,
702 "string": stringset,
693 "symbol": symbolset,
703 "symbol": symbolset,
694 "and": andset,
704 "and": andset,
695 "or": orset,
705 "or": orset,
696 "not": notset,
706 "not": notset,
697 "list": listset,
707 "list": listset,
698 "func": func,
708 "func": func,
699 }
709 }
700
710
701 def optimize(x, small):
711 def optimize(x, small):
702 if x == None:
712 if x == None:
703 return 0, x
713 return 0, x
704
714
705 smallbonus = 1
715 smallbonus = 1
706 if small:
716 if small:
707 smallbonus = .5
717 smallbonus = .5
708
718
709 op = x[0]
719 op = x[0]
710 if op == 'minus':
720 if op == 'minus':
711 return optimize(('and', x[1], ('not', x[2])), small)
721 return optimize(('and', x[1], ('not', x[2])), small)
712 elif op == 'dagrange':
722 elif op == 'dagrange':
713 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
723 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
714 ('func', ('symbol', 'ancestors'), x[2])), small)
724 ('func', ('symbol', 'ancestors'), x[2])), small)
715 elif op == 'dagrangepre':
725 elif op == 'dagrangepre':
716 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
726 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
717 elif op == 'dagrangepost':
727 elif op == 'dagrangepost':
718 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
728 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
719 elif op == 'rangepre':
729 elif op == 'rangepre':
720 return optimize(('range', ('string', '0'), x[1]), small)
730 return optimize(('range', ('string', '0'), x[1]), small)
721 elif op == 'rangepost':
731 elif op == 'rangepost':
722 return optimize(('range', x[1], ('string', 'tip')), small)
732 return optimize(('range', x[1], ('string', 'tip')), small)
723 elif op == 'negate':
733 elif op == 'negate':
724 return optimize(('string',
734 return optimize(('string',
725 '-' + getstring(x[1], _("can't negate that"))), small)
735 '-' + getstring(x[1], _("can't negate that"))), small)
726 elif op in 'string symbol negate':
736 elif op in 'string symbol negate':
727 return smallbonus, x # single revisions are small
737 return smallbonus, x # single revisions are small
728 elif op == 'and' or op == 'dagrange':
738 elif op == 'and' or op == 'dagrange':
729 wa, ta = optimize(x[1], True)
739 wa, ta = optimize(x[1], True)
730 wb, tb = optimize(x[2], True)
740 wb, tb = optimize(x[2], True)
731 w = min(wa, wb)
741 w = min(wa, wb)
732 if wa > wb:
742 if wa > wb:
733 return w, (op, tb, ta)
743 return w, (op, tb, ta)
734 return w, (op, ta, tb)
744 return w, (op, ta, tb)
735 elif op == 'or':
745 elif op == 'or':
736 wa, ta = optimize(x[1], False)
746 wa, ta = optimize(x[1], False)
737 wb, tb = optimize(x[2], False)
747 wb, tb = optimize(x[2], False)
738 if wb < wa:
748 if wb < wa:
739 wb, wa = wa, wb
749 wb, wa = wa, wb
740 return max(wa, wb), (op, ta, tb)
750 return max(wa, wb), (op, ta, tb)
741 elif op == 'not':
751 elif op == 'not':
742 o = optimize(x[1], not small)
752 o = optimize(x[1], not small)
743 return o[0], (op, o[1])
753 return o[0], (op, o[1])
744 elif op == 'group':
754 elif op == 'group':
745 return optimize(x[1], small)
755 return optimize(x[1], small)
746 elif op in 'range list':
756 elif op in 'range list':
747 wa, ta = optimize(x[1], small)
757 wa, ta = optimize(x[1], small)
748 wb, tb = optimize(x[2], small)
758 wb, tb = optimize(x[2], small)
749 return wa + wb, (op, ta, tb)
759 return wa + wb, (op, ta, tb)
750 elif op == 'func':
760 elif op == 'func':
751 f = getstring(x[1], _("not a symbol"))
761 f = getstring(x[1], _("not a symbol"))
752 wa, ta = optimize(x[2], small)
762 wa, ta = optimize(x[2], small)
753 if f in "grep date user author keyword branch file outgoing":
763 if f in "grep date user author keyword branch file outgoing":
754 w = 10 # slow
764 w = 10 # slow
755 elif f in "modifies adds removes":
765 elif f in "modifies adds removes":
756 w = 30 # slower
766 w = 30 # slower
757 elif f == "contains":
767 elif f == "contains":
758 w = 100 # very slow
768 w = 100 # very slow
759 elif f == "ancestor":
769 elif f == "ancestor":
760 w = 1 * smallbonus
770 w = 1 * smallbonus
761 elif f == "reverse limit":
771 elif f == "reverse limit":
762 w = 0
772 w = 0
763 elif f in "sort":
773 elif f in "sort":
764 w = 10 # assume most sorts look at changelog
774 w = 10 # assume most sorts look at changelog
765 else:
775 else:
766 w = 1
776 w = 1
767 return w + wa, (op, x[1], ta)
777 return w + wa, (op, x[1], ta)
768 return 1, x
778 return 1, x
769
779
770 parse = parser.parser(tokenize, elements).parse
780 parse = parser.parser(tokenize, elements).parse
771
781
772 def match(spec):
782 def match(spec):
773 if not spec:
783 if not spec:
774 raise error.ParseError(_("empty query"))
784 raise error.ParseError(_("empty query"))
775 tree = parse(spec)
785 tree = parse(spec)
776 weight, tree = optimize(tree, True)
786 weight, tree = optimize(tree, True)
777 def mfunc(repo, subset):
787 def mfunc(repo, subset):
778 return getset(repo, subset, tree)
788 return getset(repo, subset, tree)
779 return mfunc
789 return mfunc
780
790
781 def makedoc(topic, doc):
791 def makedoc(topic, doc):
782 """Generate and include predicates help in revsets topic."""
792 """Generate and include predicates help in revsets topic."""
783 predicates = []
793 predicates = []
784 for name in sorted(symbols):
794 for name in sorted(symbols):
785 text = symbols[name].__doc__
795 text = symbols[name].__doc__
786 if not text:
796 if not text:
787 continue
797 continue
788 text = gettext(text.rstrip())
798 text = gettext(text.rstrip())
789 lines = text.splitlines()
799 lines = text.splitlines()
790 lines[1:] = [(' ' + l.strip()) for l in lines[1:]]
800 lines[1:] = [(' ' + l.strip()) for l in lines[1:]]
791 predicates.append('\n'.join(lines))
801 predicates.append('\n'.join(lines))
792 predicates = '\n\n'.join(predicates)
802 predicates = '\n\n'.join(predicates)
793 doc = doc.replace('.. predicatesmarker', predicates)
803 doc = doc.replace('.. predicatesmarker', predicates)
794 return doc
804 return doc
795
805
796 # tell hggettext to extract docstrings from these functions:
806 # tell hggettext to extract docstrings from these functions:
797 i18nfunctions = symbols.values()
807 i18nfunctions = symbols.values()
General Comments 0
You need to be logged in to leave comments. Login now