follow_definition function for completions. fixes #54

This commit is contained in:
David Halter
2012-12-09 17:58:22 +01:00
parent 93aaff4cf4
commit 3008b96e44
2 changed files with 37 additions and 10 deletions

View File

@@ -5,11 +5,12 @@ import os
import settings import settings
import evaluate import evaluate
import imports
import parsing import parsing
import keywords import keywords
class BaseOutput(object): class BaseDefinition(object):
_mapping = {'posixpath': 'os.path', _mapping = {'posixpath': 'os.path',
'riscospath': 'os.path', 'riscospath': 'os.path',
'ntpath': 'os.path', 'ntpath': 'os.path',
@@ -41,7 +42,7 @@ class BaseOutput(object):
stripped = self.definition stripped = self.definition
if isinstance(self.definition, evaluate.InstanceElement): if isinstance(self.definition, evaluate.InstanceElement):
stripped = self.definition.var stripped = self.definition.var
self.type = type(stripped).__name__ return type(stripped).__name__
@property @property
def path(self): def path(self):
@@ -92,7 +93,7 @@ class BaseOutput(object):
@property @property
def description(self): def description(self):
raise NotImplementedError('Base Class') return str(self.definition)
@property @property
def full_name(self): def full_name(self):
@@ -115,7 +116,7 @@ class BaseOutput(object):
return "<%s %s>" % (type(self).__name__, self.description) return "<%s %s>" % (type(self).__name__, self.description)
class Completion(BaseOutput): class Completion(BaseDefinition):
""" `Completion` objects are returned from `Script.complete`. Providing """ `Completion` objects are returned from `Script.complete`. Providing
some useful functions for IDE's. """ some useful functions for IDE's. """
def __init__(self, name, needs_dot, like_name_length, base): def __init__(self, name, needs_dot, like_name_length, base):
@@ -126,6 +127,8 @@ class Completion(BaseOutput):
self.like_name_length = like_name_length self.like_name_length = like_name_length
self.base = base self.base = base
self._followed_definitions = None
@property @property
def complete(self): def complete(self):
""" Delievers the rest of the word, e.g. completing `isinstance` """ Delievers the rest of the word, e.g. completing `isinstance`
@@ -172,11 +175,33 @@ class Completion(BaseOutput):
line_nr = '' if self.in_builtin_module else '@%s' % self.line_nr line_nr = '' if self.in_builtin_module else '@%s' % self.line_nr
return '%s: %s%s' % (t, desc, line_nr) return '%s: %s%s' % (t, desc, line_nr)
def follow_definition(self):
""" Returns you the original definitions. I strongly recommend not
using it for your completions, because it might slow down Jedi. If you
want to read only a few objects (<=20). I think it might be useful,
especially to get the original docstrings.
The basic problem of this function is that it follows all results. This
means with 1000 completions (e.g. numpy), it's just PITA slow.
"""
if self._followed_definitions is None:
if self.definition.isinstance(parsing.Statement):
defs = evaluate.follow_statement(self.definition)
elif self.definition.isinstance(parsing.Import):
defs = imports.strip_imports([self.definition])
else:
return [self]
self._followed_definitions = \
[BaseDefinition(d, start_pos=None) for d in defs]
evaluate.clear_caches()
return self._followed_definitions
def __repr__(self): def __repr__(self):
return '<%s: %s>' % (type(self).__name__, self.name) return '<%s: %s>' % (type(self).__name__, self.name)
class Definition(BaseOutput): class Definition(BaseDefinition):
""" These are the objects returned by either `Script.goto` or """ These are the objects returned by either `Script.goto` or
`Script.get_definition`. """ `Script.get_definition`. """
def __init__(self, definition): def __init__(self, definition):
@@ -223,7 +248,7 @@ class Definition(BaseOutput):
return "%s:%s%s" % (self.module_name, self.description, position) return "%s:%s%s" % (self.module_name, self.description, position)
class RelatedName(BaseOutput): class RelatedName(BaseDefinition):
def __init__(self, name_part, scope): def __init__(self, name_part, scope):
super(RelatedName, self).__init__(scope, name_part.start_pos) super(RelatedName, self).__init__(scope, name_part.start_pos)
self.name_part = name_part self.name_part = name_part

View File

@@ -6,6 +6,7 @@ import unittest
from os.path import abspath, dirname from os.path import abspath, dirname
import time import time
import functools import functools
import itertools
sys.path.insert(0, abspath(dirname(abspath(__file__)) + '/../jedi')) sys.path.insert(0, abspath(dirname(abspath(__file__)) + '/../jedi'))
os.chdir(os.path.dirname(os.path.abspath(__file__)) + '/../jedi') os.chdir(os.path.dirname(os.path.abspath(__file__)) + '/../jedi')
@@ -244,13 +245,14 @@ class TestRegression(Base):
s = self.complete("import os; os.P_") s = self.complete("import os; os.P_")
assert 'P_NOWAIT' in [i.word for i in s] assert 'P_NOWAIT' in [i.word for i in s]
def test_follow_imports_if_possible(self): def test_follow_definition(self):
""" github issue #45 """ """ github issue #45 """
s = self.complete("from datetime import timedelta; timedelta") c = self.complete("from datetime import timedelta; timedelta")
# type can also point to import, but there will be additional # type can also point to import, but there will be additional
# attributes # attributes
types = [r.type for r in s] objs = itertools.chain.from_iterable(r.follow_definition() for r in c)
#assert 'Import' not in types and 'Class' in types types = [o.type for o in objs]
assert 'Import' not in types and 'Class' in types
class TestFeature(Base): class TestFeature(Base):