mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-09 07:14:48 +08:00
goto function added
This commit is contained in:
@@ -39,6 +39,7 @@ nice in Python 2. To keep things simple, some things have been held back:
|
|||||||
|
|
||||||
- Classes: Always Python 3, therefore all classes inherit from `object`.
|
- Classes: Always Python 3, therefore all classes inherit from `object`.
|
||||||
- Generators: No `next` method. The `__next__` method is there instead.
|
- Generators: No `next` method. The `__next__` method is there instead.
|
||||||
|
- Exceptions are only looked at in the form of `Exception as e`, no comma!
|
||||||
|
|
||||||
Syntax Errors and other strange stuff, that is defined differently in the
|
Syntax Errors and other strange stuff, that is defined differently in the
|
||||||
Python language, may lead to undefined behaviour of the completion. If you
|
Python language, may lead to undefined behaviour of the completion. If you
|
||||||
|
|||||||
23
evaluate.py
23
evaluate.py
@@ -286,11 +286,24 @@ class Instance(Executable):
|
|||||||
|
|
||||||
return names
|
return names
|
||||||
|
|
||||||
|
@property
|
||||||
def parent(self):
|
def parent(self):
|
||||||
return self.base.parent
|
return self.base.parent
|
||||||
|
|
||||||
|
@property
|
||||||
|
def line_nr(self):
|
||||||
|
return self.base.line_nr
|
||||||
|
|
||||||
|
@property
|
||||||
|
def indent(self):
|
||||||
|
return self.base.indent
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self.base.name
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<p%s of %s (var_args: %s)>" % \
|
return "<e%s of %s (var_args: %s)>" % \
|
||||||
(self.__class__.__name__, self.base, len(self.var_args or []))
|
(self.__class__.__name__, self.base, len(self.var_args or []))
|
||||||
|
|
||||||
|
|
||||||
@@ -345,11 +358,15 @@ class Class(object):
|
|||||||
names.append(i)
|
names.append(i)
|
||||||
return names
|
return names
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self.base.name
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
return getattr(self.base, name)
|
return getattr(self.base, name)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<p%s of %s>" % (self.__class__.__name__, self.base)
|
return "<e%s of %s>" % (self.__class__.__name__, self.base)
|
||||||
|
|
||||||
|
|
||||||
class Execution(Executable):
|
class Execution(Executable):
|
||||||
@@ -537,7 +554,7 @@ class Array(object):
|
|||||||
return self._array
|
return self._array
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<p%s of %s>" % (self.__class__.__name__, self._array)
|
return "<e%s of %s>" % (self.__class__.__name__, self._array)
|
||||||
|
|
||||||
|
|
||||||
class ArrayElement(object):
|
class ArrayElement(object):
|
||||||
|
|||||||
2
ftest.py
2
ftest.py
@@ -15,7 +15,7 @@ path = os.path.join(os.getcwd(), f_name)
|
|||||||
f = open(path)
|
f = open(path)
|
||||||
code = f.read()
|
code = f.read()
|
||||||
for i in range(1):
|
for i in range(1):
|
||||||
completions = functions.complete(code, 180, 200, path)
|
completions = functions.get_definitions(code, 180, 200, path)
|
||||||
#completions = functions.complete(code, 42, 200, path)
|
#completions = functions.complete(code, 42, 200, path)
|
||||||
|
|
||||||
print '\n', ', '.join(sorted(str(c) for c in completions))
|
print '\n', ', '.join(sorted(str(c) for c in completions))
|
||||||
|
|||||||
97
functions.py
97
functions.py
@@ -1,4 +1,5 @@
|
|||||||
import re
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
import parsing
|
import parsing
|
||||||
import evaluate
|
import evaluate
|
||||||
@@ -10,7 +11,10 @@ __all__ = ['complete', 'goto', 'get_completion_parts', 'set_debug_function']
|
|||||||
|
|
||||||
class NotFoundError(Exception):
|
class NotFoundError(Exception):
|
||||||
""" A custom error to avoid catching the wrong errors """
|
""" A custom error to avoid catching the wrong errors """
|
||||||
pass
|
def __init__(self, scope, path_tuple, message=None):
|
||||||
|
super(NotFoundError, self).__init__(message)
|
||||||
|
self.scope = scope
|
||||||
|
self.path_tuple = path_tuple
|
||||||
|
|
||||||
|
|
||||||
class Completion(object):
|
class Completion(object):
|
||||||
@@ -32,7 +36,7 @@ class Completion(object):
|
|||||||
def help(self):
|
def help(self):
|
||||||
try:
|
try:
|
||||||
return str(self.name.parent.docstr)
|
return str(self.name.parent.docstr)
|
||||||
except:
|
except AttributeError:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def get_type(self):
|
def get_type(self):
|
||||||
@@ -63,6 +67,42 @@ class Completion(object):
|
|||||||
return self.name.names[-1]
|
return self.name.names[-1]
|
||||||
|
|
||||||
|
|
||||||
|
class Definition(object):
|
||||||
|
def __init__(self, scope):
|
||||||
|
""" The definition of a function """
|
||||||
|
self.scope = scope
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
return self.scope.name
|
||||||
|
|
||||||
|
def get_module(self):
|
||||||
|
par = self.scope
|
||||||
|
while True:
|
||||||
|
if par.parent is not None:
|
||||||
|
par = par.parent
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
return par.path
|
||||||
|
|
||||||
|
def get_line(self):
|
||||||
|
return self.scope.line_nr
|
||||||
|
|
||||||
|
def get_indent(self):
|
||||||
|
return self.scope.indent
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
module = self.get_module()
|
||||||
|
if module[0] == '/':
|
||||||
|
position = '@%s' % (self.get_line())
|
||||||
|
else:
|
||||||
|
# no path - is a builtin
|
||||||
|
position = ''
|
||||||
|
|
||||||
|
return "%s.%s%s" % (module, self.get_name(), position)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<%s %s>" % (self.__class__.__name__, self)
|
||||||
|
|
||||||
def get_completion_parts(path):
|
def get_completion_parts(path):
|
||||||
"""
|
"""
|
||||||
Returns the parts for the completion
|
Returns the parts for the completion
|
||||||
@@ -88,18 +128,14 @@ def complete(source, row, column, source_path):
|
|||||||
:return: list of completion objects
|
:return: list of completion objects
|
||||||
:rtype: list
|
:rtype: list
|
||||||
"""
|
"""
|
||||||
f = modules.ModuleWithCursor(source_path, source=source, row=row)
|
|
||||||
scope = f.parser.user_scope
|
|
||||||
path = f.get_path_until_cursor(column)
|
|
||||||
debug.dbg('completion_start: %s in %s' % (path, scope))
|
|
||||||
|
|
||||||
# just parse one statement, take it and evaluate it
|
|
||||||
path, dot, like = get_completion_parts(path)
|
|
||||||
r = parsing.PyFuzzyParser(path, source_path)
|
|
||||||
try:
|
try:
|
||||||
stmt = r.top.statements[0]
|
scopes, path, dot, like = prepare_goto(source, row, column, source_path, True)
|
||||||
except IndexError:
|
except NotFoundError:
|
||||||
scope_generator = evaluate.get_names_for_scope(scope)
|
# normally this would be used like this: `NotFoundError as exc`, but
|
||||||
|
# this guarantues backwards compatibility with Python2.5.
|
||||||
|
exc = sys.exc_info()[1]
|
||||||
|
path, dot, like = exc.path_tuple
|
||||||
|
scope_generator = evaluate.get_names_for_scope(exc.scope)
|
||||||
completions = []
|
completions = []
|
||||||
for dummy, name_list in scope_generator:
|
for dummy, name_list in scope_generator:
|
||||||
completions += name_list
|
completions += name_list
|
||||||
@@ -107,11 +143,6 @@ def complete(source, row, column, source_path):
|
|||||||
# if isinstance(, parsing.Function):
|
# if isinstance(, parsing.Function):
|
||||||
# print c.parent
|
# print c.parent
|
||||||
else:
|
else:
|
||||||
stmt.line_nr = row
|
|
||||||
stmt.indent = column
|
|
||||||
stmt.parent = scope
|
|
||||||
scopes = evaluate.follow_statement(stmt, scope=scope)
|
|
||||||
|
|
||||||
completions = []
|
completions = []
|
||||||
debug.dbg('possible scopes', scopes)
|
debug.dbg('possible scopes', scopes)
|
||||||
for s in scopes:
|
for s in scopes:
|
||||||
@@ -146,20 +177,40 @@ def prepare_goto(source, row, column, source_path, is_like_search):
|
|||||||
try:
|
try:
|
||||||
stmt = r.top.statements[0]
|
stmt = r.top.statements[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise NotFoundError()
|
path_tuple = path, dot, like
|
||||||
|
raise NotFoundError(scope, path_tuple)
|
||||||
else:
|
else:
|
||||||
stmt.line_nr = row
|
stmt.line_nr = row
|
||||||
stmt.indent = column
|
stmt.indent = column
|
||||||
stmt.parent = scope
|
stmt.parent = scope
|
||||||
scopes = evaluate.follow_statement(stmt, scope=scope)
|
scopes = evaluate.follow_statement(stmt, scope=scope)
|
||||||
return scope, scopes
|
|
||||||
|
|
||||||
|
if is_like_search:
|
||||||
|
return scopes, path, dot, like
|
||||||
|
else:
|
||||||
|
return scopes
|
||||||
|
|
||||||
def goto(source, row, column, source_path):
|
def get_definitions(source, row, column, source_path):
|
||||||
dummy, scopes = prepare_goto(source, row, column, source_path, False)
|
"""
|
||||||
|
Returns the definitions of a the path under the cursor.
|
||||||
|
This is not a goto function! This follows complicated paths and returns the
|
||||||
|
end, not the first definition.
|
||||||
|
|
||||||
|
:param source: The source code of the current file
|
||||||
|
:type source: string
|
||||||
|
:param row: The row to complete in.
|
||||||
|
:type row: int
|
||||||
|
:param col: The column to complete in.
|
||||||
|
:type col: int
|
||||||
|
:param source_path: The path in the os, the current module is in.
|
||||||
|
:type source_path: int
|
||||||
|
|
||||||
|
:return: list of Definition objects, which are basically scopes.
|
||||||
|
:rtype: list
|
||||||
|
"""
|
||||||
|
scopes = prepare_goto(source, row, column, source_path, False)
|
||||||
_clear_caches()
|
_clear_caches()
|
||||||
return scopes
|
return [Definition(s) for s in set(scopes)]
|
||||||
|
|
||||||
|
|
||||||
def set_debug_function(func_cb):
|
def set_debug_function(func_cb):
|
||||||
|
|||||||
Reference in New Issue
Block a user