From bc28141b791b7d524e610db3d09b1b3266f2fc41 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Tue, 20 Mar 2018 00:28:33 -0400 Subject: Adding opening quote with GNU readline --- cmd2.py | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'cmd2.py') diff --git a/cmd2.py b/cmd2.py index 98eb2a88..4e3fdfd8 100644 --- a/cmd2.py +++ b/cmd2.py @@ -1495,13 +1495,13 @@ class Cmd(cmd.Cmd): tokens = tokens_for_completion(line, begidx, endidx, preserve_quotes=True) # Check if the token being complete has an unclosed quote + quotes = ['"', "'"] 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 @@ -1556,6 +1556,52 @@ class Cmd(cmd.Cmd): # Call the completer function self.completion_matches = compfunc(text, line, begidx, endidx) + # Check if we need to add an opening quote + if len(self.completion_matches) > 0: + first_char = token_being_completed[0] + + if first_char not in quotes: + # Get the common prefix of all matches. This is what is added to the token being completed. + common_prefix = os.path.commonprefix(self.completion_matches) + + # 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 + if ' ' in token_being_completed or ' ' in common_prefix: + # Find in the original line on screen where our token starts + starting_index = 0 + for token_index, cur_token in enumerate(tokens): + starting_index = origline.find(cur_token) + if token_index < len(tokens) - 1: + starting_index += len(cur_token) + + # If the token started at begidx, then all we have to do is prepend + # an opening quote to all the completions. Readline will do the rest. + if starting_index == readline.get_begidx(): + self.completion_matches = ['"' + match for match in self.completion_matches] + + # The token started after begidx, therefore we need to manually insert an + # opening quote before the token in the readline buffer. + else: + # GNU readline specific way to insert an opening quote + if readline_lib: + # Get and save the current cursor position + rl_point = ctypes.c_int.in_dll(readline_lib, "rl_point") + orig_rl_point = rl_point.value + + # Move the cursor where the token being completed begins to insert the opening quote + rl_point.value = starting_index + readline.insert_text('"') + + # Restore the cursor 1 past where it was the since we shifted everything + rl_point.value = orig_rl_point + 1 + + # Since we just shifted the whole command line over by one, readline will begin + # inserting the text one spot to the left of where we want it since it still is + # using the original index. Therefore we must prepend the original character that + # is 1 spot before where text begins to make sure it doesn't get erased. + saved_char = token_being_completed[(len(text) + 1) * -1] + self.completion_matches = [saved_char + match for match in self.completion_matches] + # Handle single result if len(self.completion_matches) == 1: str_to_append = '' -- cgit v1.2.1