1
0
forked from VimPlug/jedi

Simplify completions further to eventually get rid of user_context.

This commit is contained in:
Dave Halter
2016-06-22 09:15:32 +02:00
parent 80aa9ad079
commit 1355ea01b3
2 changed files with 45 additions and 43 deletions

View File

@@ -64,10 +64,6 @@ class Completion:
self._call_signatures_method = call_signatures_method self._call_signatures_method = call_signatures_method
def completions(self, path): 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) completion_parts = helpers.get_completion_parts(path)
user_stmt = self._parser.user_stmt_with_whitespace() user_stmt = self._parser.user_stmt_with_whitespace()
@@ -112,8 +108,13 @@ class Completion:
try: try:
stack = helpers.get_stack_at_position(grammar, self._source, self._module, pos) stack = helpers.get_stack_at_position(grammar, self._source, self._module, pos)
except helpers.OnErrorLeaf: except helpers.OnErrorLeaf as e:
return self._simple_complete(completion_parts) 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 = \ allowed_keywords, allowed_tokens = \
helpers.get_possible_completion_types(grammar, stack) helpers.get_possible_completion_types(grammar, stack)
@@ -125,7 +126,7 @@ class Completion:
# This means that we actually have to do type inference. # This means that we actually have to do type inference.
symbol_names = list(stack.get_node_names(grammar)) symbol_names = list(stack.get_node_names(grammar))
print(symbol_names) print('symbolnames',symbol_names)
nodes = list(stack.get_nodes()) nodes = list(stack.get_nodes())
last_symbol = symbol_names[-1] last_symbol = symbol_names[-1]
@@ -149,8 +150,10 @@ class Completion:
# No completions for ``with x as foo`` and ``import x as foo``. # No completions for ``with x as foo`` and ``import x as foo``.
# Also true for defining names as a class or function. # Also true for defining names as a class or function.
return [] return []
elif symbol_names[-1] == 'trailer' and '(' != nodes[-1]:
completion_names += self._trailer_completions(completion_parts)
else: else:
completion_names += self._simple_complete(completion_parts) completion_names += self._global_completions()
return completion_names return completion_names
@@ -158,42 +161,40 @@ class Completion:
for k in keywords_: for k in keywords_:
yield keywords.keyword(self._evaluator, k).name yield keywords.keyword(self._evaluator, k).name
def _simple_complete(self, completion_parts): def _global_completions(self):
if not completion_parts.path and not completion_parts.has_dot: scope = self._parser.user_scope()
scope = self._parser.user_scope() if not scope.is_scope(): # Might be a flow (if/while/etc).
if not scope.is_scope(): # Might be a flow (if/while/etc). scope = scope.get_parent_scope()
scope = scope.get_parent_scope() names_dicts = global_names_dict_generator(
names_dicts = global_names_dict_generator( self._evaluator,
self._evaluator, self._evaluator.wrap(scope),
self._evaluator.wrap(scope), self._pos
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 = [] return 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())
completion_names += filter_definition_names( def _trailer_completions(self, completion_parts):
names, self._parser.user_stmt() 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 return completion_names
def _parse_dotted_names(self, nodes): def _parse_dotted_names(self, nodes):

View File

@@ -62,7 +62,8 @@ def _check_number(source, result='float'):
def test_completion_on_number_literals(): def test_completion_on_number_literals():
# No completions on an int literal (is a float). # 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 # Multiple points after an int literal basically mean that there's a float
# and a call after that. # and a call after that.