mercurial/fileset.py
changeset 27460 11286ac374f3
parent 27459 2f15253e415f
child 27461 afa76585c955
--- a/mercurial/fileset.py	Mon Dec 21 22:31:16 2015 +0900
+++ b/mercurial/fileset.py	Mon Dec 21 22:31:16 2015 +0900
@@ -130,54 +130,79 @@
 def listset(mctx, a, b):
     raise error.ParseError(_("can't use a list in this context"))
 
+# symbols are callable like:
+#  fun(mctx, x)
+# with:
+#  mctx - current matchctx instance
+#  x - argument in tree form
+symbols = {}
+
+def predicate(decl):
+    """Return a decorator for fileset predicate function
+
+    'decl' argument is the declaration (including argument list like
+    'adds(pattern)') or the name (for internal use only) of predicate.
+    """
+    def decorator(func):
+        i = decl.find('(')
+        if i > 0:
+            name = decl[:i]
+        else:
+            name = decl
+        symbols[name] = func
+        if func.__doc__:
+            func.__doc__ = "``%s``\n    %s" % (decl, func.__doc__.strip())
+        return func
+    return decorator
+
+@predicate('modified()')
 def modified(mctx, x):
-    """``modified()``
-    File that is modified according to :hg:`status`.
+    """File that is modified according to :hg:`status`.
     """
     # i18n: "modified" is a keyword
     getargs(x, 0, 0, _("modified takes no arguments"))
     s = mctx.status().modified
     return [f for f in mctx.subset if f in s]
 
+@predicate('added()')
 def added(mctx, x):
-    """``added()``
-    File that is added according to :hg:`status`.
+    """File that is added according to :hg:`status`.
     """
     # i18n: "added" is a keyword
     getargs(x, 0, 0, _("added takes no arguments"))
     s = mctx.status().added
     return [f for f in mctx.subset if f in s]
 
+@predicate('removed()')
 def removed(mctx, x):
-    """``removed()``
-    File that is removed according to :hg:`status`.
+    """File that is removed according to :hg:`status`.
     """
     # i18n: "removed" is a keyword
     getargs(x, 0, 0, _("removed takes no arguments"))
     s = mctx.status().removed
     return [f for f in mctx.subset if f in s]
 
+@predicate('deleted()')
 def deleted(mctx, x):
-    """``deleted()``
-    Alias for ``missing()``.
+    """Alias for ``missing()``.
     """
     # i18n: "deleted" is a keyword
     getargs(x, 0, 0, _("deleted takes no arguments"))
     s = mctx.status().deleted
     return [f for f in mctx.subset if f in s]
 
+@predicate('missing()')
 def missing(mctx, x):
-    """``missing()``
-    File that is missing according to :hg:`status`.
+    """File that is missing according to :hg:`status`.
     """
     # i18n: "missing" is a keyword
     getargs(x, 0, 0, _("missing takes no arguments"))
     s = mctx.status().deleted
     return [f for f in mctx.subset if f in s]
 
+@predicate('unknown()')
 def unknown(mctx, x):
-    """``unknown()``
-    File that is unknown according to :hg:`status`. These files will only be
+    """File that is unknown according to :hg:`status`. These files will only be
     considered if this predicate is used.
     """
     # i18n: "unknown" is a keyword
@@ -185,9 +210,9 @@
     s = mctx.status().unknown
     return [f for f in mctx.subset if f in s]
 
+@predicate('ignored()')
 def ignored(mctx, x):
-    """``ignored()``
-    File that is ignored according to :hg:`status`. These files will only be
+    """File that is ignored according to :hg:`status`. These files will only be
     considered if this predicate is used.
     """
     # i18n: "ignored" is a keyword
@@ -195,9 +220,9 @@
     s = mctx.status().ignored
     return [f for f in mctx.subset if f in s]
 
+@predicate('clean()')
 def clean(mctx, x):
-    """``clean()``
-    File that is clean according to :hg:`status`.
+    """File that is clean according to :hg:`status`.
     """
     # i18n: "clean" is a keyword
     getargs(x, 0, 0, _("clean takes no arguments"))
@@ -226,33 +251,33 @@
         raise error.ParseError(err)
     return l
 
+@predicate('binary()')
 def binary(mctx, x):
-    """``binary()``
-    File that appears to be binary (contains NUL bytes).
+    """File that appears to be binary (contains NUL bytes).
     """
     # i18n: "binary" is a keyword
     getargs(x, 0, 0, _("binary takes no arguments"))
     return [f for f in mctx.existing() if util.binary(mctx.ctx[f].data())]
 
+@predicate('exec()')
 def exec_(mctx, x):
-    """``exec()``
-    File that is marked as executable.
+    """File that is marked as executable.
     """
     # i18n: "exec" is a keyword
     getargs(x, 0, 0, _("exec takes no arguments"))
     return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'x']
 
+@predicate('symlink()')
 def symlink(mctx, x):
