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