changeset 40490:444861dc1e55

help: displaying documented aliases by default This makes aliases be displayed in "hg help" when they have a :doc config entry, and also allows them to be assigned to a category with :category. Differential Revision: https://phab.mercurial-scm.org/D5087
author rdamazio@google.com
date Thu, 18 Oct 2018 19:57:05 -0700
parents 1ddd202c47d9
children dce0e0f78f0f
files mercurial/dispatch.py mercurial/help.py mercurial/registrar.py tests/test-alias.t tests/test-help.t
diffstat 5 files changed, 76 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/dispatch.py	Sat Oct 13 05:43:39 2018 -0700
+++ b/mercurial/dispatch.py	Thu Oct 18 19:57:05 2018 -0700
@@ -37,6 +37,7 @@
     hook,
     profiling,
     pycompat,
+    registrar,
     scmutil,
     ui as uimod,
     util,
@@ -503,6 +504,7 @@
                 return ui.system(cmd, environ=env,
                                  blockedtag='alias_%s' % self.name)
             self.fn = fn
+            self.alias = True
             self._populatehelp(ui, name, shdef, self.fn)
             return
 
@@ -530,6 +532,7 @@
                 self.fn, self.opts = tableentry
                 cmdhelp = None
 
+            self.alias = True
             self._populatehelp(ui, name, cmd, self.fn, cmdhelp)
 
         except error.UnknownCommand:
@@ -543,7 +546,7 @@
     def _populatehelp(self, ui, name, cmd, fn, defaulthelp=None):
         # confine strings to be passed to i18n.gettext()
         cfg = {}
-        for k in ('doc', 'help'):
+        for k in ('doc', 'help', 'category'):
             v = ui.config('alias', '%s:%s' % (name, k), None)
             if v is None:
                 continue
@@ -558,11 +561,14 @@
             # drop prefix in old-style help lines so hg shows the alias
             self.help = self.help[4 + len(cmd):]
 
+        self.owndoc = 'doc' in cfg
         doc = cfg.get('doc', pycompat.getdoc(fn))
         if doc is not None:
             doc = pycompat.sysstr(doc)
         self.__doc__ = doc
 
+        self.helpcategory = cfg.get('category', registrar.command.CATEGORY_NONE)
+
     @property
     def args(self):
         args = pycompat.maplist(util.expandpath, self.givenargs)
@@ -613,6 +619,7 @@
         self.definition = definition
         self.cmdtable = cmdtable.copy()
         self.source = source
+        self.alias = True
 
     @util.propertycache
     def _aliasdef(self):
--- a/mercurial/help.py	Sat Oct 13 05:43:39 2018 -0700
+++ b/mercurial/help.py	Thu Oct 18 19:57:05 2018 -0700
@@ -189,12 +189,25 @@
     if notomitted:
         rst.append('\n\n.. container:: notomitted\n\n    %s\n\n' % notomitted)
 
-def filtercmd(ui, cmd, kw, doc):
+def filtercmd(ui, cmd, func, kw, doc):
     if not ui.debugflag and cmd.startswith("debug") and kw != "debug":
+        # Debug command, and user is not looking for those.
         return True
-    if not ui.verbose and doc and any(w in doc for w in _exclkeywords):
+    if not ui.verbose:
+        if not kw and not doc:
+            # Command had no documentation, no point in showing it by default.
+            return True
+        if getattr(func, 'alias', False) and not getattr(func, 'owndoc', False):
+            # Alias didn't have its own documentation.
+            return True
+        if doc and any(w in doc for w in _exclkeywords):
+            # Documentation has excluded keywords.
+            return True
+    if kw == "shortlist" and not getattr(func, 'helpbasic', False):
+        # We're presenting the short list but the command is not basic.
         return True
     if ui.configbool('help', 'hidden-command.%s' % cmd):
+        # Configuration explicitly hides the command.
         return True
     return False
 
@@ -230,13 +243,14 @@
         else:
             summary = ''
         # translate docs *before* searching there
-        docs = _(pycompat.getdoc(entry[0])) or ''
+        func = entry[0]
+        docs = _(pycompat.getdoc(func)) or ''
         if kw in cmd or lowercontains(summary) or lowercontains(docs):
             doclines = docs.splitlines()
             if doclines:
                 summary = doclines[0]
             cmdname = cmdutil.parsealiases(cmd)[0]
