1
0
forked from VimPlug/jedi

First small implementation of goto.

This commit is contained in:
Dave Halter
2014-11-21 14:21:00 +01:00
parent fd16dfe2c7
commit f604066288
3 changed files with 23 additions and 16 deletions

View File

@@ -442,18 +442,13 @@ class Script(object):
user_stmt = self._parser.user_stmt() user_stmt = self._parser.user_stmt()
stmt = self._get_under_cursor_stmt(goto_path) stmt = self._get_under_cursor_stmt(goto_path)
expression_list = stmt.expression_list() if stmt is None:
if len(expression_list) == 0:
return []
# The reverse tokenizer only generates parses call.
assert len(expression_list) == 1
call = expression_list[0]
if isinstance(call, pr.Call):
call_path = list(call.generate_call_path())
else:
# goto_assignments on Operator returns nothing.
return [] return []
last_name = stmt
while not isinstance(last_name, pr.Name):
last_name = last_name.children[-1]
if next(context) in ('class', 'def'): if next(context) in ('class', 'def'):
# The cursor is on a class/function name. # The cursor is on a class/function name.
user_scope = self._parser.user_scope() user_scope = self._parser.user_scope()
@@ -476,14 +471,14 @@ class Script(object):
# The Evaluator.goto function checks for definitions, but since we # The Evaluator.goto function checks for definitions, but since we
# use a reverse tokenizer, we have new name_part objects, so we # use a reverse tokenizer, we have new name_part objects, so we
# have to check the user_stmt here for positions. # have to check the user_stmt here for positions.
if isinstance(user_stmt, pr.ExprStmt): if False and isinstance(user_stmt, pr.ExprStmt):
for name in user_stmt.get_defined_names(): for name in user_stmt.get_defined_names():
if name.start_pos <= self._pos <= name.end_pos \ if name.start_pos <= self._pos <= name.end_pos \
and (not isinstance(name.parent, pr.Call) and (not isinstance(name.parent, pr.Call)
or name.parent.next is None): or name.parent.next is None):
return [name] return [name]
defs = self._evaluator.goto(stmt, call_path) defs = self._evaluator.goto(last_name)
definitions = follow_inexistent_imports(defs) definitions = follow_inexistent_imports(defs)
return definitions return definitions

View File

@@ -442,7 +442,15 @@ class Evaluator(object):
call = call_of_name(name) call = call_of_name(name)
return self.eval_element(call) return self.eval_element(call)
def goto(self, stmt, call_path): def goto(self, name):
scope = name.get_parent_scope()
if pr.is_node(name.parent, 'trailer'):
call = call_of_name(name, cut_own_trailer=True)
types = self.eval_element(call)
return iterable.unite(self.find_types(typ, name, is_goto=True)
for typ in types)
else:
return self.find_types(scope, name, search_global=True, is_goto=True)
if isinstance(stmt, pr.Import): if isinstance(stmt, pr.Import):
# Nowhere to goto for aliases # Nowhere to goto for aliases
if stmt.alias == call_path[0]: if stmt.alias == call_path[0]:

View File

@@ -97,7 +97,7 @@ def deep_ast_copy(obj, new_elements_default=None):
return recursion(obj) return recursion(obj)
def call_of_name(name): def call_of_name(name, cut_own_trailer=False):
""" """
Creates a "call" node that consist of all ``trailer`` and ``power`` Creates a "call" node that consist of all ``trailer`` and ``power``
objects. E.g. if you call it with ``append``:: objects. E.g. if you call it with ``append``::
@@ -119,10 +119,14 @@ def call_of_name(name):
par = power par = power
# Now the name must be part of a trailer # Now the name must be part of a trailer
index = par.children.index(name.parent) index = par.children.index(name.parent)
if index != len(par.children) - 1: if index != len(par.children) - 1 or cut_own_trailer:
# Now we have to cut the other trailers away. # Now we have to cut the other trailers away.
par = deep_ast_copy(par) par = deep_ast_copy(par)
par.children[index + 1:] = [] if not cut_own_trailer:
# Normally we would remove just the stuff after the index, but
# if the option is set remove the index as well. (for goto)
index = index + 1
par.children[index:] = []
return par return par