From 1355ea01b3e7a508a78e0be905de8cdcfd541da6 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Wed, 22 Jun 2016 09:15:32 +0200 Subject: [PATCH] Simplify completions further to eventually get rid of user_context. --- jedi/api/completion.py | 85 ++++++++++++++++++++------------------- test/test_api/test_api.py | 3 +- 2 files changed, 45 insertions(+), 43 deletions(-) diff --git a/jedi/api/completion.py b/jedi/api/completion.py index 9e1b3144..cdc74b4e 100644 --- a/jedi/api/completion.py +++ b/jedi/api/completion.py @@ -64,10 +64,6 @@ class Completion: self._call_signatures_method = call_signatures_method def completions(self, path): - # Dots following an int are not the start of a completion but a float - # literal. - if re.search(r'^\d\.$', path): - return [] completion_parts = helpers.get_completion_parts(path) user_stmt = self._parser.user_stmt_with_whitespace() @@ -112,8 +108,13 @@ class Completion: try: stack = helpers.get_stack_at_position(grammar, self._source, self._module, pos) - except helpers.OnErrorLeaf: - return self._simple_complete(completion_parts) + except helpers.OnErrorLeaf as e: + if e.error_leaf.value == '.': + # After ErrorLeaf's that are dots, we will not do any + # completions since this probably just confuses the user. + return [] + # If we don't have a context, just use global completion. + return self._global_completions() allowed_keywords, allowed_tokens = \ helpers.get_possible_completion_types(grammar, stack) @@ -125,7 +126,7 @@ class Completion: # This means that we actually have to do type inference. symbol_names = list(stack.get_node_names(grammar)) - print(symbol_names) + print('symbolnames',symbol_names) nodes = list(stack.get_nodes()) last_symbol = symbol_names[-1] @@ -149,8 +150,10 @@ class Completion: # No completions for ``with x as foo`` and ``import x as foo``. # Also true for defining names as a class or function. return [] + elif symbol_names[-1] == 'trailer' and '(' != nodes[-1]: + completion_names += self._trailer_completions(completion_parts) else: - completion_names += self._simple_complete(completion_parts) + completion_names += self._global_completions() return completion_names @@ -158,42 +161,40 @@ class Completion: for k in keywords_: yield keywords.keyword(self._evaluator, k).name - def _simple_complete(self, completion_parts): - if not completion_parts.path and not completion_parts.has_dot: - scope = self._parser.user_scope() - if not scope.is_scope(): # Might be a flow (if/while/etc). - scope = scope.get_parent_scope() - names_dicts = global_names_dict_generator( - self._evaluator, - self._evaluator.wrap(scope), - self._pos + def _global_completions(self): + scope = self._parser.user_scope() + if not scope.is_scope(): # Might be a flow (if/while/etc). + scope = scope.get_parent_scope() + names_dicts = global_names_dict_generator( + self._evaluator, + self._evaluator.wrap(scope), + self._pos + ) + completion_names = [] + for names_dict, pos in names_dicts: + names = list(chain.from_iterable(names_dict.values())) + if not names: + continue + completion_names += filter_definition_names( + names, self._parser.user_stmt(), pos ) - completion_names = [] - for names_dict, pos in names_dicts: - names = list(chain.from_iterable(names_dict.values())) - if not names: - continue - completion_names += filter_definition_names( - names, self._parser.user_stmt(), pos - ) - elif inference.get_under_cursor_stmt(self._evaluator, self._parser, - completion_parts.path, self._pos) is None: - return [] - else: - scopes = list(inference.type_inference( - self._evaluator, self._parser, - self._pos, completion_parts.path - )) - completion_names = [] - debug.dbg('possible completion scopes: %s', scopes) - for s in scopes: - names = [] - for names_dict in s.names_dicts(search_global=False): - names += chain.from_iterable(names_dict.values()) + return completion_names - completion_names += filter_definition_names( - names, self._parser.user_stmt() - ) + def _trailer_completions(self, completion_parts): + scopes = list(inference.type_inference( + self._evaluator, self._parser, + self._pos, completion_parts.path + )) + completion_names = [] + debug.dbg('possible completion scopes: %s', scopes) + for s in scopes: + names = [] + for names_dict in s.names_dicts(search_global=False): + names += chain.from_iterable(names_dict.values()) + + completion_names += filter_definition_names( + names, self._parser.user_stmt() + ) return completion_names def _parse_dotted_names(self, nodes): diff --git a/test/test_api/test_api.py b/test/test_api/test_api.py index 926f41a2..a928fbf1 100644 --- a/test/test_api/test_api.py +++ b/test/test_api/test_api.py @@ -62,7 +62,8 @@ def _check_number(source, result='float'): def test_completion_on_number_literals(): # No completions on an int literal (is a float). - assert api.Script('1.').completions() == [] + assert [c.name for c in api.Script('1.').completions()] \ + == ['and', 'if', 'in', 'is', 'not', 'or'] # Multiple points after an int literal basically mean that there's a float # and a call after that.