1
0
forked from VimPlug/jedi
This commit is contained in:
David Halter
2012-09-15 16:02:39 +02:00
parent 7e62c47f22
commit 9e7e5293d8
3 changed files with 39 additions and 33 deletions

55
api.py
View File

@@ -163,8 +163,8 @@ class Script(object):
try: try:
scopes = self._prepare_goto(path, True) scopes = self._prepare_goto(path, True)
except NotFoundError: except NotFoundError:
scope_generator = evaluate.get_names_for_scope(self.parser.user_scope, scope_generator = evaluate.get_names_for_scope(
self.pos) self.parser.user_scope, self.pos)
completions = [] completions = []
for scope, name_list in scope_generator: for scope, name_list in scope_generator:
for c in name_list: for c in name_list:
@@ -173,7 +173,7 @@ class Script(object):
completions = [] completions = []
debug.dbg('possible scopes', scopes) debug.dbg('possible scopes', scopes)
for s in scopes: for s in scopes:
# TODO is this really the right way? just ignore the functions? \ # TODO is this really the right way? just ignore the funcs? \
# do the magic functions first? and then recheck here? # do the magic functions first? and then recheck here?
if not isinstance(s, evaluate.Function): if not isinstance(s, evaluate.Function):
if isinstance(s, imports.ImportPath): if isinstance(s, imports.ImportPath):
@@ -184,12 +184,13 @@ class Script(object):
completions.append((c, s)) completions.append((c, s))
completions = [(c, s) for c, s in completions completions = [(c, s) for c, s in completions
if settings.case_insensitive_completion if settings.case_insensitive_completion
and c.names[-1].lower().startswith(like.lower()) and c.names[-1].lower().startswith(like.lower())
or c.names[-1].startswith(like)] or c.names[-1].startswith(like)]
needs_dot = not dot and path needs_dot = not dot and path
c = [Completion(c, needs_dot, len(like), s) for c, s in set(completions)] completions = set(completions)
c = [Completion(c, needs_dot, len(like), s) for c, s in completions]
_clear_caches() _clear_caches()
return c return c
@@ -201,8 +202,8 @@ class Script(object):
user_stmt = self.parser.user_stmt user_stmt = self.parser.user_stmt
if not user_stmt and len(goto_path.split('\n')) > 1: if not user_stmt and len(goto_path.split('\n')) > 1:
# If the user_stmt is not defined and the goto_path is multi line, # If the user_stmt is not defined and the goto_path is multi line,
# something's strange. Most probably the backwards tokenizer matched to # something's strange. Most probably the backwards tokenizer
# much. # matched to much.
return [] return []
if isinstance(user_stmt, parsing.Import): if isinstance(user_stmt, parsing.Import):
@@ -218,7 +219,8 @@ class Script(object):
kill_count=kill_count, direct_resolve=True)] kill_count=kill_count, direct_resolve=True)]
else: else:
# just parse one statement, take it and evaluate it # just parse one statement, take it and evaluate it
r = parsing.PyFuzzyParser(goto_path, self.source_path, no_docstr=True) r = parsing.PyFuzzyParser(goto_path, self.source_path,
no_docstr=True)
try: try:
stmt = r.module.statements[0] stmt = r.module.statements[0]
except IndexError: except IndexError:
@@ -229,11 +231,10 @@ class Script(object):
scopes = evaluate.follow_statement(stmt) scopes = evaluate.follow_statement(stmt)
return scopes return scopes
def get_definition(self): def get_definition(self):
""" """
Returns the definitions of a the path under the cursor. Returns the definitions of a the path under the cursor. This is
This is not a goto function! This follows complicated paths and returns the not a goto function! This follows complicated paths and returns the
end, not the first definition. end, not the first definition.
:param source: The source code of the current file :param source: The source code of the current file
@@ -275,7 +276,6 @@ class Script(object):
_clear_caches() _clear_caches()
return sorted(d, key=lambda x: (x.module_path, x.start_pos)) return sorted(d, key=lambda x: (x.module_path, x.start_pos))
def goto(self): def goto(self):
goto_path = self.module.get_path_under_cursor() goto_path = self.module.get_path_under_cursor()
goto_path, dot, search_name = self._get_completion_parts(goto_path) goto_path, dot, search_name = self._get_completion_parts(goto_path)
@@ -298,13 +298,12 @@ class Script(object):
_clear_caches() _clear_caches()
return sorted(d, key=lambda x: (x.module_path, x.start_pos)) return sorted(d, key=lambda x: (x.module_path, x.start_pos))
def related_names(self): def related_names(self):
""" """
Returns `dynamic.RelatedName` objects, which contain all names, that are Returns `dynamic.RelatedName` objects, which contain all names, that
defined by the same variable, function, class or import. are defined by the same variable, function, class or import.
This function can be used either to show all the usages of a variable or This function can be used either to show all the usages of a variable
for renaming purposes. or for renaming purposes.
""" """
goto_path = self.module.get_path_under_cursor() goto_path = self.module.get_path_under_cursor()
goto_path, dot, search_name = self._get_completion_parts(goto_path) goto_path, dot, search_name = self._get_completion_parts(goto_path)
@@ -323,7 +322,8 @@ class Script(object):
else: else:
e = evaluate.Class(self.module.parser.user_scope) e = evaluate.Class(self.module.parser.user_scope)
definitions = [e] definitions = [e]
elif isinstance(self.module.parser.user_stmt, (parsing.Param, parsing.Import)): elif isinstance(self.module.parser.user_stmt,
(parsing.Param, parsing.Import)):
definitions = [self.module.parser.user_stmt] definitions = [self.module.parser.user_stmt]
else: else:
scopes = self._prepare_goto(goto_path) scopes = self._prepare_goto(goto_path)
@@ -348,11 +348,12 @@ class Script(object):
elif isinstance(d, parsing.Import): elif isinstance(d, parsing.Import):
is_user = d == self.module.parser.user_stmt is_user = d == self.module.parser.user_stmt
check_names = [d.namespace, d.alias, d.from_ns] if is_user \ check_names = [d.namespace, d.alias, d.from_ns] if is_user \
else d.get_defined_names() else d.get_defined_names()
for name in check_names: for name in check_names:
if name: if name:
for n in name.names: for n in name.names:
if n.start_pos <= self.pos <= n.end_pos or not is_user: if n.start_pos <= self.pos <= n.end_pos \
or not is_user:
names.append(dynamic.RelatedName(n, d)) names.append(dynamic.RelatedName(n, d))
elif isinstance(d, parsing.Name): elif isinstance(d, parsing.Name):
names.append(dynamic.RelatedName(d.names[0], d)) names.append(dynamic.RelatedName(d.names[0], d))
@@ -364,7 +365,9 @@ class Script(object):
def get_in_function_call(self): def get_in_function_call(self):
def scan_array_for_pos(arr, pos): def scan_array_for_pos(arr, pos):
""" Returns the function Call that match search_name in an Array. """ """
Returns the function Call that match search_name in an Array.
"""
index = None index = None
call = None call = None
for index, sub in enumerate(arr): for index, sub in enumerate(arr):
@@ -381,7 +384,8 @@ class Script(object):
if s.execution is not None: if s.execution is not None:
if s.execution.start_pos <= pos: if s.execution.start_pos <= pos:
call = s call = s
c, index = scan_array_for_pos(s.execution, pos) c, index = scan_array_for_pos(s.execution,
pos)
if c is not None: if c is not None:
call = c call = c
else: else:
@@ -404,7 +408,8 @@ class Script(object):
if len(origins) == 0: if len(origins) == 0:
return None return None
executable = origins[0] # just take entry zero, because we need just one. # just take entry zero, because we need just one.
executable = origins[0]
return CallDef(executable, index) return CallDef(executable, index)
def _get_completion_parts(self, path): def _get_completion_parts(self, path):

