diff options
-rwxr-xr-x | cmd2.py | 27 | ||||
-rw-r--r-- | tests/test_completion.py | 54 |
2 files changed, 59 insertions, 22 deletions
@@ -1330,8 +1330,8 @@ class Cmd(cmd.Cmd): for cur_initial_token in initial_tokens: - # Keep empty and quoted tokens - if len(cur_initial_token) == 0 or cur_initial_token[0] in QUOTES: + # Save tokens up to 1 character in length or quoted tokens. No need to parse these. + if len(cur_initial_token) <= 1 or cur_initial_token[0] in QUOTES: raw_tokens.append(cur_initial_token) continue @@ -2068,20 +2068,23 @@ class Cmd(cmd.Cmd): self.completion_matches = [] return None - # Check if we need to remove text from the beginning of tab completions - if text_to_remove: - self.completion_matches = [m.replace(text_to_remove, '', 1) for m in self.completion_matches] - - # Check if we need to restore a shortcut in the tab completions - if shortcut_to_restore: + if text_to_remove or shortcut_to_restore: # If self.display_matches is empty, then set it to self.completion_matches - # before we restore the shortcut so the tab completion suggestions that display to - # the user don't have the shortcut character. + # before we alter them. That way the suggestions will reflect how we parsed + # the token being completed and not how readline did. if len(self.display_matches) == 0: self.display_matches = self.completion_matches - # Prepend all tab completions with the shortcut so it doesn't get erased from the command line - self.completion_matches = [shortcut_to_restore + match for match in self.completion_matches] + # Check if we need to remove text from the beginning of tab completions + if text_to_remove: + self.completion_matches = \ + [m.replace(text_to_remove, '', 1) for m in self.completion_matches] + + # Check if we need to restore a shortcut in the tab completions + # so it doesn't get erased from the command line + if shortcut_to_restore: + self.completion_matches = \ + [shortcut_to_restore + match for match in self.completion_matches] # Check if the token being completed has an unclosed quote if len(raw_completion_token) == 1: diff --git a/tests/test_completion.py b/tests/test_completion.py index 5817334e..8c2fd55d 100644 --- a/tests/test_completion.py +++ b/tests/test_completion.py @@ -177,18 +177,27 @@ def test_cmd2_help_completion_nomatch(cmd2_app): assert cmd2_app.complete_help(text, line, begidx, endidx) == [] -def test_shell_command_completion(cmd2_app): +def test_shell_command_completion_shortcut(cmd2_app): + # Made sure ! runs a shell command and all matches start with ! since there + # isn't a space between ! and the shell command. Display matches won't + # begin with the !. if sys.platform == "win32": - text = 'calc' - expected = ['calc.exe'] + text = '!calc' + expected = ['!calc.exe '] + expected_display = ['calc.exe'] else: - text = 'egr' - expected = ['egrep'] + text = '!egr' + expected = ['!egrep '] + expected_display = ['egrep'] - line = 'shell {}'.format(text) + line = text endidx = len(line) - begidx = endidx - len(text) - assert cmd2_app.complete_shell(text, line, begidx, endidx) == expected + begidx = 0 + + first_match = complete_tester(text, line, begidx, endidx, cmd2_app) + assert first_match is not None and \ + cmd2_app.completion_matches == expected and \ + cmd2_app.display_matches == expected_display def test_shell_command_completion_doesnt_match_wildcards(cmd2_app): if sys.platform == "win32": @@ -742,7 +751,7 @@ def test_cmd2_help_subcommand_completion_nomatch(sc_app): def test_subcommand_tab_completion(sc_app): # This makes sure the correct completer for the sport subcommand is called text = 'Foot' - line = 'base sport Foot' + line = 'base sport {}'.format(text) endidx = len(line) begidx = endidx - len(text) @@ -755,12 +764,37 @@ def test_subcommand_tab_completion_with_no_completer(sc_app): # This tests what happens when a subcommand has no completer # In this case, the foo subcommand has no completer defined text = 'Foot' - line = 'base foo Foot' + line = 'base foo {}'.format(text) + endidx = len(line) + begidx = endidx - len(text) + + first_match = complete_tester(text, line, begidx, endidx, sc_app) + assert first_match is None + +def test_subcommand_tab_completion_add_quote(sc_app): + # This makes sure an opening quote is added to the readline line buffer + text = 'Space' + line = 'base sport {}'.format(text) endidx = len(line) begidx = endidx - len(text) first_match = complete_tester(text, line, begidx, endidx, sc_app) + + # No matches are returned when an opening quote is added to the screen assert first_match is None + assert readline.get_line_buffer() == 'base sport "Space Ball" ' + +def test_subcommand_tab_completion_space_in_text(sc_app): + text = 'B' + line = 'base sport "Space {}'.format(text) + endidx = len(line) + begidx = endidx - len(text) + + first_match = complete_tester(text, line, begidx, endidx, sc_app) + + assert first_match is not None and \ + sc_app.completion_matches == ['Ball" '] and \ + sc_app.display_matches == ['Space Ball'] class SecondLevel(cmd2.Cmd): """To be used as a second level command class. """ |