def get_completions(self, document, complete_event): text_before_cursor = document.text_before_cursor completions = self._completer.autocomplete(text_before_cursor) prompt_completions = list( self._convert_to_prompt_completions(completions, text_before_cursor)) if (not prompt_completions and self._completer.last_option and len(self._completer.cmd_path) == 3): # If we couldn't complete anything from the JSON model # completer and we're on a cli option (e.g --foo), we # can ask the server side completer if it knows anything # about this resource. LOG.debug("No local autocompletions found, trying " "server side completion.") command = self._completer.cmd_path service = command[1] if service == 's3api': # TODO: we need a more generic way to capture renames # of commands. This currently lives in the CLI # customization code. service = 's3' operation = command[2] param = self._completer.arg_metadata.get( self._completer.last_option, {}).get('api_name') if param is not None: LOG.debug( "Trying to retrieve autcompletion for: " "%s, %s, %s", service, operation, param) results = self._server_side_completer\ .retrieve_candidate_values(service, operation, param) LOG.debug("Results for %s, %s, %s: %s", service, operation, param, results) word_before_cursor = text_before_cursor.strip().split()[-1] location = 0 if text_before_cursor[-1] != ' ' and \ word_before_cursor and results: # Filter the results down by fuzzy searching what # the user has provided. results = fuzzy.fuzzy_search(word_before_cursor, results) location = -len(word_before_cursor) if results is not None: for result in results: # Insert at the end yield Completion(result, location, display=result, display_meta='') else: for c in prompt_completions: yield c
def get_completions(self, document, complete_event): text_before_cursor = document.text_before_cursor completions = self._completer.autocomplete(text_before_cursor) prompt_completions = list(self._convert_to_prompt_completions( completions, text_before_cursor)) if (not prompt_completions and self._completer.last_option and len(self._completer.cmd_path) == 3): # If we couldn't complete anything from the JSON model # completer and we're on a cli option (e.g --foo), we # can ask the server side completer if it knows anything # about this resource. LOG.debug("No local autocompletions found, trying " "server side completion.") command = self._completer.cmd_path service = command[1] if service == 's3api': # TODO: we need a more generic way to capture renames # of commands. This currently lives in the CLI # customization code. service = 's3' operation = command[2] param = self._completer.arg_metadata.get( self._completer.last_option, {}).get('api_name') if param is not None: LOG.debug("Trying to retrieve autcompletion for: " "%s, %s, %s", service, operation, param) results = self._server_side_completer\ .retrieve_candidate_values(service, operation, param) LOG.debug("Results for %s, %s, %s: %s", service, operation, param, results) word_before_cursor = text_before_cursor.strip().split()[-1] location = 0 if text_before_cursor[-1] != ' ' and \ word_before_cursor and results: # Filter the results down by fuzzy searching what # the user has provided. results = fuzzy.fuzzy_search(word_before_cursor, results) location = -len(word_before_cursor) if results is not None: for result in results: # Insert at the end yield Completion(result, location, display=result, display_meta='') else: for c in prompt_completions: yield c
def autocomplete(self, line): """Given a line, return a list of suggestions.""" current_length = len(line) self._current_line = line if current_length == 1 and self._last_position > 1: # Reset state. This is likely from a user completing # a previous command. self.reset() elif current_length < self._last_position: # The user has hit backspace. We'll need to check # the current words. return self._handle_backspace() elif not line: return [] elif current_length != self._last_position + 1: return self._complete_from_full_parse() # This position is important. We only update the _last_position # after we've checked the special cases above where that value # matters. self._last_position = len(line) if line and not line.strip(): # Special case, the user hits a space on a new line so # we autocomplete all the top level commands. return self._current['commands'] last_word = line.split()[-1] if last_word in self.arg_metadata or last_word in self._global_options: # The last thing we completed was an argument, record # this as self.last_arg self.last_option = last_word if line[-1] == ' ': # At this point the user has autocompleted a command # or an argument and has hit space. If they've # just completed a command, we need to change the # current context and traverse into the subcommand. # "ec2 " # ^--here, need to traverse into "ec2" # # Otherwise: # "ec2 --no-validate-ssl " # ^-- here, stay on "ec2" context. if not last_word.startswith('-'): next_command = self._current['children'].get(last_word) if next_command is not None: self._current = next_command self._current_name = last_word self.cmd_path.append(self._current_name) elif last_word in self.arg_metadata and \ self.arg_metadata[last_word]['example']: # Then this is an arg with a shorthand example so we'll # suggest that example. return [self.arg_metadata[last_word]['example']] # Even if we don't change context, we still want to # autocomplete all the commands for the current context # in either of the above two cases. return self._current['commands'][:] elif last_word.startswith('-'): # TODO: cache this for the duration of the current context. # We don't need to recompute this until the args are # different. all_args = self._get_all_args() if self.match_fuzzy: return fuzzy_search(last_word, all_args) else: return substring_search(last_word, all_args) if self.match_fuzzy: return fuzzy_search(last_word, self._current['commands']) else: return substring_search(last_word, self._current['commands'])
def test_subsequences(search, corpus, expected): actual = fuzzy_search(search, corpus) assert actual == expected