View File

@@ -1183,7 +1183,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
scope_generator = scope.scope_generator() scope_generator = scope.scope_generator()
else: else:
if isinstance(scope, Class): if isinstance(scope, Class):
# classes are only available directly via chaining? # classes are only available directly via chaining?
# strange stuff... # strange stuff...
names = scope.get_defined_names() names = scope.get_defined_names()
else: else:
@@ -1192,6 +1192,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
return descriptor_check(remove_statements(filter_name(scope_generator))) return descriptor_check(remove_statements(filter_name(scope_generator)))
def check_getattr(inst, name_str): def check_getattr(inst, name_str):
result = [] result = []
# str is important to lose the NamePart! # str is important to lose the NamePart!

View File

@@ -90,7 +90,7 @@ class TestRegression(unittest.TestCase):
assert len(s) == 1 assert len(s) == 1
assert list(s)[0].word == 'str' assert list(s)[0].word == 'str'
s = self.complete("", (1,0)) s = self.complete("", (1, 0))
assert len(s) > 0 assert len(s) > 0
def test_get_definition_on_import(self): def test_get_definition_on_import(self):
@@ -115,13 +115,13 @@ class TestRegression(unittest.TestCase):
s2 = "isinstance(), " s2 = "isinstance(), "
check = lambda call_def, index: call_def and call_def.index == index check = lambda call_def, index: call_def and call_def.index == index
assert check(self.get_in_function_call(s, (1,11)), 0) assert check(self.get_in_function_call(s, (1, 11)), 0)
assert check(self.get_in_function_call(s, (1,14)), 1) assert check(self.get_in_function_call(s, (1, 14)), 1)
assert check(self.get_in_function_call(s, (1,15)), 1) assert check(self.get_in_function_call(s, (1, 15)), 1)
assert check(self.get_in_function_call(s, (1,18)), 0) assert check(self.get_in_function_call(s, (1, 18)), 0)
#assert check(self.get_in_function_call(s2, (1,11)), 0) # TODO uncomment ##assert check(self.get_in_function_call(s2, (1, 11)), 0) # TODO uncomment
assert self.get_in_function_call(s2, (1,12)) is None assert self.get_in_function_call(s2, (1, 12)) is None
assert self.get_in_function_call(s2) is None assert self.get_in_function_call(s2) is None
if __name__ == '__main__': if __name__ == '__main__':