revsets: generate predicate help dynamically stable
authorPatrick Mezard <pmezard@gmail.com>
Sat, 23 Oct 2010 19:21:51 +0200
branchstable
changeset 12821 165079e564f0
parent 12820 0edc0aa7432d
child 12822 f13acb96b2a7
revsets: generate predicate help dynamically
mercurial/commands.py
mercurial/help/revsets.txt
mercurial/revset.py
--- a/mercurial/commands.py	Sat Oct 23 19:21:49 2010 +0200
+++ b/mercurial/commands.py	Sat Oct 23 19:21:51 2010 +0200
@@ -2029,6 +2029,8 @@
         ui.write(_('use "hg help extensions" for information on enabling '
                    'extensions\n'))
 
+    help.addtopichook('revsets', revset.makedoc)
+
     if name and name != 'shortlist':
         i = None
         if unknowncmd:
--- a/mercurial/help/revsets.txt	Sat Oct 23 19:21:49 2010 +0200
+++ b/mercurial/help/revsets.txt	Sat Oct 23 19:21:51 2010 +0200
@@ -45,123 +45,7 @@
 
 The following predicates are supported:
 
-``adds(pattern)``
-  Changesets that add a file matching pattern.
-
-``all()``
-  All changesets, the same as ``0:tip``.
-
-``ancestor(single, single)``
-  Greatest common ancestor of the two changesets.
-
-``ancestors(set)``
-  Changesets that are ancestors of a changeset in set.
-
-``author(string)``
-  Alias for ``user(string)``.
-
-``branch(set)``
-  All changesets belonging to the branches of changesets in set.
-
-``children(set)``
-  Child changesets of changesets in set.
-
-``closed()``
-  Changeset is closed.
-
-``contains(pattern)``
-  Revision contains pattern.
-
-``date(interval)``
-  Changesets within the interval, see :hg:`help dates`.
-
-``descendants(set)``
-  Changesets which are descendants of changesets in set.
-
-``file(pattern)``
-  Changesets affecting files matched by pattern.
-
-``follow()``
-  An alias for ``::.`` (ancestors of the working copy's first parent).
-
-``grep(regex)``
-  Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
-  to ensure special escape characters are handled correctly.
-
-``head()``
-  Changeset is a named branch head.
-
-``heads(set)``
-  Members of set with no children in set.
-
-``id(string)``
-  Revision non-ambiguously specified by the given hex string prefix
-
-``keyword(string)``
-  Search commit message, user name, and names of changed files for
-  string.
-
-``limit(set, n)``
-  First n members of set.
-
-``max(set)``
-  Changeset with highest revision number in set.
-
-``min(set)``
-  Changeset with lowest revision number in set.
-
-``merge()``
-  Changeset is a merge changeset.
-
-``modifies(pattern)``
-  Changesets modifying files matched by pattern.
-
-``outgoing([path])``
-  Changesets not found in the specified destination repository, or the
-  default push location.
-
-``p1(set)``
-  First parent of changesets in set.
-
-``p2(set)``
-  Second parent of changesets in set.
-
-``parents(set)``
-  The set of all parents for all changesets in set.
-
-``present(set)``
-  An empty set, if any revision in set isn't found; otherwise,
-  all revisions in set.
-
-``removes(pattern)``
-  Changesets which remove files matching pattern.
-
-``rev(number)``
-  Revision with the given numeric identifier.
-
-``reverse(set)``
-  Reverse order of set.
-
-``roots(set)``
-  Changesets with no parent changeset in set.
-
-``sort(set[, [-]key...])``
-  Sort set by keys. The default sort order is ascending, specify a key
-  as ``-key`` to sort in descending order.
-
-  The keys can be:
-
-  - ``rev`` for the revision number,
-  - ``branch`` for the branch name,
-  - ``desc`` for the commit message (description),
-  - ``user`` for user name (``author`` can be used as an alias),
-  - ``date`` for the commit date
-
-``tag(name)``
-  The specified tag by name, or all tagged revisions if no name is given.
-
-``user(string)``
-  User name is string.
+.. predicatesmarker
 
 Command line equivalents for :hg:`log`::
 
--- a/mercurial/revset.py	Sat Oct 23 19:21:49 2010 +0200
+++ b/mercurial/revset.py	Sat Oct 23 19:21:51 2010 +0200
@@ -174,6 +174,9 @@
 # functions
 
 def node(repo, subset, x):
+    """``id(string)``
+    Revision non-ambiguously specified by the given hex string prefix
+    """
     # i18n: "id" is a keyword
     l = getargs(x, 1, 1, _("id requires one argument"))
     # i18n: "id" is a keyword
@@ -185,6 +188,9 @@
     return [r for r in subset if r == rn]
 
 def rev(repo, subset, x):
+    """``rev(number)``
+    Revision with the given numeric identifier.
+    """
     # i18n: "rev" is a keyword
     l = getargs(x, 1, 1, _("rev requires one argument"))
     try:
@@ -196,6 +202,9 @@
     return [r for r in subset if r == l]
 
 def p1(repo, subset, x):
+    """``p1(set)``
+    First parent of changesets in set.
+    """
     ps = set()
     cl = repo.changelog
     for r in getset(repo, range(len(repo)), x):
@@ -203,6 +212,9 @@
     return [r for r in subset if r in ps]
 
 def p2(repo, subset, x):
+    """``p2(set)``
+    Second parent of changesets in set.
+    """
     ps = set()
     cl = repo.changelog
     for r in getset(repo, range(len(repo)), x):
@@ -210,6 +222,9 @@
     return [r for r in subset if r in ps]
 
 def parents(repo, subset, x):
+    """``parents(set)``
+    The set of all parents for all changesets in set.
+    """
     ps = set()
     cl = repo.changelog
     for r in getset(repo, range(len(repo)), x):
@@ -217,6 +232,9 @@
     return [r for r in subset if r in ps]
 
 def maxrev(repo, subset, x):
+    """``max(set)``
+    Changeset with highest revision number in set.
+    """
     s = getset(repo, subset, x)
     if s:
         m = max(s)
@@ -225,6 +243,9 @@
     return []
 
 def minrev(repo, subset, x):
+    """``min(set)``
+    Changeset with lowest revision number in set.
+    """
     s = getset(repo, subset, x)
     if s:
         m = min(s)
@@ -233,6 +254,9 @@
     return []
 
 def limit(repo, subset, x):
+    """``limit(set, n)``
+    First n members of set.
+    """
     # i18n: "limit" is a keyword
     l = getargs(x, 2, 2, _("limit requires two arguments"))
     try:
@@ -244,6 +268,9 @@
     return getset(repo, subset, l[0])[:lim]
 
 def children(repo, subset, x):
+    """``children(set)``
+    Child changesets of changesets in set.
+    """
     cs = set()
     cl = repo.changelog
     s = set(getset(repo, range(len(repo)), x))
@@ -254,6 +281,9 @@
     return [r for r in subset if r in cs]
 
 def branch(repo, subset, x):
+    """``branch(set)``
+    All changesets belonging to the branches of changesets in set.
+    """
     s = getset(repo, range(len(repo)), x)
     b = set()
     for r in s:
@@ -262,6 +292,9 @@
     return [r for r in subset if r in s or repo[r].branch() in b]
 
 def ancestor(repo, subset, x):
+    """``ancestor(single, single)``
+    Greatest common ancestor of the two changesets.
+    """
     # i18n: "ancestor" is a keyword
     l = getargs(x, 2, 2, _("ancestor requires two arguments"))
     r = range(len(repo))
@@ -275,6 +308,9 @@
     return [r for r in an if r in subset]
 
 def ancestors(repo, subset, x):
+    """``ancestors(set)``
+    Changesets that are ancestors of a changeset in set.
+    """
     args = getset(repo, range(len(repo)), x)
     if not args:
         return []
@@ -282,6 +318,9 @@
     return [r for r in subset if r in s]
 
 def descendants(repo, subset, x):
+    """``descendants(set)``
+    Changesets which are descendants of changesets in set.
+    """
     args = getset(repo, range(len(repo)), x)
     if not args:
         return []
@@ -289,6 +328,9 @@
     return [r for r in subset if r in s]
 
 def follow(repo, subset, x):
+    """``follow()``
+    An alias for ``::.`` (ancestors of the working copy's first parent).
+    """
     # i18n: "follow" is a keyword
     getargs(x, 0, 0, _("follow takes no arguments"))
     p = repo['.'].rev()
@@ -296,12 +338,19 @@
     return [r for r in subset if r in s]
 
 def date(repo, subset, x):
+    """``date(interval)``
+    Changesets within the interval, see :hg:`help dates`.
+    """
     # i18n: "date" is a keyword
     ds = getstring(x, _("date requires a string"))
     dm = util.matchdate(ds)
     return [r for r in subset if dm(repo[r].date()[0])]
 
 def keyword(repo, subset, x):
+    """``keyword(string)``
+    Search commit message, user name, and names of changed files for
+    string.
+    """
     # i18n: "keyword" is a keyword
     kw = getstring(x, _("keyword requires a string")).lower()
     l = []
@@ -313,6 +362,10 @@
     return l
 
 def grep(repo, subset, x):
+    """``grep(regex)``
+    Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
+    to ensure special escape characters are handled correctly.
+    """
     try:
         # i18n: "grep" is a keyword
         gr = re.compile(getstring(x, _("grep requires a string")))
@@ -328,11 +381,23 @@
     return l
 
 def author(repo, subset, x):
+    """``author(string)``
+    Alias for ``user(string)``.
+    """
     # i18n: "author" is a keyword
     n = getstring(x, _("author requires a string")).lower()
     return [r for r in subset if n in repo[r].user().lower()]
 
+def user(repo, subset, x):
+    """``user(string)``
+    User name is string.
+    """
+    return author(repo, subset, x)
+
 def hasfile(repo, subset, x):
+    """``file(pattern)``
+    Changesets affecting files matched by pattern.
+    """
     # i18n: "file" is a keyword
     pat = getstring(x, _("file requires a pattern"))
     m = matchmod.match(repo.root, repo.getcwd(), [pat])
@@ -345,6 +410,9 @@
     return s
 
 def contains(repo, subset, x):
+    """``contains(pattern)``
+    Revision contains pattern.
+    """
     # i18n: "contains" is a keyword
     pat = getstring(x, _("contains requires a pattern"))
     m = matchmod.match(repo.root, repo.getcwd(), [pat])
@@ -390,32 +458,50 @@
     return s
 
 def modifies(repo, subset, x):
+    """``modifies(pattern)``
+    Changesets modifying files matched by pattern.
+    """
     # i18n: "modifies" is a keyword
     pat = getstring(x, _("modifies requires a pattern"))
     return checkstatus(repo, subset, pat, 0)
 
 def adds(repo, subset, x):
+    """``adds(pattern)``
+    Changesets that add a file matching pattern.
+    """
     # i18n: "adds" is a keyword
     pat = getstring(x, _("adds requires a pattern"))
     return checkstatus(repo, subset, pat, 1)
 
 def removes(repo, subset, x):
+    """``removes(pattern)``
+    Changesets which remove files matching pattern.
+    """
     # i18n: "removes" is a keyword
     pat = getstring(x, _("removes requires a pattern"))
     return checkstatus(repo, subset, pat, 2)
 
 def merge(repo, subset, x):
+    """``merge()``
+    Changeset is a merge changeset.
+    """
     # i18n: "merge" is a keyword
     getargs(x, 0, 0, _("merge takes no arguments"))
     cl = repo.changelog
     return [r for r in subset if cl.parentrevs(r)[1] != -1]
 
 def closed(repo, subset, x):
+    """``closed()``
+    Changeset is closed.
+    """
     # i18n: "closed" is a keyword
     getargs(x, 0, 0, _("closed takes no arguments"))
     return [r for r in subset if repo[r].extra().get('close')]
 
 def head(repo, subset, x):
+    """``head()``
+    Changeset is a named branch head.
+    """
     # i18n: "head" is a keyword
     getargs(x, 0, 0, _("head takes no arguments"))
     hs = set()
@@ -424,17 +510,36 @@
     return [r for r in subset if r in hs]
 
 def reverse(repo, subset, x):
+    """``reverse(set)``
+    Reverse order of set.
+    """
     l = getset(repo, subset, x)
     l.reverse()
     return l
 
 def present(repo, subset, x):
+    """``present(set)``
+    An empty set, if any revision in set isn't found; otherwise,
+    all revisions in set.
+    """
     try:
         return getset(repo, subset, x)
     except error.RepoLookupError:
         return []
 
 def sort(repo, subset, x):
+    """``sort(set[, [-]key...])``
+    Sort set by keys. The default sort order is ascending, specify a key
+    as ``-key`` to sort in descending order.
+
+    The keys can be:
+
+    - ``rev`` for the revision number,
+    - ``branch`` for the branch name,
+    - ``desc`` for the commit message (description),
+    - ``user`` for user name (``author`` can be used as an alias),
+    - ``date`` for the commit date
+    """
     # i18n: "sort" is a keyword
     l = getargs(x, 1, 2, _("sort requires one or two arguments"))
     keys = "rev"
@@ -478,21 +583,34 @@
     return [e[-1] for e in l]
 
 def getall(repo, subset, x):
+    """``all()``
+    All changesets, the same as ``0:tip``.
+    """
     # i18n: "all" is a keyword
     getargs(x, 0, 0, _("all takes no arguments"))
     return subset
 
 def heads(repo, subset, x):
+    """``heads(set)``
+    Members of set with no children in set.
+    """
     s = getset(repo, subset, x)
     ps = set(parents(repo, subset, x))
     return [r for r in s if r not in ps]
 
 def roots(repo, subset, x):
+    """``roots(set)``
+    Changesets with no parent changeset in set.
+    """
     s = getset(repo, subset, x)
     cs = set(children(repo, subset, x))
     return [r for r in s if r not in cs]
 
 def outgoing(repo, subset, x):
+    """``outgoing([path])``
+    Changesets not found in the specified destination repository, or the
+    default push location.
+    """
     import hg # avoid start-up nasties
     # i18n: "outgoing" is a keyword
     l = getargs(x, 0, 1, _("outgoing requires a repository path"))
@@ -512,6 +630,9 @@
     return [r for r in subset if r in o]
 
 def tag(repo, subset, x):
+    """``tag(name)``
+    The specified tag by name, or all tagged revisions if no name is given.
+    """
     # i18n: "tag" is a keyword
     args = getargs(x, 0, 1, _("tag takes one or no arguments"))
     cl = repo.changelog
@@ -524,6 +645,9 @@
         s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
     return [r for r in subset if r in s]
 
+def tagged(repo, subset, x):
+    return tag(repo, subset, x)
+
 symbols = {
     "adds": adds,
     "all": getall,
@@ -559,8 +683,8 @@
     "roots": roots,
     "sort": sort,
     "tag": tag,
-    "tagged": tag,
-    "user": author,
+    "tagged": tagged,
+    "user": user,
 }
 
 methods = {
@@ -653,3 +777,17 @@
     def mfunc(repo, subset):
         return getset(repo, subset, tree)
     return mfunc
+
+def makedoc(topic, doc):
+    """Generate and include predicates help in revsets topic."""
+    predicates = []
+    for name in sorted(symbols):
+        text = symbols[name].__doc__
+        if not text:
+            continue
+        lines = text.splitlines()
+        lines[1:] = [('  ' + l.strip()) for l in lines[1:]]
+        predicates.append('\n'.join(lines))
+    predicates = '\n'.join(predicates)
+    doc = doc.replace('.. predicatesmarker', predicates)
+    return doc