diff options
| author | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2018-03-19 22:33:17 -0400 |
|---|---|---|
| committer | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2018-03-19 22:33:17 -0400 |
| commit | be197be2637b04584f9658da9cf1c7bdfa676c7f (patch) | |
| tree | 3e3215e702e48c32ab11a07c12628dd892eacffa | |
| parent | 0c367e19d71e78a1e60c87c69df8bfb91192d045 (diff) | |
| download | cmd2-git-be197be2637b04584f9658da9cf1c7bdfa676c7f.tar.gz | |
Simplified function that tokenizes for tab completion
| -rw-r--r-- | cmd2.py | 65 |
1 files changed, 45 insertions, 20 deletions
@@ -224,14 +224,19 @@ def set_use_arg_list(val): USE_ARG_LIST = val -def tokenize_line(line, begidx, endidx): +def tokens_for_completion(line, begidx, endidx, preserve_quotes=False): """ Used by tab completion functions to get all tokens through the one being completed This also handles tab-completion within quotes :param line: str - the current input line with leading whitespace removed :param begidx: int - the beginning index of the prefix text :param endidx: int - the ending index of the prefix text - :return: A list of tokens and whether or not the token being completed has an unclosed quote + :param preserve_quotes - if True, then the tokens will be returned still wrapped in whatever quotes + appeared on the command line. This defaults to False since tab completion routines + generally need the tokens unquoted. The only reason to set this to True would + be to check if the token being completed has an unclosed quote. complete() is the + only functions that does this. + :return: A list of tokens """ tokens = [] unclosed_quote = '' @@ -259,11 +264,17 @@ def tokenize_line(line, begidx, endidx): # No tokens were parsed if len(tokens) == 0: - unclosed_quote = '' + return tokens + + if preserve_quotes: + # If the token being completed had an unclosed quote, we need remove the closing quote that was added + if unclosed_quote: + tokens[-1] = tokens[-1][:-1] # Unquote all tokens - for index, cur_token in enumerate(tokens): - tokens[index] = strip_quotes(cur_token) + else: + 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. @@ -278,7 +289,7 @@ def tokenize_line(line, begidx, endidx): if prev_space_index == 0 or prev_space_index == begidx - 1: tokens.append('') - return tokens, unclosed_quote + return tokens # noinspection PyUnusedLocal @@ -293,7 +304,7 @@ def basic_complete(text, line, begidx, endidx, match_against): :return: List[str] - a list of possible tab completions """ # Get all tokens through the one being completed - tokens, unclosed_quote = tokenize_line(line, begidx, endidx) + tokens = tokens_for_completion(line, begidx, endidx) if len(tokens) == 0: return [] @@ -326,7 +337,7 @@ def flag_based_complete(text, line, begidx, endidx, flag_dict, all_else=None): """ # Get all tokens through the one being completed - tokens, unclosed_quote = tokenize_line(line, begidx, endidx) + tokens = tokens_for_completion(line, begidx, endidx) if len(tokens) == 0: return [] @@ -374,7 +385,7 @@ def index_based_complete(text, line, begidx, endidx, index_dict, all_else=None): """ # Get all tokens through the one being completed - tokens, unclosed_quote = tokenize_line(line, begidx, endidx) + tokens = tokens_for_completion(line, begidx, endidx) if len(tokens) == 0: return [] @@ -418,7 +429,7 @@ def path_complete(text, line, begidx, endidx, dir_exe_only=False, dir_only=False """ # Get all tokens through the one being completed - tokens, unclosed_quote = tokenize_line(line, begidx, endidx) + tokens = tokens_for_completion(line, begidx, endidx) if len(tokens) == 0: return [] @@ -444,6 +455,9 @@ def path_complete(text, line, begidx, endidx, dir_exe_only=False, dir_only=False # If the user only entered a '~', then complete it with a slash if completion_token == '~': + # This is a directory, so don't add a space or quote + set_allow_appended_space(False) + set_allow_closing_quote(False) return [os.path.sep] elif completion_token.startswith('~'): @@ -1478,14 +1492,25 @@ class Cmd(cmd.Cmd): if begidx > 0: # Get all tokens through the one being completed - tokens, unclosed_quote = tokenize_line(line, begidx, endidx) + tokens = tokens_for_completion(line, begidx, endidx, preserve_quotes=True) + + # Check if the token being complete has an unclosed quote + token_being_completed = tokens[-1] + unclosed_quote = '' + + if len(token_being_completed) > 1: + first_char = token_being_completed[0] + last_char = token_being_completed[-1] + quotes = ['"', "'"] + + 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 - quotes = ['"', "'"] - prior_char = line[begidx - 1] - if not unclosed_quote and prior_char in quotes: - self.completion_matches = [' '] - return self.completion_matches[state] + # If the cursor is right after a closed quote, then insert a space + prior_char = line[begidx - 1] + if not unclosed_quote and prior_char in quotes: + self.completion_matches = [' '] + return self.completion_matches[state] # Parse the command line command, args, expanded_line = self.parseline(line) @@ -1582,7 +1607,7 @@ class Cmd(cmd.Cmd): subcmd_index = 2 # Get all tokens through the one being completed - tokens, unclosed_quote = tokenize_line(line, begidx, endidx) + tokens = tokens_for_completion(line, begidx, endidx) if len(tokens) == 0: return [] @@ -2425,7 +2450,7 @@ Usage: Usage: unalias [-a] name [name ...] shell_cmd_index = 1 # Get all tokens through the one being completed - tokens, unclosed_quote = tokenize_line(line, begidx, endidx) + tokens = tokens_for_completion(line, begidx, endidx) if len(tokens) == 0: return [] @@ -2498,7 +2523,7 @@ Usage: Usage: unalias [-a] name [name ...] subcmd_index = 1 # Get all tokens through the one being completed - tokens, unclosed_quote = tokenize_line(line, begidx, endidx) + tokens = tokens_for_completion(line, begidx, endidx) if len(tokens) == 0: return [] |
