Patchwork [V2] extensions: allow extending command synopsis and docstring

login
register
mail settings
Submitter Ryan McElroy
Date Feb. 11, 2015, 11:06 p.m.
Message ID <2bf76082ec5aa2ed823d.1423695965@devbig105.prn2.facebook.com>
Download mbox | patch
Permalink /patch/7793/
State Superseded
Headers show

Comments

Ryan McElroy - Feb. 11, 2015, 11:06 p.m.
# HG changeset patch
# User Ryan McElroy <rm@fb.com>
# Date 1423508565 28800
#      Mon Feb 09 11:02:45 2015 -0800
# Node ID 2bf76082ec5aa2ed823d89424354ef063f2de93a
# Parent  ff5caa8dfd993680d9602ca6ebb14da9de10d5f4
extensions: allow extending command synopsis and docstring

Mercurial uses a synopsis string and the docstring of a command for the
command's help output. Today  there is no way for an extension that adds
functionality to a command to extend either of these help strings.

This patch enables appending to both the doctring and the synopsis, and adds
a test for this functionality. Example usage is shown in the test and is also
described in the docstring of extensions.wrapcommand().
Ryan McElroy - Feb. 11, 2015, 11:17 p.m.
On 2/11/2015 3:06 PM, Ryan McElroy wrote:
> # HG changeset patch
> # User Ryan McElroy <rm@fb.com>
> # Date 1423508565 28800
> #      Mon Feb 09 11:02:45 2015 -0800
> # Node ID 2bf76082ec5aa2ed823d89424354ef063f2de93a
> # Parent  ff5caa8dfd993680d9602ca6ebb14da9de10d5f4
> extensions: allow extending command synopsis and docstring
>
> Mercurial uses a synopsis string and the docstring of a command for the
> command's help output. Today  there is no way for an extension that adds
> functionality to a command to extend either of these help strings.
>
> This patch enables appending to both the doctring and the synopsis, and adds
> a test for this functionality. Example usage is shown in the test and is also
> described in the docstring of extensions.wrapcommand().
>
> diff --git a/mercurial/extensions.py b/mercurial/extensions.py
> --- a/mercurial/extensions.py
> +++ b/mercurial/extensions.py
> @@ -152,7 +152,7 @@ def afterloaded(extension, callback):
>       else:
>           _aftercallbacks.setdefault(extension, []).append(callback)
>   
> -def wrapcommand(table, command, wrapper):
> +def wrapcommand(table, command, wrapper, synopsis=None, docstring=None):
>       '''Wrap the command named `command' in table
>   
>       Replace command in the command table with wrapper. The wrapped command will
> @@ -164,6 +164,22 @@ def wrapcommand(table, command, wrapper)
>   
>       where orig is the original (wrapped) function, and *args, **kwargs
>       are the arguments passed to it.
> +
> +    Optionally append to the command synopsis and docstring, used for help.
> +    For example, if your extension wraps the ``bookmarks`` command to add the
> +    flags ``--remote`` and ``--all`` you might call this function like so:
> +
> +      synopsis = ' [-a] [--remote]'
> +      docstring = """
> +
> +      The ``remotenames`` extension adds the ``--remote`` and ``--all`` (``-a``)
> +      flags to the bookmarks command. Either flag will show the remote bookmarks
> +      known to the repository; ``--remote`` will also supress the output of the
> +      local bookmarks.
> +      """
> +
> +      extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
> +                             synopsis, docstring)
>       '''
>       assert callable(wrapper)
>       aliases, entry = cmdutil.findcmd(command, table)
> @@ -177,11 +193,17 @@ def wrapcommand(table, command, wrapper)
>           return util.checksignature(wrapper)(
>               util.checksignature(origfn), *args, **kwargs)
>   
> -    wrap.__doc__ = getattr(origfn, '__doc__')
>       wrap.__module__ = getattr(origfn, '__module__')
>   
> +    doc = getattr(origfn, '__doc__')
> +    if docstring is not None:
> +        doc += docstring
> +    wrap.__doc__ = doc
> +
>       newentry = list(entry)
>       newentry[0] = wrap
> +    if synopsis is not None:
> +        newentry[2] += synopsis
>       table[key] = tuple(newentry)
>       return entry
>   
> diff --git a/tests/test-extension.t b/tests/test-extension.t
> --- a/tests/test-extension.t
> +++ b/tests/test-extension.t
> @@ -1140,3 +1140,27 @@ disabling in command line overlays with
>     C sub3/3
>   
>     $ cd ..
> +
> +Test synopsis and docstring extending
> +
> +  $ hg init exthelp
> +  $ cat > exthelp.py <<EOF
> +  > from mercurial import commands, extensions
> +  > def exbookmarks(orig, *args, **opts):
> +  >     return orig(*args, **opts)
> +  > def uisetup(ui):
> +  >     synopsis = ' GREPME [--foo] [-x]'
> +  >     docstring = '''
> +  >     GREPME make sure that this is in the help!
> +  >     '''
> +  >     extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
> +  >                            synopsis, docstring)
> +  > EOF
> +  $ abspath=`pwd`/exthelp.py
> +  $ echo '[extensions]' > $HGRCPATH

