128 return [f for f in xl if f not in yl] |
128 return [f for f in xl if f not in yl] |
129 |
129 |
130 def listset(mctx, a, b): |
130 def listset(mctx, a, b): |
131 raise error.ParseError(_("can't use a list in this context")) |
131 raise error.ParseError(_("can't use a list in this context")) |
132 |
132 |
|
133 # symbols are callable like: |
|
134 # fun(mctx, x) |
|
135 # with: |
|
136 # mctx - current matchctx instance |
|
137 # x - argument in tree form |
|
138 symbols = {} |
|
139 |
|
140 def predicate(decl): |
|
141 """Return a decorator for fileset predicate function |
|
142 |
|
143 'decl' argument is the declaration (including argument list like |
|
144 'adds(pattern)') or the name (for internal use only) of predicate. |
|
145 """ |
|
146 def decorator(func): |
|
147 i = decl.find('(') |
|
148 if i > 0: |
|
149 name = decl[:i] |
|
150 else: |
|
151 name = decl |
|
152 symbols[name] = func |
|
153 if func.__doc__: |
|
154 func.__doc__ = "``%s``\n %s" % (decl, func.__doc__.strip()) |
|
155 return func |
|
156 return decorator |
|
157 |
|
158 @predicate('modified()') |
133 def modified(mctx, x): |
159 def modified(mctx, x): |
134 """``modified()`` |
160 """File that is modified according to :hg:`status`. |
135 File that is modified according to :hg:`status`. |
|
136 """ |
161 """ |
137 # i18n: "modified" is a keyword |
162 # i18n: "modified" is a keyword |
138 getargs(x, 0, 0, _("modified takes no arguments")) |
163 getargs(x, 0, 0, _("modified takes no arguments")) |
139 s = mctx.status().modified |
164 s = mctx.status().modified |
140 return [f for f in mctx.subset if f in s] |
165 return [f for f in mctx.subset if f in s] |
141 |
166 |
|
167 @predicate('added()') |
142 def added(mctx, x): |
168 def added(mctx, x): |
143 """``added()`` |
169 """File that is added according to :hg:`status`. |
144 File that is added according to :hg:`status`. |
|
145 """ |
170 """ |
146 # i18n: "added" is a keyword |
171 # i18n: "added" is a keyword |
147 getargs(x, 0, 0, _("added takes no arguments")) |
172 getargs(x, 0, 0, _("added takes no arguments")) |
148 s = mctx.status().added |
173 s = mctx.status().added |
149 return [f for f in mctx.subset if f in s] |
174 return [f for f in mctx.subset if f in s] |
150 |
175 |
|
176 @predicate('removed()') |
151 def removed(mctx, x): |
177 def removed(mctx, x): |
152 """``removed()`` |
178 """File that is removed according to :hg:`status`. |
153 File that is removed according to :hg:`status`. |
|
154 """ |
179 """ |
155 # i18n: "removed" is a keyword |
180 # i18n: "removed" is a keyword |
156 getargs(x, 0, 0, _("removed takes no arguments")) |
181 getargs(x, 0, 0, _("removed takes no arguments")) |
157 s = mctx.status().removed |
182 s = mctx.status().removed |
158 return [f for f in mctx.subset if f in s] |
183 return [f for f in mctx.subset if f in s] |
159 |
184 |
|
185 @predicate('deleted()') |
160 def deleted(mctx, x): |
186 def deleted(mctx, x): |
161 """``deleted()`` |
187 """Alias for ``missing()``. |
162 Alias for ``missing()``. |
|
163 """ |
188 """ |
164 # i18n: "deleted" is a keyword |
189 # i18n: "deleted" is a keyword |
165 getargs(x, 0, 0, _("deleted takes no arguments")) |
190 getargs(x, 0, 0, _("deleted takes no arguments")) |
166 s = mctx.status().deleted |
191 s = mctx.status().deleted |
167 return [f for f in mctx.subset if f in s] |
192 return [f for f in mctx.subset if f in s] |
168 |
193 |
|
194 @predicate('missing()') |
169 def missing(mctx, x): |
195 def missing(mctx, x): |
170 """``missing()`` |
196 """File that is missing according to :hg:`status`. |
171 File that is missing according to :hg:`status`. |
|
172 """ |
197 """ |
173 # i18n: "missing" is a keyword |
198 # i18n: "missing" is a keyword |
174 getargs(x, 0, 0, _("missing takes no arguments")) |
199 getargs(x, 0, 0, _("missing takes no arguments")) |
175 s = mctx.status().deleted |
200 s = mctx.status().deleted |
176 return [f for f in mctx.subset if f in s] |
201 return [f for f in mctx.subset if f in s] |
177 |
202 |
|
203 @predicate('unknown()') |
178 def unknown(mctx, x): |
204 def unknown(mctx, x): |
179 """``unknown()`` |
205 """File that is unknown according to :hg:`status`. These files will only be |
180 File that is unknown according to :hg:`status`. These files will only be |
|
181 considered if this predicate is used. |
206 considered if this predicate is used. |
182 """ |
207 """ |
183 # i18n: "unknown" is a keyword |
208 # i18n: "unknown" is a keyword |
184 getargs(x, 0, 0, _("unknown takes no arguments")) |
209 getargs(x, 0, 0, _("unknown takes no arguments")) |
185 s = mctx.status().unknown |
210 s = mctx.status().unknown |
186 return [f for f in mctx.subset if f in s] |
211 return [f for f in mctx.subset if f in s] |
187 |
212 |
|
213 @predicate('ignored()') |
188 def ignored(mctx, x): |
214 def ignored(mctx, x): |
189 """``ignored()`` |
215 """File that is ignored according to :hg:`status`. These files will only be |
190 File that is ignored according to :hg:`status`. These files will only be |
|
191 considered if this predicate is used. |
216 considered if this predicate is used. |
192 """ |
217 """ |
193 # i18n: "ignored" is a keyword |
218 # i18n: "ignored" is a keyword |
194 getargs(x, 0, 0, _("ignored takes no arguments")) |
219 getargs(x, 0, 0, _("ignored takes no arguments")) |
195 s = mctx.status().ignored |
220 s = mctx.status().ignored |
196 return [f for f in mctx.subset if f in s] |
221 return [f for f in mctx.subset if f in s] |
197 |
222 |
|
223 @predicate('clean()') |
198 def clean(mctx, x): |
224 def clean(mctx, x): |
199 """``clean()`` |
225 """File that is clean according to :hg:`status`. |
200 File that is clean according to :hg:`status`. |
|
201 """ |
226 """ |
202 # i18n: "clean" is a keyword |
227 # i18n: "clean" is a keyword |
203 getargs(x, 0, 0, _("clean takes no arguments")) |
228 getargs(x, 0, 0, _("clean takes no arguments")) |
204 s = mctx.status().clean |
229 s = mctx.status().clean |
205 return [f for f in mctx.subset if f in s] |
230 return [f for f in mctx.subset if f in s] |
224 l = getlist(x) |
249 l = getlist(x) |
225 if len(l) < min or len(l) > max: |
250 if len(l) < min or len(l) > max: |
226 raise error.ParseError(err) |
251 raise error.ParseError(err) |
227 return l |
252 return l |
228 |
253 |
|
254 @predicate('binary()') |
229 def binary(mctx, x): |
255 def binary(mctx, x): |
230 """``binary()`` |
256 """File that appears to be binary (contains NUL bytes). |
231 File that appears to be binary (contains NUL bytes). |
|
232 """ |
257 """ |
233 # i18n: "binary" is a keyword |
258 # i18n: "binary" is a keyword |
234 getargs(x, 0, 0, _("binary takes no arguments")) |
259 getargs(x, 0, 0, _("binary takes no arguments")) |
235 return [f for f in mctx.existing() if util.binary(mctx.ctx[f].data())] |
260 return [f for f in mctx.existing() if util.binary(mctx.ctx[f].data())] |
236 |
261 |
|
262 @predicate('exec()') |
237 def exec_(mctx, x): |
263 def exec_(mctx, x): |
238 """``exec()`` |
264 """File that is marked as executable. |
239 File that is marked as executable. |
|
240 """ |
265 """ |
241 # i18n: "exec" is a keyword |
266 # i18n: "exec" is a keyword |
242 getargs(x, 0, 0, _("exec takes no arguments")) |
267 getargs(x, 0, 0, _("exec takes no arguments")) |
243 return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'x'] |
268 return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'x'] |
244 |
269 |
|
270 @predicate('symlink()') |
245 def symlink(mctx, x): |
271 def symlink(mctx, x): |
246 """``symlink()`` |
272 """File that is marked as a symlink. |
247 File that is marked as a symlink. |
|
248 """ |
273 """ |
249 # i18n: "symlink" is a keyword |
274 # i18n: "symlink" is a keyword |
250 getargs(x, 0, 0, _("symlink takes no arguments")) |
275 getargs(x, 0, 0, _("symlink takes no arguments")) |
251 return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'l'] |
276 return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'l'] |
252 |
277 |
|
278 @predicate('resolved()') |
253 def resolved(mctx, x): |
279 def resolved(mctx, x): |
254 """``resolved()`` |
280 """File that is marked resolved according to :hg:`resolve -l`. |
255 File that is marked resolved according to :hg:`resolve -l`. |
|
256 """ |
281 """ |
257 # i18n: "resolved" is a keyword |
282 # i18n: "resolved" is a keyword |
258 getargs(x, 0, 0, _("resolved takes no arguments")) |
283 getargs(x, 0, 0, _("resolved takes no arguments")) |
259 if mctx.ctx.rev() is not None: |
284 if mctx.ctx.rev() is not None: |
260 return [] |
285 return [] |
261 ms = merge.mergestate.read(mctx.ctx.repo()) |
286 ms = merge.mergestate.read(mctx.ctx.repo()) |
262 return [f for f in mctx.subset if f in ms and ms[f] == 'r'] |
287 return [f for f in mctx.subset if f in ms and ms[f] == 'r'] |
263 |
288 |
|
289 @predicate('unresolved()') |
264 def unresolved(mctx, x): |
290 def unresolved(mctx, x): |
265 """``unresolved()`` |
291 """File that is marked unresolved according to :hg:`resolve -l`. |
266 File that is marked unresolved according to :hg:`resolve -l`. |
|
267 """ |
292 """ |
268 # i18n: "unresolved" is a keyword |
293 # i18n: "unresolved" is a keyword |
269 getargs(x, 0, 0, _("unresolved takes no arguments")) |
294 getargs(x, 0, 0, _("unresolved takes no arguments")) |
270 if mctx.ctx.rev() is not None: |
295 if mctx.ctx.rev() is not None: |
271 return [] |
296 return [] |
272 ms = merge.mergestate.read(mctx.ctx.repo()) |
297 ms = merge.mergestate.read(mctx.ctx.repo()) |
273 return [f for f in mctx.subset if f in ms and ms[f] == 'u'] |
298 return [f for f in mctx.subset if f in ms and ms[f] == 'u'] |
274 |
299 |
|
300 @predicate('hgignore()') |
275 def hgignore(mctx, x): |
301 def hgignore(mctx, x): |
276 """``hgignore()`` |
302 """File that matches the active .hgignore pattern. |
277 File that matches the active .hgignore pattern. |
|
278 """ |
303 """ |
279 # i18n: "hgignore" is a keyword |
304 # i18n: "hgignore" is a keyword |
280 getargs(x, 0, 0, _("hgignore takes no arguments")) |
305 getargs(x, 0, 0, _("hgignore takes no arguments")) |
281 ignore = mctx.ctx.repo().dirstate._ignore |
306 ignore = mctx.ctx.repo().dirstate._ignore |
282 return [f for f in mctx.subset if ignore(f)] |
307 return [f for f in mctx.subset if ignore(f)] |
283 |
308 |
|
309 @predicate('portable()') |
284 def portable(mctx, x): |
310 def portable(mctx, x): |
285 """``portable()`` |
311 """File that has a portable name. (This doesn't include filenames with case |
286 File that has a portable name. (This doesn't include filenames with case |
|
287 collisions.) |
312 collisions.) |
288 """ |
313 """ |
289 # i18n: "portable" is a keyword |
314 # i18n: "portable" is a keyword |
290 getargs(x, 0, 0, _("portable takes no arguments")) |
315 getargs(x, 0, 0, _("portable takes no arguments")) |
291 checkwinfilename = util.checkwinfilename |
316 checkwinfilename = util.checkwinfilename |
292 return [f for f in mctx.subset if checkwinfilename(f) is None] |
317 return [f for f in mctx.subset if checkwinfilename(f) is None] |
293 |
318 |
|
319 @predicate('grep(regex)') |
294 def grep(mctx, x): |
320 def grep(mctx, x): |
295 """``grep(regex)`` |
321 """File contains the given regular expression. |
296 File contains the given regular expression. |
|
297 """ |
322 """ |
298 try: |
323 try: |
299 # i18n: "grep" is a keyword |
324 # i18n: "grep" is a keyword |
300 r = re.compile(getstring(x, _("grep requires a pattern"))) |
325 r = re.compile(getstring(x, _("grep requires a pattern"))) |
301 except re.error as e: |
326 except re.error as e: |
400 s.append(f) |
425 s.append(f) |
401 elif enc == 'mac' and re.search('\r(?!\n)', d): |
426 elif enc == 'mac' and re.search('\r(?!\n)', d): |
402 s.append(f) |
427 s.append(f) |
403 return s |
428 return s |
404 |
429 |
|
430 @predicate('copied()') |
405 def copied(mctx, x): |
431 def copied(mctx, x): |
406 """``copied()`` |
432 """File that is recorded as being copied. |
407 File that is recorded as being copied. |
|
408 """ |
433 """ |
409 # i18n: "copied" is a keyword |
434 # i18n: "copied" is a keyword |
410 getargs(x, 0, 0, _("copied takes no arguments")) |
435 getargs(x, 0, 0, _("copied takes no arguments")) |
411 s = [] |
436 s = [] |
412 for f in mctx.subset: |
437 for f in mctx.subset: |
413 p = mctx.ctx[f].parents() |
438 p = mctx.ctx[f].parents() |
414 if p and p[0].path() != f: |
439 if p and p[0].path() != f: |
415 s.append(f) |
440 s.append(f) |
416 return s |
441 return s |
417 |
442 |
|
443 @predicate('subrepo([pattern])') |
418 def subrepo(mctx, x): |
444 def subrepo(mctx, x): |
419 """``subrepo([pattern])`` |
445 """Subrepositories whose paths match the given pattern. |
420 Subrepositories whose paths match the given pattern. |
|
421 """ |
446 """ |
422 # i18n: "subrepo" is a keyword |
447 # i18n: "subrepo" is a keyword |
423 getargs(x, 0, 1, _("subrepo takes at most one argument")) |
448 getargs(x, 0, 1, _("subrepo takes at most one argument")) |
424 ctx = mctx.ctx |
449 ctx = mctx.ctx |
425 sstate = sorted(ctx.substate) |
450 sstate = sorted(ctx.substate) |