[PATCH] help: 'hg help' supports subtopics (issue2804)

Martin Geisler mg at aragost.com
Thu May 12 02:48:33 CDT 2011

Yun Lee <yun.lee.bj at gmail.com> writes:

Hi Yun,

It's great to see you're becoming familiar with the code! I have put
some comments below and a longer suggestion at the end :)

> diff -r 89e7d35e0ef0 -r fb82249e4ef6 mercurial/help.py
> --- a/mercurial/help.py	Sun May 01 13:07:00 2011 +0200
> +++ b/mercurial/help.py	Thu May 12 00:33:41 2011 +0800
> @@ -86,26 +86,53 @@
>      return loader
> +def loadsubdoc(topic, subtopic):
> +    def loader():
> +        if hasattr(sys, 'frozen'):
> +            module = sys.executable
> +        else:
> +            module = __file__
> +        base = os.path.dirname(module)
> +
> +        for dir in ('', '..', '.'):
> +            docdir = os.path.join(base, dir, 'help')
> +            if os.path.isdir(docdir):
> +                break
> +
> +        path = os.path.join(docdir, topic, subtopic + ".txt")
> +        
> +        doc = gettext(open(path).read())
> +        for rewriter in helphooks.get(topic, []):
> +            doc = rewriter(topic, doc)
> +        return doc
> +
> +    return loader

I think this does almost the same as the loaddoc function, right? So if
I call

  loadsubdoc('config', 'alias')

then I think I get the same result as if I called

  loaddoc(os.path.join('config', 'alias'))

or even just


If so, then we don't need a new function. If not, then we must be able
to adjust the loaddoc function so that it can serve both purposes. That
will let us avoid duplicating code.

>  helptable = [
> -    (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
> -    (["dates"], _("Date Formats"), loaddoc('dates')),
> -    (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
> +    (["config", "hgrc"], _("Configuration Files"), loaddoc('config')
> +     , [(["alias"], _("Defines command aliases"), loadsubdoc('config', 'alias')),
> +        (["auth"], _("Defines  Authentication credentials"), loadsubdoc('config', 'auth')),
> +        (["defaults"], _("Defines command defaults"), loadsubdoc('config', 'defaults')),
> +        ]),

There were at least two goals with the original idea:

1) Make it possible to do 'hg help ui.username' in a console and get
   some information about that config setting.

2) Make it easier to keep the documentation up to date by putting the
   help text for ui.username close to where that config setting is used

I think this patch helps with 1) but from a higher-level, I think it
really does a third thing:

3) Let help topics point to a list of subtopics.

To solve 1), we don't actually need anything new -- we just need to add
a lot of help topics with names like 'ui.username' and so on. In
combination with 2), it would make sense to add those help topics based
on where we define the config settings.

I'm thinking of a system where ui.py could start with

  conftable = [
      ('ui.username', str, None, "The committer of a changeset created ..."),
      ('ui.verbose', bool, False, "Increase the amount of output printed."),
      ('ui.quiet', bool, False, "Reduce the amount of output printed."),

and where url.py would have

  conftable = [
      ('ui.userhttp2, bool, False, "User experimental HTTP client."),
      ('http_proxy.host', str, None, "Proxy hostname"),

just to illustrate that a module might define config settings in "other"

We can then generate the hgrc.5.txt file from these tables by importing
all modules when building documentation. This raises the question if all
our modules import-safe?

Maybe it would be better to use a specially formatted comment. That
comment could then be put directly where it is needed! Like this

diff --git a/mercurial/url.py b/mercurial/url.py
--- a/mercurial/url.py
+++ b/mercurial/url.py
@@ -425,6 +425,9 @@
     construct an opener suitable for urllib2
     authinfo will be added to the password manager
+    ## ui.usehttp2: bool, False
+    ##
+    ## Use new experimental HTTP client?
     if ui.configbool('ui', 'usehttp2', False):
         handlers = [httpconnectionmod.http2handler(ui, passwordmgr(ui))]

Except for setdiscovery.py, we don't use any '##' comments ourselves, so
this might just be enough for us to parse a setting name, a type and a
default value. The default value might be enough to determine the type,
except if there is no default value.

Again, we would be extracting these comments when building the
documentation. At the same time, we would turn the comments into
additional help topics. This would take the form of an auto-generated
Python file with

  conftable = [
      ('ui.username', str, None, "The committer of a changeset created ..."),
      ('ui.verbose', bool, False, "Increase the amount of output printed."),
      ('ui.quiet', bool, False, "Reduce the amount of output printed."),
      ('ui.userhttp2, bool, False, "User experimental HTTP client."),
      ('http_proxy.host', str, None, "Proxy hostname"),

The help module would then import that file and add help topics based on
the table.

Finally, we could write an extension that would make the ui.config*
methods return a warning if a config setting has not been defined. The
test suite could run tests with that extension enabled and that should
help us to document all settings in the beginning. There are some
settings which we cannot document since they are not pre-defined. The
merge-tools settings is one example of this.

Phew, lots of ideas here! I personally like the idea of special comments
in the code, but let me know what you think about it.

Martin Geisler

aragost Trifork
Professional Mercurial support

More information about the Mercurial-devel mailing list