summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Lin <anselor@gmail.com>2018-09-23 20:57:47 +0000
committerEric Lin <anselor@gmail.com>2018-09-23 20:57:47 +0000
commit7cc94ab98c007210b344fbb1af965570fae63959 (patch)
tree80fe9c72f4a2512337710a68bc0ef67054d23375
parentdbe485957b421f6fd973b3a493de7b264b363d54 (diff)
downloadcmd2-git-7cc94ab98c007210b344fbb1af965570fae63959.tar.gz
Added the the ability to format help to the AutoCompleter to support sub-command specific help lookup.
-rwxr-xr-xcmd2/argparse_completer.py12
-rw-r--r--cmd2/cmd2.py13
-rwxr-xr-xexamples/subcommands.py38
3 files changed, 54 insertions, 9 deletions
diff --git a/cmd2/argparse_completer.py b/cmd2/argparse_completer.py
index 03ff4375..dc9baf7a 100755
--- a/cmd2/argparse_completer.py
+++ b/cmd2/argparse_completer.py
@@ -510,6 +510,18 @@ class AutoCompleter(object):
return self.basic_complete(text, line, begidx, endidx, completers.keys())
return []
+ def format_help(self, tokens: List[str]) -> str:
+ """Supports the completion of sub-commands for commands through the cmd2 help command."""
+ for idx, token in enumerate(tokens):
+ if idx >= self._token_start_index:
+ if self._positional_completers:
+ # For now argparse only allows 1 sub-command group per level
+ # so this will only loop once.
+ for completers in self._positional_completers.values():
+ if token in completers:
+ return completers[token].format_help(tokens)
+ return self._parser.format_help()
+
@staticmethod
def _process_action_nargs(action: argparse.Action, arg_state: _ArgumentState) -> None:
if isinstance(action, _RangeAction):
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index 546b03cd..26cfbf4a 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -1609,7 +1609,7 @@ class Cmd(cmd.Cmd):
try:
cmd_func = getattr(self, 'do_' + tokens[cmd_index])
parser = getattr(cmd_func, 'argparser')
- completer = AutoCompleter(parser)
+ completer = AutoCompleter(parser, cmd2_app=self)
matches = completer.complete_command_help(tokens[1:], text, line, begidx, endidx)
except AttributeError:
pass
@@ -2347,14 +2347,9 @@ Usage: Usage: unalias [-a] name [name ...]
# Check to see if this function was decorated with an argparse ArgumentParser
func = getattr(self, funcname)
if hasattr(func, 'argparser'):
- # Function has an argparser, so get help based on all the arguments in case there are sub-commands
- new_arglist = arglist[1:]
- new_arglist.append('-h')
-
- # Temporarily redirect all argparse output to both sys.stdout and sys.stderr to self.stdout
- with redirect_stdout(self.stdout):
- with redirect_stderr(self.stdout):
- func(new_arglist)
+ completer = AutoCompleter(getattr(func, 'argparser'), cmd2_app=self)
+
+ self.poutput(completer.format_help(arglist))
else:
# No special behavior needed, delegate to cmd base class do_help()
cmd.Cmd.do_help(self, funcname[3:])
diff --git a/examples/subcommands.py b/examples/subcommands.py
index 9d51fbee..02b06412 100755
--- a/examples/subcommands.py
+++ b/examples/subcommands.py
@@ -37,6 +37,33 @@ sport_arg = parser_sport.add_argument('sport', help='Enter name of a sport')
setattr(sport_arg, 'arg_choices', sport_item_strs)
+# create the top-level parser for the alternate command
+# The alternate command doesn't provide its own help flag
+base2_parser = argparse.ArgumentParser(prog='alternate', add_help=False)
+base2_subparsers = base2_parser.add_subparsers(title='subcommands', help='subcommand help')
+
+# create the parser for the "foo" subcommand
+parser_foo2 = base2_subparsers.add_parser('foo', help='foo help')
+parser_foo2.add_argument('-x', type=int, default=1, help='integer')
+parser_foo2.add_argument('y', type=float, help='float')
+parser_foo2.add_argument('input_file', type=str, help='Input File')
+
+# create the parser for the "bar" subcommand
+parser_bar2 = base2_subparsers.add_parser('bar', help='bar help')
+
+bar2_subparsers = parser_bar2.add_subparsers(title='layer3', help='help for 3rd layer of commands')
+parser_bar2.add_argument('z', help='string')
+
+bar2_subparsers.add_parser('apple', help='apple help')
+bar2_subparsers.add_parser('artichoke', help='artichoke help')
+bar2_subparsers.add_parser('cranberries', help='cranberries help')
+
+# create the parser for the "sport" subcommand
+parser_sport2 = base2_subparsers.add_parser('sport', help='sport help')
+sport2_arg = parser_sport2.add_argument('sport', help='Enter name of a sport')
+setattr(sport2_arg, 'arg_choices', sport_item_strs)
+
+
class SubcommandsExample(cmd2.Cmd):
"""
Example cmd2 application where we a base command which has a couple subcommands
@@ -74,6 +101,17 @@ class SubcommandsExample(cmd2.Cmd):
# No subcommand was provided, so call help
self.do_help('base')
+ @cmd2.with_argparser(base2_parser)
+ def do_alternate(self, args):
+ """Alternate command help"""
+ func = getattr(args, 'func', None)
+ if func is not None:
+ # Call whatever subcommand function was selected
+ func(self, args)
+ else:
+ # No subcommand was provided, so call help
+ self.do_help('alternate')
+
if __name__ == '__main__':
app = SubcommandsExample()