mirror of
https://github.com/davidhalter/jedi.git
synced 2026-02-15 12:51:58 +08:00
Make goto_definitions a lot simpler.
This commit is contained in:
@@ -183,41 +183,9 @@ class Script(object):
|
||||
|
||||
:rtype: list of :class:`classes.Definition`
|
||||
"""
|
||||
def resolve_import_paths(definitions):
|
||||
new_defs = list(definitions)
|
||||
for s in definitions:
|
||||
if isinstance(s, imports.ImportWrapper):
|
||||
new_defs.remove(s)
|
||||
new_defs += resolve_import_paths(set(s.follow()))
|
||||
return new_defs
|
||||
c = helpers.ContextResults(self._evaluator, self.source, self._get_module(), self._pos)
|
||||
definitions = c.get_results()
|
||||
|
||||
goto_path = self._user_context.get_path_under_cursor()
|
||||
context = self._user_context.get_reverse_context()
|
||||
definitions = []
|
||||
if next(context) in ('class', 'def'):
|
||||
definitions = [self._evaluator.wrap(self._parser.user_scope())]
|
||||
else:
|
||||
# Fetch definition of callee, if there's no path otherwise.
|
||||
if not goto_path:
|
||||
definitions = [signature._definition
|
||||
for signature in self.call_signatures()]
|
||||
|
||||
if re.match('\w[\w\d_]*$', goto_path) and not definitions:
|
||||
user_stmt = self._parser.user_stmt()
|
||||
if user_stmt is not None and user_stmt.type == 'expr_stmt':
|
||||
for name in user_stmt.get_defined_names():
|
||||
if name.start_pos <= self._pos <= name.end_pos:
|
||||
# TODO scaning for a name and then using it should be
|
||||
# the default.
|
||||
definitions = self._evaluator.goto_definition(name)
|
||||
|
||||
if not definitions and goto_path:
|
||||
definitions = inference.type_inference(
|
||||
self._evaluator, self._parser, self._user_context,
|
||||
self._pos, goto_path
|
||||
)
|
||||
|
||||
definitions = resolve_import_paths(definitions)
|
||||
names = [s.name for s in definitions]
|
||||
defs = [classes.Definition(self._evaluator, name) for name in names]
|
||||
# The additional set here allows the definitions to become unique in an
|
||||
|
||||
@@ -183,7 +183,7 @@ class Completion:
|
||||
else:
|
||||
scopes = list(inference.type_inference(
|
||||
self._evaluator, self._parser, self._user_context,
|
||||
self._pos, completion_parts.path, is_completion=True
|
||||
self._pos, completion_parts.path
|
||||
))
|
||||
completion_names = []
|
||||
debug.dbg('possible completion scopes: %s', scopes)
|
||||
|
||||
@@ -212,3 +212,70 @@ def importer_from_error_statement(error_statement, pos):
|
||||
only_modules = False
|
||||
|
||||
return names, level, only_modules, unfinished_dotted
|
||||
|
||||
|
||||
class ContextResults():
|
||||
def __init__(self, evaluator, source, module, pos):
|
||||
self._evaluator = evaluator
|
||||
self._module = module
|
||||
self._source = source
|
||||
self._pos = pos
|
||||
|
||||
def _on_defining_name(self, leaf):
|
||||
return [self._evaluator.wrap(self._parser.user_scope())]
|
||||
|
||||
def get_results(self):
|
||||
'''
|
||||
try:
|
||||
stack = get_stack_at_position(self._evaluator.grammar, self._source, self._module, self._leaf.end_pos)
|
||||
except OnErrorLeaf:
|
||||
return []
|
||||
'''
|
||||
|
||||
name = self._module.name_for_position(self._pos)
|
||||
if name is not None:
|
||||
return self._evaluator.goto_definition(name)
|
||||
|
||||
leaf = self._module.get_leaf_for_position(self._pos)
|
||||
if leaf is None:
|
||||
return []
|
||||
|
||||
if leaf.parent.type == 'atom':
|
||||
return self._evaluator.eval_element(leaf.parent)
|
||||
if leaf.parent.type == 'trailer':
|
||||
return self._evaluator.eval_element(leaf.parent.parent)
|
||||
return []
|
||||
symbol_names = list(stack.get_node_names(self._evaluator.grammar))
|
||||
|
||||
nodes = list(stack.get_nodes())
|
||||
|
||||
if "import_stmt" in symbol_names:
|
||||
level = 0
|
||||
only_modules = True
|
||||
level, names = self._parse_dotted_names(nodes)
|
||||
if "import_from" in symbol_names:
|
||||
if 'import' in nodes:
|
||||
only_modules = False
|
||||
else:
|
||||
assert "import_name" in symbol_names
|
||||
|
||||
completion_names += self._get_importer_names(
|
||||
names,
|
||||
level,
|
||||
only_modules
|
||||
)
|
||||
elif nodes[-2] in ('as', 'def', 'class'):
|
||||
# No completions for ``with x as foo`` and ``import x as foo``.
|
||||
# Also true for defining names as a class or function.
|
||||
return self._on_defining_name(self._leaf)
|
||||
else:
|
||||
completion_names += self._simple_complete(completion_parts)
|
||||
return
|
||||
|
||||
|
||||
class GotoDefinition(ContextResults):
|
||||
def _():
|
||||
definitions = inference.type_inference(
|
||||
self._evaluator, self._parser, self._user_context,
|
||||
self._pos, goto_path
|
||||
)
|
||||
|
||||
@@ -3,50 +3,29 @@ This module has helpers for doing type inference on strings. It is needed,
|
||||
because we still want to infer types where the syntax is invalid.
|
||||
"""
|
||||
from jedi import debug
|
||||
from jedi.api import helpers
|
||||
from jedi.parser import tree
|
||||
from jedi.parser import Parser, ParseError
|
||||
from jedi.evaluate import imports
|
||||
from jedi.evaluate.cache import memoize_default
|
||||
from jedi.api import helpers
|
||||
|
||||
|
||||
def type_inference(evaluator, parser, user_context, position, dotted_path, is_completion=False):
|
||||
def goto_checks(evaluator, parser, user_context, position, dotted_path, follow_types=False):
|
||||
module = evaluator.wrap(parser.module())
|
||||
stack = helpers.get_stack_at_position(evaluator.grammar, self._source, module, position)
|
||||
stack
|
||||
|
||||
def type_inference(evaluator, parser, user_context, position, dotted_path):
|
||||
"""
|
||||
Base for completions/goto. Basically it returns the resolved scopes
|
||||
under cursor.
|
||||
"""
|
||||
debug.dbg('start: %s in %s', dotted_path, parser.user_scope())
|
||||
|
||||
user_stmt = parser.user_stmt_with_whitespace()
|
||||
if not user_stmt and len(dotted_path.split('\n')) > 1:
|
||||
# If the user_stmt is not defined and the dotted_path is multi line,
|
||||
# something's strange. Most probably the backwards tokenizer
|
||||
# matched to much.
|
||||
# Just parse one statement, take it and evaluate it.
|
||||
eval_stmt = get_under_cursor_stmt(evaluator, parser, dotted_path, position)
|
||||
if eval_stmt is None:
|
||||
return []
|
||||
|
||||
if isinstance(user_stmt, tree.Import) and not is_completion:
|
||||
i, _ = helpers.get_on_import_stmt(evaluator, user_context,
|
||||
user_stmt, is_completion)
|
||||
if i is None:
|
||||
return []
|
||||
scopes = [i]
|
||||
else:
|
||||
# Just parse one statement, take it and evaluate it.
|
||||
eval_stmt = get_under_cursor_stmt(evaluator, parser, dotted_path, position)
|
||||
if eval_stmt is None:
|
||||
return []
|
||||
|
||||
if not is_completion:
|
||||
module = evaluator.wrap(parser.module())
|
||||
names, level, _, _ = helpers.check_error_statements(module, position)
|
||||
if names:
|
||||
names = [str(n) for n in names]
|
||||
i = imports.Importer(evaluator, names, module, level)
|
||||
return i.follow()
|
||||
|
||||
scopes = evaluator.eval_element(eval_stmt)
|
||||
|
||||
return scopes
|
||||
return evaluator.eval_element(eval_stmt)
|
||||
|
||||
|
||||
@memoize_default(evaluator_is_first_arg=True)
|
||||
|
||||
Reference in New Issue
Block a user