Whoops, this fails the code checker. V3 is on it's way...

> +  $ echo "exthelp = $abspath" >> $HGRCPATH
> +  $ cd exthelp
> +  $ hg help bookmarks | grep GREPME
> +  hg bookmarks [OPTIONS]... [NAME]... GREPME [--foo] [-x]
> +      GREPME make sure that this is in the help!
> +

Patch

diff --git a/mercurial/extensions.py b/mercurial/extensions.py
--- a/mercurial/extensions.py
+++ b/mercurial/extensions.py
@@ -152,7 +152,7 @@  def afterloaded(extension, callback):
     else:
         _aftercallbacks.setdefault(extension, []).append(callback)
 
-def wrapcommand(table, command, wrapper):
+def wrapcommand(table, command, wrapper, synopsis=None, docstring=None):
     '''Wrap the command named `command' in table
 
     Replace command in the command table with wrapper. The wrapped command will
@@ -164,6 +164,22 @@  def wrapcommand(table, command, wrapper)
 
     where orig is the original (wrapped) function, and *args, **kwargs
     are the arguments passed to it.
+
+    Optionally append to the command synopsis and docstring, used for help.
+    For example, if your extension wraps the ``bookmarks`` command to add the
+    flags ``--remote`` and ``--all`` you might call this function like so:
+
+      synopsis = ' [-a] [--remote]'
+      docstring = """
+
+      The ``remotenames`` extension adds the ``--remote`` and ``--all`` (``-a``)
+      flags to the bookmarks command. Either flag will show the remote bookmarks
+      known to the repository; ``--remote`` will also supress the output of the
+      local bookmarks.
+      """
+
+      extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
+                             synopsis, docstring)
     '''
     assert callable(wrapper)
     aliases, entry = cmdutil.findcmd(command, table)
@@ -177,11 +193,17 @@  def wrapcommand(table, command, wrapper)
         return util.checksignature(wrapper)(
             util.checksignature(origfn), *args, **kwargs)
 
-    wrap.__doc__ = getattr(origfn, '__doc__')
     wrap.__module__ = getattr(origfn, '__module__')
 
+    doc = getattr(origfn, '__doc__')
+    if docstring is not None:
+        doc += docstring
+    wrap.__doc__ = doc
+
     newentry = list(entry)
     newentry[0] = wrap
+    if synopsis is not None:
+        newentry[2] += synopsis
     table[key] = tuple(newentry)
     return entry
 
diff --git a/tests/test-extension.t b/tests/test-extension.t
--- a/tests/test-extension.t
+++ b/tests/test-extension.t
@@ -1140,3 +1140,27 @@  disabling in command line overlays with 
   C sub3/3
 
   $ cd ..
+
+Test synopsis and docstring extending
+
+  $ hg init exthelp
+  $ cat > exthelp.py <<EOF
+  > from mercurial import commands, extensions
+  > def exbookmarks(orig, *args, **opts):
+  >     return orig(*args, **opts)
+  > def uisetup(ui):
+  >     synopsis = ' GREPME [--foo] [-x]'
+  >     docstring = '''
+  >     GREPME make sure that this is in the help!
+  >     '''
+  >     extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
+  >                            synopsis, docstring)
+  > EOF
+  $ abspath=`pwd`/exthelp.py
+  $ echo '[extensions]' > $HGRCPATH
+  $ echo "exthelp = $abspath" >> $HGRCPATH
+  $ cd exthelp
+  $ hg help bookmarks | grep GREPME
+  hg bookmarks [OPTIONS]... [NAME]... GREPME [--foo] [-x]
+      GREPME make sure that this is in the help!
+