-            if filtercmd(ui, cmdname, kw, docs):
+            if filtercmd(ui, cmdname, func, kw, docs):
                 continue
             results['commands'].append((cmdname, summary))
     for name, docs in itertools.chain(
@@ -256,12 +270,13 @@
         for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
             if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
                 cmdname = cmdutil.parsealiases(cmd)[0]
-                cmddoc = pycompat.getdoc(entry[0])
+                func = entry[0]
+                cmddoc = pycompat.getdoc(func)
                 if cmddoc:
                     cmddoc = gettext(cmddoc).splitlines()[0]
                 else:
                     cmddoc = _('(no help text available)')
-                if filtercmd(ui, cmdname, kw, cmddoc):
+                if filtercmd(ui, cmdname, func, kw, cmddoc):
                     continue
                 results['extensioncommands'].append((cmdname, cmddoc))
     return results
@@ -525,14 +540,17 @@
             func = e[0]
             if select and not select(f):
                 continue
+            # Only list built-in commands (defined in commands.py) and aliases
+            # (defined in dispatch.py), but not any other extensions.
+            # We don't want a circular dependency between this file and
+            # dispatch, so reference that by name.
+            # TODO(rdamazio): Just show commands from all extensions.
             if (not select and name != 'shortlist' and
-                func.__module__ != commands.__name__):
+                func.__module__ != commands.__name__ and
+                func.__module__ != 'mercurial.dispatch'):
                 continue
-            if name == "shortlist":
-                if not getattr(func, 'helpbasic', False):
-                    continue
             doc = pycompat.getdoc(func)
-            if filtercmd(ui, f, name, doc):
+            if filtercmd(ui, f, func, name, doc):
                 continue
             doc = gettext(doc)
             if not doc:
--- a/mercurial/registrar.py	Sat Oct 13 05:43:39 2018 -0700
+++ b/mercurial/registrar.py	Thu Oct 18 19:57:05 2018 -0700
@@ -169,6 +169,10 @@
     """
 
     # Command categories for grouping them in help output.
+    # These can also be specified for aliases, like:
+    # [alias]
+    # myalias = something
+    # myalias:category = repo
     CATEGORY_REPO_CREATION = 'repo'
     CATEGORY_REMOTE_REPO_MANAGEMENT = 'remote'
     CATEGORY_COMMITTING = 'commit'
--- a/tests/test-alias.t	Sat Oct 13 05:43:39 2018 -0700
+++ b/tests/test-alias.t	Thu Oct 18 19:57:05 2018 -0700
@@ -68,17 +68,17 @@
 help
 
   $ hg help -c | grep myinit
-   myinit             This is my documented alias for init.
+   myinit       This is my documented alias for init.
   $ hg help -c | grep mycommit
-   mycommit           This is my alias with only doc.
+   mycommit     This is my alias with only doc.
   $ hg help -c | grep cleanstatus
-   cleanstatus        show changed files in the working directory
+  [1]
   $ hg help -c | grep lognull
-   lognull            Logs the null rev
+   lognull      Logs the null rev
   $ hg help -c | grep dln
-   dln                Logs the null rev
+  [1]
   $ hg help -c | grep recursivedoc
-   recursivedoc       Logs the null rev in debug mode
+   recursivedoc Logs the null rev in debug mode
   $ hg help myinit
   hg myinit [OPTIONS] [BLA] [BLE]
   
@@ -602,7 +602,7 @@
 help for a shell alias
 
   $ hg help -c | grep rebate
-   rebate             This is my alias which just prints something.
+   rebate       This is my alias which just prints something.
   $ hg help rebate
   hg rebate [MYARGS]
   
--- a/tests/test-help.t	Sat Oct 13 05:43:39 2018 -0700
+++ b/tests/test-help.t	Thu Oct 18 19:57:05 2018 -0700
@@ -823,6 +823,9 @@
   > def uisetup(ui):
   >     ui.setconfig(b'alias', b'shellalias', b'!echo hi', b'helpext')
   >     ui.setconfig(b'alias', b'hgalias', b'summary', b'helpext')
+  >     ui.setconfig(b'alias', b'hgalias:doc', b'My doc', b'helpext')
+  >     ui.setconfig(b'alias', b'hgalias:category', b'navigation', b'helpext')
+  >     ui.setconfig(b'alias', b'hgaliasnodoc', b'summary', b'helpext')
   > 
   > EOF
   $ echo '[extensions]' >> $HGRCPATH
@@ -830,11 +833,28 @@
 
 Test for aliases
 
+  $ hg help | grep hgalias
+   hgalias       My doc
+
   $ hg help hgalias
   hg hgalias [--remote]
   
   alias for: hg summary
   
+  My doc
+  
+  defined by: helpext
+  
+  options:
+  
+    --remote check for push and pull
+  
+  (some details hidden, use --verbose to show complete help)
+  $ hg help hgaliasnodoc
+  hg hgaliasnodoc [--remote]
+  
+  alias for: hg summary
+  
   summarize working directory state
   
       This generates a brief summary of the working directory state, including
@@ -947,6 +967,7 @@
   
    bisect        subdivision search of changesets
    heads         show branch heads
+   hgalias       My doc
    identify      identify the working directory or specified revision
    log           show revision history of entire repository or files
   
@@ -2662,6 +2683,13 @@
   hgalias
   </a>
   </td><td>
+  My doc
+  </td></tr>
+  <tr><td>
+  <a href="/help/hgaliasnodoc">
+  hgaliasnodoc
+  </a>
+  </td><td>
   summarize working directory state
   </td></tr>
   <tr><td>