diff options
author | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2018-03-23 13:16:18 -0400 |
---|---|---|
committer | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2018-03-23 13:16:18 -0400 |
commit | ac64f1b08b87558f24ae3fa2843323db7a81ff7f (patch) | |
tree | 66ff978186ea5a915b3a583343efc7f83f120f52 /cmd2.py | |
parent | 43cc4f7b6d2f7fcc1a27071542e52fc2f2becfbd (diff) | |
download | cmd2-git-ac64f1b08b87558f24ae3fa2843323db7a81ff7f.tar.gz |
Improved token parsing for tab completion
Diffstat (limited to 'cmd2.py')
-rwxr-xr-x | cmd2.py | 36 |
1 files changed, 25 insertions, 11 deletions
@@ -309,11 +309,11 @@ def tokens_for_completion(line, begidx, endidx, preserve_quotes=False): :param begidx: int - the beginning index of the prefix text :param endidx: int - the ending index of the prefix text :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 that is never empty on success or None on error + appeared on the command line. This defaults to False since tab-completion routines + generally need the tokens unquoted. + :return: If successful parsing occurs, then a non-empty list of tokens is returned where the last token + in the list is the one being tab completed. + None is returned if parsing fails due to a malformed line. """ unclosed_quote = '' quotes_to_try = copy.copy(QUOTES) @@ -323,7 +323,18 @@ def tokens_for_completion(line, begidx, endidx, preserve_quotes=False): while True: try: - tokens = shlex.split(tmp_line[:tmp_endidx], posix=POSIX_SHLEX) + # This type of parsing works better than shlex.split() which doesn't seem to treat > as an individual token. + # Use non-POSIX parsing to keep the quotes around the tokens. + parser = shlex.shlex(tmp_line[:tmp_endidx], posix=False) + + # Get the tokens + tokens = [] + while True: + cur_token = parser.get_token() + if cur_token: + tokens.append(cur_token) + else: + break break except ValueError: # ValueError can be caused by missing closing quote @@ -355,13 +366,16 @@ def tokens_for_completion(line, begidx, endidx, preserve_quotes=False): for index, cur_token in enumerate(tokens): tokens[index] = strip_quotes(cur_token) - # Check if we need to append an empty entry as the token being completed + # Check if the cursor is at the end of the line and not within a quoted string 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) - if prev_space_index == 0 or prev_space_index == begidx - 1: + # Get character before the cursor. This math is safe since begidx has + # to be greater than 0 if it equals endidx and there were tokens. + prev_char = line[begidx - 1] + + # If there is a space before the cursor and we are not in a quoted string, then the + # actual token being completed is blank right now. Add this to the token list. + if prev_char == ' ': tokens.append('') return tokens |