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