summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd2/argparse_completer.py47
-rw-r--r--cmd2/argparse_custom.py8
-rw-r--r--tests/test_argparse_completer.py91
3 files changed, 120 insertions, 26 deletions
diff --git a/cmd2/argparse_completer.py b/cmd2/argparse_completer.py
index 0c4cafde..1a8dd473 100644
--- a/cmd2/argparse_completer.py
+++ b/cmd2/argparse_completer.py
@@ -454,16 +454,28 @@ class AutoCompleter(object):
# Here we're done parsing all of the prior arguments. We know what the next argument is.
- completion_results = []
-
# if we don't have a flag to populate with arguments and the last token starts with
# a flag prefix then we'll complete the list of flag options
- if not flag_arg.needed and len(tokens[-1]) > 0 and tokens[-1][0] in self._parser.prefix_chars and \
- not skip_remaining_flags:
- return utils.basic_complete(text, line, begidx, endidx,
- [flag for flag in self._flags if flag not in matched_flags])
+ if not flag_arg.needed and len(tokens[-1]) > 0 and \
+ tokens[-1][0] in self._parser.prefix_chars and not skip_remaining_flags:
+
+ # Build a list of flags that can be tab completed
+ match_against = []
+
+ for flag in self._flags:
+ # Make sure this flag hasn't already been used
+ if flag not in matched_flags:
+ # Make sure this flag isn't considered hidden
+ action = self._flag_to_action[flag]
+ if action.help != argparse.SUPPRESS:
+ match_against.append(flag)
+
+ return utils.basic_complete(text, line, begidx, endidx, match_against)
+
+ completion_results = []
+
# we're not at a positional argument, see if we're in a flag argument
- elif not current_is_positional:
+ if not current_is_positional:
if flag_action is not None:
consumed = consumed_arg_values[flag_action.dest]\
if flag_action.dest in consumed_arg_values else []
@@ -614,35 +626,26 @@ class AutoCompleter(object):
@staticmethod
def _print_arg_hint(arg: argparse.Action) -> None:
"""Print argument hint to the terminal when tab completion results in no results"""
- # is hinting disabled for this argument?
+
+ # Check if hinting is disabled
suppress_hint = getattr(arg, ATTR_SUPPRESS_TAB_HINT, False)
- if suppress_hint:
+ if suppress_hint or arg.help == argparse.SUPPRESS:
return
# Check if this is a flag
if arg.option_strings:
flags = ', '.join(arg.option_strings)
- param = ''
- if arg.nargs is None or arg.nargs != 0:
- param += ' ' + str(arg.dest).upper()
-
+ param = ' ' + str(arg.dest).upper()
prefix = '{}{}'.format(flags, param)
# Otherwise this is a positional
else:
prefix = '{}'.format(str(arg.dest).upper())
- if not arg.help or arg.help == argparse.SUPPRESS:
- help_text = ''
- else:
- help_text = arg.help
-
- # is there anything to print for this parameter?
- if not prefix and not help_text:
- return
-
prefix = ' {0: <{width}} '.format(prefix, width=20)
pref_len = len(prefix)
+
+ help_text = '' if arg.help is None else arg.help
help_lines = help_text.splitlines()
if len(help_lines) == 1:
diff --git a/cmd2/argparse_custom.py b/cmd2/argparse_custom.py
index 6361bdb9..b05ca6ed 100644
--- a/cmd2/argparse_custom.py
+++ b/cmd2/argparse_custom.py
@@ -59,7 +59,7 @@ def _add_argument_wrapper(self, *args,
choices_method: Optional[Callable[[Any], Iterable[Any]]] = None,
completer_function: Optional[Callable[[str, str, int, int], List[str]]] = None,
completer_method: Optional[Callable[[Any, str, str, int, int], List[str]]] = None,
- suppress_hint: bool = False,
+ suppress_tab_hint: bool = False,
descriptive_header: Optional[str] = None,
**kwargs) -> argparse.Action:
"""
@@ -77,8 +77,8 @@ def _add_argument_wrapper(self, *args,
:param choices_method: cmd2-app method that provides choices for this argument
:param completer_function: tab-completion function that provides choices for this argument
:param completer_method: cmd2-app tab-completion method that provides choices for this argument
- :param suppress_hint: when AutoCompleter has no choices to show during tab completion, it displays the current
- argument's help text as a hint. Set this to True to suppress the hint. Defaults to False.
+ :param suppress_tab_hint: when AutoCompleter has no choices to show during tab completion, it displays the current
+ argument's help text as a hint. Set this to True to suppress the hint. Defaults to False.
:param descriptive_header: if the provided choices are CompletionItems, then this header will display
during tab completion. Defaults to None.
@@ -152,7 +152,7 @@ def _add_argument_wrapper(self, *args,
setattr(new_arg, ATTR_CHOICES_CALLABLE,
ChoicesCallable(is_method=True, is_completer=True, to_call=completer_method))
- setattr(new_arg, ATTR_SUPPRESS_TAB_HINT, suppress_hint)
+ setattr(new_arg, ATTR_SUPPRESS_TAB_HINT, suppress_tab_hint)
setattr(new_arg, ATTR_DESCRIPTIVE_COMPLETION_HEADER, descriptive_header)
return new_arg
diff --git a/tests/test_argparse_completer.py b/tests/test_argparse_completer.py
index c73290e0..a3fa6a59 100644
--- a/tests/test_argparse_completer.py
+++ b/tests/test_argparse_completer.py
@@ -104,6 +104,21 @@ class AutoCompleteTester(cmd2.Cmd):
def do_completer(self, args: argparse.Namespace) -> None:
pass
+ ############################################################################################################
+ # Begin code related to testing tab hints
+ ############################################################################################################
+ hint_parser = Cmd2ArgParser()
+ hint_parser.add_argument('-f', '--flag', help='a flag arg')
+ hint_parser.add_argument('-s', '--suppressed_help', help=argparse.SUPPRESS)
+ hint_parser.add_argument('-t', '--suppressed_hint', help='a flag arg', suppress_tab_hint=True)
+
+ hint_parser.add_argument('hint_pos', help='here is a hint\nwith new lines')
+ hint_parser.add_argument('no_help_pos')
+
+ @with_argparser(hint_parser)
+ def do_hint(self, args: argparse.Namespace) -> None:
+ pass
+
@pytest.fixture
def ac_app():
@@ -263,6 +278,82 @@ def test_completion_items_default_header(ac_app):
assert DEFAULT_DESCRIPTIVE_HEADER in ac_app.completion_header
+def test_autocomp_hint_flag(ac_app, capsys):
+ text = ''
+ line = 'hint --flag {}'.format(text)
+ endidx = len(line)
+ begidx = endidx - len(text)
+
+ first_match = complete_tester(text, line, begidx, endidx, ac_app)
+ out, err = capsys.readouterr()
+
+ assert first_match is None
+ assert out == '''
+Hint:
+ -f, --flag FLAG a flag arg
+
+'''
+
+
+def test_autocomp_hint_suppressed_help(ac_app, capsys):
+ text = ''
+ line = 'hint --suppressed_help {}'.format(text)
+ endidx = len(line)
+ begidx = endidx - len(text)
+
+ first_match = complete_tester(text, line, begidx, endidx, ac_app)
+ out, err = capsys.readouterr()
+
+ assert first_match is None
+ assert not out
+
+
+def test_autocomp_hint_suppressed_hint(ac_app, capsys):
+ text = ''
+ line = 'hint --suppressed_hint {}'.format(text)
+ endidx = len(line)
+ begidx = endidx - len(text)
+
+ first_match = complete_tester(text, line, begidx, endidx, ac_app)
+ out, err = capsys.readouterr()
+
+ assert first_match is None
+ assert not out
+
+
+def test_autocomp_hint_pos(ac_app, capsys):
+ text = ''
+ line = 'hint {}'.format(text)
+ endidx = len(line)
+ begidx = endidx - len(text)
+
+ first_match = complete_tester(text, line, begidx, endidx, ac_app)
+ out, err = capsys.readouterr()
+
+ assert first_match is None
+ assert out == '''
+Hint:
+ HINT_POS here is a hint
+ with new lines
+
+'''
+
+def test_autocomp_hint_no_help(ac_app, capsys):
+ text = ''
+ line = 'hint foo {}'.format(text)
+ endidx = len(line)
+ begidx = endidx - len(text)
+
+ first_match = complete_tester(text, line, begidx, endidx, ac_app)
+ out, err = capsys.readouterr()
+
+ assert first_match is None
+ assert not out == '''
+Hint:
+ NO_HELP_POS
+
+'''
+
# def test_autcomp_hint_in_narg_range(cmd2_app, capsys):
# text = ''
# line = 'suggest -d 2 {}'.format(text)