diff options
author | Eric Lin <anselor@gmail.com> | 2018-05-02 14:53:20 -0400 |
---|---|---|
committer | Eric Lin <anselor@gmail.com> | 2018-05-02 14:53:20 -0400 |
commit | a95c8a065abeac286c196783393ecc49e4356f54 (patch) | |
tree | b4575eda772450b54620d16c09d4d29c52abdec7 /cmd2/cmd2.py | |
parent | d2d3c2f37d5324b5bc967fe268a92f9d563a3a30 (diff) | |
parent | 148f05d0af66f38c8ba6ca3a5619f50a8bb1b8a9 (diff) | |
download | cmd2-git-a95c8a065abeac286c196783393ecc49e4356f54.tar.gz |
Merge branch 'bash_completion' into bash_to_pyscript
Diffstat (limited to 'cmd2/cmd2.py')
-rwxr-xr-x | cmd2/cmd2.py | 95 |
1 files changed, 41 insertions, 54 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 98adc01f..80fa5601 100755 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -71,10 +71,6 @@ elif rl_type == RlType.GNU: import ctypes from .rl_utils import readline_lib - # Save address that rl_basic_quote_characters is pointing to since we need to override and restore it - rl_basic_quote_characters = ctypes.c_char_p.in_dll(readline_lib, "rl_basic_quote_characters") - orig_rl_basic_quote_characters_addr = ctypes.cast(rl_basic_quote_characters, ctypes.c_void_p).value - # Newer versions of pyperclip are released as a single file, but older versions had a more complicated structure try: from pyperclip.exceptions import PyperclipException @@ -184,21 +180,6 @@ def _which(editor: str) -> Optional[str]: return editor_path -def strip_quotes(arg: str) -> str: - """ Strip outer quotes from a string. - - Applies to both single and double quotes. - - :param arg: string to strip outer quotes from - :return: same string with potentially outer quotes stripped - """ - quote_chars = '"' + "'" - - if len(arg) > 1 and arg[0] == arg[-1] and arg[0] in quote_chars: - arg = arg[1:-1] - return arg - - def parse_quoted_string(cmdline: str) -> List[str]: """Parse a quoted string into a list of arguments.""" if isinstance(cmdline, list): @@ -211,7 +192,7 @@ def parse_quoted_string(cmdline: str) -> List[str]: if not POSIX_SHLEX and STRIP_QUOTES_FOR_NON_POSIX: temp_arglist = [] for arg in lexed_arglist: - temp_arglist.append(strip_quotes(arg)) + temp_arglist.append(utils.strip_quotes(arg)) lexed_arglist = temp_arglist return lexed_arglist @@ -385,7 +366,7 @@ def replace_with_file_contents(fname: str) -> str: """ try: # Any outer quotes are not part of the filename - unquoted_file = strip_quotes(fname[0]) + unquoted_file = utils.strip_quotes(fname[0]) with open(os.path.expanduser(unquoted_file)) as source_file: result = source_file.read() except IOError: @@ -603,11 +584,22 @@ class AddSubmenu(object): try: # copy over any shared attributes self._copy_in_shared_attrs(_self) + + # Reset the submenu's tab completion parameters + submenu.allow_appended_space = True + submenu.allow_closing_quote = True + submenu.display_matches = [] + return _complete_from_cmd(submenu, text, line, begidx, endidx) finally: # copy back original attributes self._copy_out_shared_attrs(_self, original_attributes) + # Pass the submenu's tab completion parameters back up to the menu that called complete() + _self.allow_appended_space = submenu.allow_appended_space + _self.allow_closing_quote = submenu.allow_closing_quote + _self.display_matches = copy.copy(submenu.display_matches) + original_do_help = cmd_obj.do_help original_complete_help = cmd_obj.complete_help @@ -996,6 +988,11 @@ class Cmd(cmd.Cmd): self.allow_closing_quote = True self.display_matches = [] + if rl_type == RlType.GNU: + readline.set_completion_display_matches_hook(self._display_matches_gnu_readline) + elif rl_type == RlType.PYREADLINE: + readline.rl.mode._display_completions = self._display_matches_pyreadline + def tokens_for_completion(self, line, begidx, endidx): """ Used by tab completion functions to get all tokens through the one being completed @@ -1105,7 +1102,7 @@ class Cmd(cmd.Cmd): raw_tokens = initial_tokens # Save the unquoted tokens - tokens = [strip_quotes(cur_token) for cur_token in raw_tokens] + tokens = [utils.strip_quotes(cur_token) for cur_token in raw_tokens] # If the token being completed had an unclosed quote, we need # to remove the closing quote that was added in order for it @@ -2368,38 +2365,33 @@ class Cmd(cmd.Cmd): """ # An almost perfect copy from Cmd; however, the pseudo_raw_input portion # has been split out so that it can be called separately - if self.use_rawinput and self.completekey: + if self.use_rawinput and self.completekey and rl_type != RlType.NONE: # Set up readline for our tab completion needs if rl_type == RlType.GNU: - readline.set_completion_display_matches_hook(self._display_matches_gnu_readline) - # Set GNU readline's rl_basic_quote_characters to NULL so it won't automatically add a closing quote # We don't need to worry about setting rl_completion_suppress_quote since we never declared # rl_completer_quote_characters. - rl_basic_quote_characters.value = None + basic_quote_characters = ctypes.c_char_p.in_dll(readline_lib, "rl_basic_quote_characters") + old_basic_quote_characters = ctypes.cast(basic_quote_characters, ctypes.c_void_p).value + basic_quote_characters.value = None - elif rl_type == RlType.PYREADLINE: - readline.rl.mode._display_completions = self._display_matches_pyreadline + old_completer = readline.get_completer() + old_delims = readline.get_completer_delims() + readline.set_completer(self.complete) - try: - self.old_completer = readline.get_completer() - self.old_delims = readline.get_completer_delims() - readline.set_completer(self.complete) + # Break words on whitespace and quotes when tab completing + completer_delims = " \t\n" + ''.join(constants.QUOTES) - # Break words on whitespace and quotes when tab completing - completer_delims = " \t\n" + ''.join(constants.QUOTES) + if self.allow_redirection: + # If redirection is allowed, then break words on those characters too + completer_delims += ''.join(constants.REDIRECTION_CHARS) - if self.allow_redirection: - # If redirection is allowed, then break words on those characters too - completer_delims += ''.join(constants.REDIRECTION_CHARS) + readline.set_completer_delims(completer_delims) - readline.set_completer_delims(completer_delims) + # Enable tab completion + readline.parse_and_bind(self.completekey + ": complete") - # Enable tab completion - readline.parse_and_bind(self.completekey + ": complete") - except NameError: - pass stop = None try: while not stop: @@ -2423,19 +2415,15 @@ class Cmd(cmd.Cmd): # Run the command along with all associated pre and post hooks stop = self.onecmd_plus_hooks(line) finally: - if self.use_rawinput and self.completekey: + if self.use_rawinput and self.completekey and rl_type != RlType.NONE: # Restore what we changed in readline - try: - readline.set_completer(self.old_completer) - readline.set_completer_delims(self.old_delims) - except NameError: - pass + readline.set_completer(old_completer) + readline.set_completer_delims(old_delims) if rl_type == RlType.GNU: readline.set_completion_display_matches_hook(None) - rl_basic_quote_characters.value = orig_rl_basic_quote_characters_addr - + basic_quote_characters.value = old_basic_quote_characters elif rl_type == RlType.PYREADLINE: readline.rl.mode._display_completions = orig_pyreadline_display @@ -2781,7 +2769,7 @@ Usage: Usage: unalias [-a] name [name ...] set_parser = ACArgumentParser(formatter_class=argparse.RawTextHelpFormatter) set_parser.add_argument('-a', '--all', action='store_true', help='display read-only settings as well') set_parser.add_argument('-l', '--long', action='store_true', help='describe function of parameter') - set_parser.add_argument('settable', nargs=(0,2), help='[param_name] [value]') + set_parser.add_argument('settable', nargs=(0, 2), help='[param_name] [value]') @with_argparser(set_parser) def do_set(self, args): @@ -2838,7 +2826,7 @@ Usage: Usage: unalias [-a] name [name ...] # an unclosed quote, so we only need to check the first character. first_char = tokens[index][0] if first_char in constants.QUOTES: - tokens[index] = strip_quotes(tokens[index]) + tokens[index] = utils.strip_quotes(tokens[index]) tokens[index] = os.path.expanduser(tokens[index]) @@ -2862,7 +2850,6 @@ Usage: Usage: unalias [-a] name [name ...] index_dict = {1: self.shell_cmd_complete} return self.index_based_complete(text, line, begidx, endidx, index_dict, self.path_complete) - # noinspection PyBroadException def do_py(self, arg): """ @@ -3356,7 +3343,7 @@ class ParserManager: ignore=do_not_parse)('pipeTo')) + \ pyparsing.Optional(output_destination_parser + pyparsing.SkipTo(string_end, ignore=do_not_parse). - setParseAction(lambda x: strip_quotes(x[0].strip()))('outputTo')) + setParseAction(lambda x: utils.strip_quotes(x[0].strip()))('outputTo')) multilineCommand.setParseAction(lambda x: x[0]) oneline_command.setParseAction(lambda x: x[0]) |