summaryrefslogtreecommitdiff
path: root/cmd2/argparse_completer.py
diff options
context:
space:
mode:
authorKevin Van Brunt <kmvanbrunt@gmail.com>2019-08-12 18:04:16 -0400
committerKevin Van Brunt <kmvanbrunt@gmail.com>2019-08-12 18:04:16 -0400
commit474af6f290b188e9161c0a47689262752ba79843 (patch)
tree2d193c2743e3cff69b29c25f08c71822afbbb962 /cmd2/argparse_completer.py
parent4b4d723f99b17399f7d1f69cf1bf205b104ec85c (diff)
downloadcmd2-git-474af6f290b188e9161c0a47689262752ba79843.tar.gz
Replaced AutoCompleter._positional_completers since an ArgumentParser can only have one level of subcommands
No longer creating AutoCompleters for all subcommands each time tab is pressed
Diffstat (limited to 'cmd2/argparse_completer.py')
-rw-r--r--cmd2/argparse_completer.py66
1 files changed, 29 insertions, 37 deletions
diff --git a/cmd2/argparse_completer.py b/cmd2/argparse_completer.py
index a877841a..d373a822 100644
--- a/cmd2/argparse_completer.py
+++ b/cmd2/argparse_completer.py
@@ -105,10 +105,7 @@ class AutoCompleter(object):
self._flags = [] # all flags in this command
self._flag_to_action = {} # maps flags to the argparse action object
self._positional_actions = [] # actions for positional arguments (by position index)
-
- # maps action to subcommand autocompleter:
- # action -> dict(sub_command -> completer)
- self._positional_completers = {}
+ self._subcommand_action = None # this will be set if self._parser has subcommands
# Start digging through the argparse structures.
# _actions is the top level container of parameter definitions
@@ -123,15 +120,9 @@ class AutoCompleter(object):
# Otherwise this is a positional parameter
else:
self._positional_actions.append(action)
-
+ # Check if this action defines subcommands
if isinstance(action, argparse._SubParsersAction):
- sub_completers = {}
-
- # Create an AutoCompleter for each subcommand of this command
- for subcmd in action.choices:
- sub_completers[subcmd] = AutoCompleter(action.choices[subcmd], cmd2_app)
-
- self._positional_completers[action] = sub_completers
+ self._subcommand_action = action
def complete_command(self, tokens: List[str], text: str, line: str, begidx: int, endidx: int) -> List[str]:
"""Complete the command using the argparse metadata and provided argument dictionary"""
@@ -259,11 +250,10 @@ class AutoCompleter(object):
action = self._positional_actions[pos_index]
# Are we at a subcommand? If so, forward to the matching completer
- if isinstance(action, argparse._SubParsersAction):
- sub_completers = self._positional_completers[action]
- if token in sub_completers:
- return sub_completers[token].complete_command(tokens[token_index:], text, line,
- begidx, endidx)
+ if action == self._subcommand_action:
+ if token in self._subcommand_action.choices:
+ completer = AutoCompleter(self._subcommand_action.choices[token], self._cmd2_app)
+ return completer.complete_command(tokens[token_index:], text, line, begidx, endidx)
else:
# Invalid subcommand entered, so no way to complete remaining tokens
return []
@@ -404,7 +394,7 @@ class AutoCompleter(object):
return completions
- def complete_command_help(self, tokens: List[str], text: str, line: str, begidx: int, endidx: int) -> List[str]:
+ def complete_subcommand_help(self, tokens: List[str], text: str, line: str, begidx: int, endidx: int) -> List[str]:
"""
Supports cmd2's help command in the completion of subcommand names
:param tokens: command line tokens
@@ -414,31 +404,33 @@ class AutoCompleter(object):
:param endidx: the ending index of the prefix text
:return: List of subcommand completions
"""
- for token_index, token in enumerate(tokens[1:], start=1):
- if self._positional_completers:
- # For now argparse only allows 1 subcommand group per level
- # so this will only loop once.
- for completers in self._positional_completers.values():
- if token in completers:
- return completers[token].complete_command_help(tokens[token_index:], text,
- line, begidx, endidx)
- else:
- return utils.basic_complete(text, line, begidx, endidx, completers.keys())
+ # If our parser has subcommands, we must examine the tokens and check if any reference one.
+ # If so, we will let the subcommand's parser handle the rest of the tokens via another AutoCompleter.
+ if self._subcommand_action is not None:
+ for token_index, token in enumerate(tokens[1:], start=1):
+ if token in self._subcommand_action.choices:
+ completer = AutoCompleter(self._subcommand_action.choices[token], self._cmd2_app)
+ return completer.complete_subcommand_help(tokens[token_index:], text, line, begidx, endidx)
+ elif token_index == len(tokens) - 1:
+ # Since this is the last token, we will attempt to complete it
+ return utils.basic_complete(text, line, begidx, endidx, self._subcommand_action.choices)
+
return []
def format_help(self, tokens: List[str]) -> str:
"""
- Retrieve help text of a subcommand
+ Supports cmd2's help command in the retrieval of help text
:param tokens: command line tokens
- :return: help text of the subcommand being queried
+ :return: help text of the commmand being queried
"""
- for token_index, token in enumerate(tokens[1:], start=1):
- if self._positional_completers:
- # For now argparse only allows 1 subcommand 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[token_index:])
+ # If our parser has subcommands, we must examine the tokens and check if any reference one.
+ # If so, we will let the subcommand's parser handle the rest of the tokens via another AutoCompleter.
+ if self._subcommand_action is not None:
+ for token_index, token in enumerate(tokens[1:], start=1):
+ if token in self._subcommand_action.choices:
+ completer = AutoCompleter(self._subcommand_action.choices[token], self._cmd2_app)
+ return completer.format_help(tokens[token_index:])
+
return self._parser.format_help()
def _complete_for_arg(self, arg: argparse.Action,