-    """``symlink()``
-    File that is marked as a symlink.
+    """File that is marked as a symlink.
     """
     # i18n: "symlink" is a keyword
     getargs(x, 0, 0, _("symlink takes no arguments"))
     return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'l']
 
+@predicate('resolved()')
 def resolved(mctx, x):
-    """``resolved()``
-    File that is marked resolved according to :hg:`resolve -l`.
+    """File that is marked resolved according to :hg:`resolve -l`.
     """
     # i18n: "resolved" is a keyword
     getargs(x, 0, 0, _("resolved takes no arguments"))
@@ -261,9 +286,9 @@
     ms = merge.mergestate.read(mctx.ctx.repo())
     return [f for f in mctx.subset if f in ms and ms[f] == 'r']
 
+@predicate('unresolved()')
 def unresolved(mctx, x):
-    """``unresolved()``
-    File that is marked unresolved according to :hg:`resolve -l`.
+    """File that is marked unresolved according to :hg:`resolve -l`.
     """
     # i18n: "unresolved" is a keyword
     getargs(x, 0, 0, _("unresolved takes no arguments"))
@@ -272,18 +297,18 @@
     ms = merge.mergestate.read(mctx.ctx.repo())
     return [f for f in mctx.subset if f in ms and ms[f] == 'u']
 
+@predicate('hgignore()')
 def hgignore(mctx, x):
-    """``hgignore()``
-    File that matches the active .hgignore pattern.
+    """File that matches the active .hgignore pattern.
     """
     # i18n: "hgignore" is a keyword
     getargs(x, 0, 0, _("hgignore takes no arguments"))
     ignore = mctx.ctx.repo().dirstate._ignore
     return [f for f in mctx.subset if ignore(f)]
 
+@predicate('portable()')
 def portable(mctx, x):
-    """``portable()``
-    File that has a portable name. (This doesn't include filenames with case
+    """File that has a portable name. (This doesn't include filenames with case
     collisions.)
     """
     # i18n: "portable" is a keyword
@@ -291,9 +316,9 @@
     checkwinfilename = util.checkwinfilename
     return [f for f in mctx.subset if checkwinfilename(f) is None]
 
+@predicate('grep(regex)')
 def grep(mctx, x):
-    """``grep(regex)``
-    File contains the given regular expression.
+    """File contains the given regular expression.
     """
     try:
         # i18n: "grep" is a keyword
@@ -318,9 +343,9 @@
     except ValueError:
         raise error.ParseError(_("couldn't parse size: %s") % s)
 
+@predicate('size(expression)')
 def size(mctx, x):
-    """``size(expression)``
-    File size matches the given expression. Examples:
+    """File size matches the given expression. Examples:
 
     - 1k (files from 1024 to 2047 bytes)
     - < 20k (files less than 20480 bytes)
@@ -356,9 +381,9 @@
 
     return [f for f in mctx.existing() if m(mctx.ctx[f].size())]
 
+@predicate('encoding(name)')
 def encoding(mctx, x):
-    """``encoding(name)``
-    File can be successfully decoded with the given character
+    """File can be successfully decoded with the given character
     encoding. May not be useful for encodings other than ASCII and
     UTF-8.
     """
@@ -379,9 +404,9 @@
 
     return s
 
+@predicate('eol(style)')
 def eol(mctx, x):
-    """``eol(style)``
-    File contains newlines of the given style (dos, unix, mac). Binary
+    """File contains newlines of the given style (dos, unix, mac). Binary
     files are excluded, files with mixed line endings match multiple
     styles.
     """
@@ -402,9 +427,9 @@
             s.append(f)
     return s
 
+@predicate('copied()')
 def copied(mctx, x):
-    """``copied()``
-    File that is recorded as being copied.
+    """File that is recorded as being copied.
     """
     # i18n: "copied" is a keyword
     getargs(x, 0, 0, _("copied takes no arguments"))
@@ -415,9 +440,9 @@
             s.append(f)
     return s
 
+@predicate('subrepo([pattern])')
 def subrepo(mctx, x):
-    """``subrepo([pattern])``
-    Subrepositories whose paths match the given pattern.
+    """Subrepositories whose paths match the given pattern.
     """
     # i18n: "subrepo" is a keyword
     getargs(x, 0, 1, _("subrepo takes at most one argument"))
@@ -438,30 +463,6 @@
     else:
         return [sub for sub in sstate]
 
-symbols = {
-    'added': added,
-    'binary': binary,
-    'clean': clean,
-    'copied': copied,
-    'deleted': deleted,
-    'encoding': encoding,
-    'eol': eol,
-    'exec': exec_,
-    'grep': grep,
-    'ignored': ignored,
-    'hgignore': hgignore,
-    'missing': missing,
-    'modified': modified,
-    'portable': portable,
-    'removed': removed,
-    'resolved': resolved,
-    'size': size,
-    'symlink': symlink,
-    'unknown': unknown,
-    'unresolved': unresolved,
-    'subrepo': subrepo,
-}
-
 methods = {
     'string': stringset,
     'symbol': stringset,