diff options
| author | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2018-03-20 23:23:27 -0400 |
|---|---|---|
| committer | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2018-03-20 23:23:27 -0400 |
| commit | b95a21fd9d4ea715edb1b1a913e6e85e0f5e3ade (patch) | |
| tree | 5a695552d347509055f94e7a44b59032018c7efe | |
| parent | 8f91bf21b65b68674f5a9bbed1ebd5ff44a40df0 (diff) | |
| download | cmd2-git-b95a21fd9d4ea715edb1b1a913e6e85e0f5e3ade.tar.gz | |
Made sure quoting of a token works on Python 2.7.
| -rwxr-xr-x | cmd2.py | 48 |
1 files changed, 28 insertions, 20 deletions
@@ -27,6 +27,7 @@ import atexit import cmd import codecs import collections +import copy import datetime import functools import glob @@ -192,6 +193,8 @@ def set_completion_defaults(): suppress_quote.value = 1 +QUOTES = ['"', "'"] + # BrokenPipeError and FileNotFoundError exist only in Python 3. Use IOError for Python 2. if six.PY3: BROKEN_PIPE_ERROR = BrokenPipeError @@ -277,7 +280,7 @@ def tokens_for_completion(line, begidx, endidx, preserve_quotes=False): """ tokens = [] unclosed_quote = '' - quotes_to_try = ['"', "'"] + quotes_to_try = copy.copy(QUOTES) tmp_line = line[:endidx] tmp_endidx = endidx @@ -313,13 +316,9 @@ def tokens_for_completion(line, begidx, endidx, preserve_quotes=False): for index, cur_token in enumerate(tokens): tokens[index] = strip_quotes(cur_token) - # If begidx is equal to endidx, then the readline text variable is blank. - # Check if begidx is preceded by a string. This can happen in things like paths. - # For example, in "/home/user/" begidx would be the index right after the last slash given - # how readline separation characters work. If begidx is preceded by a string, then the final - # token in tokens is the token being completed. If begidx is not preceded by a string, then - # we need to add a blank entry to tokens to be the token being completed. + # Check if we need to append an empty entry as the token being completed if begidx == endidx and not unclosed_quote: + # If begidx is the first character in the line, or is preceded by a space # then we need to add the blank entry to tokens. prev_space_index = max(line.rfind(' ', 0, begidx), 0) @@ -340,6 +339,10 @@ def basic_complete(text, line, begidx, endidx, match_against): :param match_against: iterable - the list being matched against :return: List[str] - a list of possible tab completions """ + # Make sure we were given an Iterable with items to match against + if not isinstance(match_against, collections.Iterable) or len(match_against) == 0: + return [] + # Get all tokens through the one being completed tokens = tokens_for_completion(line, begidx, endidx) if len(tokens) == 0: @@ -1652,7 +1655,6 @@ class Cmd(cmd.Cmd): tokens = tokens_for_completion(line, begidx, endidx, preserve_quotes=True) # Get the status of quotes in the token being completed - quotes = ['"', "'"] completion_token = tokens[-1] unclosed_quote = '' @@ -1661,13 +1663,13 @@ class Cmd(cmd.Cmd): last_char = completion_token[-1] # Check if the token being completed has an unclosed quote - if first_char in quotes and first_char != last_char: + if first_char in QUOTES and first_char != last_char: unclosed_quote = first_char # If the cursor is right after a closed quote, then insert a space else: prior_char = line[begidx - 1] - if not unclosed_quote and prior_char in quotes: + if not unclosed_quote and prior_char in QUOTES: self.completion_matches = [' '] return self.completion_matches[state] @@ -1703,7 +1705,7 @@ class Cmd(cmd.Cmd): common_prefix = os.path.commonprefix(self.completion_matches) # Check if we need to add an opening quote - if len(completion_token) == 0 or completion_token[0] not in quotes: + if len(completion_token) == 0 or completion_token[0] not in QUOTES: # If anything that will be in the token being completed contains a space, then # we must add an opening quote to the token on screen @@ -1847,9 +1849,7 @@ class Cmd(cmd.Cmd): # Match subcommands if any exist command = tokens[cmd_index] - subcommands = self.get_subcommands(command) - if subcommands is not None: - completions = [cur_sub for cur_sub in subcommands if cur_sub.startswith(text)] + completions = basic_complete(text, line, begidx, endidx, self.get_subcommands(command)) completions.sort() return completions @@ -2655,12 +2655,20 @@ Usage: Usage: unalias [-a] name [name ...] self.perror(err, traceback_war=False) return - for index, token in enumerate(tokens): - tokens[index] = strip_quotes(tokens[index]) - tokens[index] = os.path.expandvars(tokens[index]) - tokens[index] = os.path.expanduser(tokens[index]) - if six.PY3: - tokens[index] = shlex.quote(tokens[index]) + for index, _ in enumerate(tokens): + if len(tokens[index]) > 0: + # Check if the token is quoted. Since shlex.split() passed, there isn't + # an unclosed quote, so we only need to check the first character. + first_char = tokens[index][0] + if first_char in QUOTES: + tokens[index] = strip_quotes(tokens[index]) + + tokens[index] = os.path.expandvars(tokens[index]) + tokens[index] = os.path.expanduser(tokens[index]) + + # Restore the quotes + if first_char in QUOTES: + tokens[index] = first_char + tokens[index] + first_char expanded_command = ' '.join(tokens) proc = subprocess.Popen(expanded_command, stdout=self.stdout, shell=True) |
