1
0
forked from VimPlug/jedi

create a customized UserContextParser for user_stmt and user_scope

This commit is contained in:
Dave Halter
2014-01-16 12:12:21 +01:00
parent 269e84da85
commit 4bf72eeaed
3 changed files with 61 additions and 46 deletions

View File

@@ -17,7 +17,7 @@ from jedi._compatibility import next, unicode, builtins
from jedi.parser import Parser
from jedi.parser import representation as pr
from jedi.parser import fast
from jedi.parser.user_context import UserContext
from jedi.parser.user_context import UserContext, UserContextParser
from jedi import debug
from jedi import settings
from jedi import common
@@ -86,6 +86,7 @@ class Script(object):
debug.reset_time()
self.source = common.source_to_unicode(source, encoding)
self._user_context = UserContext(self.source, self._pos)
self._parser = UserContextParser(self.source, path, self._pos, self._user_context)
self._evaluator = Evaluator()
debug.speed('init')
@@ -102,31 +103,6 @@ class Script(object):
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, repr(self._source_path))
@property
@cache.underscore_memoization
def _parser(self):
"""Get the parser lazy"""
path = self._source_path and os.path.abspath(self._source_path)
cache.invalidate_star_import_cache(path)
parser = fast.FastParser(self.source, path, self._pos)
# Don't pickle that module, because the main module is changing quickly
cache.save_parser(path, None, parser, pickling=False)
return parser
def _user_stmt(self, is_completion=False):
user_stmt = self._parser.user_stmt
debug.speed('parsed')
if is_completion and not user_stmt:
# for statements like `from x import ` (cursor not in statement)
pos = next(self._user_context.get_context(yield_positions=True))
last_stmt = pos and self._parser.module.get_statement_for_position(
pos, include_imports=True)
if isinstance(last_stmt, pr.Import):
user_stmt = last_stmt
return user_stmt
def completions(self):
"""
Return :class:`classes.Completion` objects. Those objects contain
@@ -150,7 +126,7 @@ class Script(object):
return []
path, dot, like = self._get_completion_parts()
user_stmt = self._user_stmt(True)
user_stmt = self._parser.user_stmt(True)
b = compiled.builtin
completions = get_completions(user_stmt, b)
@@ -175,7 +151,7 @@ class Script(object):
and n.lower().startswith(like.lower()) \
or n.startswith(like):
if not filter_private_variable(s,
user_stmt or self._parser.user_scope, n):
user_stmt or self._parser.user_scope(), n):
new = classes.Completion(self._evaluator, c, needs_dot, len(like), s)
k = (new.name, new.complete) # key
if k in comp_dct and settings.no_completion_duplicates:
@@ -196,7 +172,7 @@ class Script(object):
except NotFoundError:
scopes = []
scope_generator = self._evaluator.get_names_of_scope(
self._parser.user_scope, self._pos)
self._parser.user_scope(), self._pos)
completions = []
for scope, name_list in scope_generator:
for c in name_list:
@@ -230,9 +206,9 @@ class Script(object):
Base for completions/goto. Basically it returns the resolved scopes
under cursor.
"""
debug.dbg('start: %s in %s', goto_path, self._parser.user_scope)
debug.dbg('start: %s in %s', goto_path, self._parser.user_scope())
user_stmt = self._user_stmt(is_completion)
user_stmt = self._parser.user_stmt(is_completion)
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,
# something's strange. Most probably the backwards tokenizer
@@ -254,7 +230,7 @@ class Script(object):
stmt = r.module.statements[0]
except IndexError:
raise NotFoundError()
stmt.parent = self._parser.user_scope
stmt.parent = self._parser.user_scope()
return stmt
def complete(self):
@@ -346,7 +322,7 @@ class Script(object):
lower_priority_operators = ('()', '(', ',')
"""Operators that could hide callee."""
if next(context) in ('class', 'def'):
scopes = set([self._parser.user_scope])
scopes = set([self._parser.user_scope()])
elif not goto_path:
op = self._user_context.get_operator_under_cursor()
if op and op not in lower_priority_operators:
@@ -416,9 +392,9 @@ class Script(object):
goto_path = self._user_context.get_path_under_cursor()
context = self._user_context.get_context()
user_stmt = self._user_stmt()
user_stmt = self._parser.user_stmt()
if next(context) in ('class', 'def'):
user_scope = self._parser.user_scope
user_scope = self._parser.user_scope()
definitions = set([user_scope.name])
search_name = unicode(user_scope.name)
elif isinstance(user_stmt, pr.Import):
@@ -462,7 +438,7 @@ class Script(object):
"""
temp, settings.dynamic_flow_information = \
settings.dynamic_flow_information, False
user_stmt = self._user_stmt()
user_stmt = self._parser.user_stmt()
definitions, search_name = self._goto(add_import_name=True)
if isinstance(user_stmt, pr.Statement):
c = user_stmt.expression_list()[0]
@@ -475,7 +451,7 @@ class Script(object):
definitions = usages_add_import_modules(self._evaluator, definitions, search_name)
module = set([d.get_parent_until() for d in definitions])
module.add(self._parser.module)
module.add(self._parser.module())
names = usages(self._evaluator, definitions, search_name, module)
for d in set(definitions):
@@ -512,7 +488,7 @@ class Script(object):
if call is None:
return []
user_stmt = self._user_stmt()
user_stmt = self._parser.user_stmt()
with common.scale_speed_settings(settings.scale_call_signatures):
_callable = lambda: self._evaluator.eval_call(call)
origins = cache.cache_call_signatures(_callable, user_stmt)
@@ -526,7 +502,7 @@ class Script(object):
debug.speed('func_call start')
call, index = None, 0
if call is None:
user_stmt = self._user_stmt()
user_stmt = self._parser.user_stmt()
if user_stmt is not None and isinstance(user_stmt, pr.Statement):
call, index, _ = helpers.search_call_signatures(user_stmt, self._pos)
debug.speed('func_call parsed')
@@ -606,12 +582,12 @@ class Interpreter(Script):
self.namespaces = namespaces
# Here we add the namespaces to the current parser.
importer = interpret.ObjectImporter(self._parser.user_scope)
importer = interpret.ObjectImporter(self._parser.user_scope())
for ns in namespaces:
importer.import_raw_namespace(ns)
def _simple_complete(self, path, like):
user_stmt = self._user_stmt(True)
user_stmt = self._parser.user_stmt(True)
is_simple_path = not path or re.search('^[\w][\w\d.]*$', path)
if isinstance(user_stmt, pr.Import) or not is_simple_path:
return super(type(self), self)._simple_complete(path, like)
@@ -644,8 +620,8 @@ class Interpreter(Script):
for n in namespaces:
for name in dir(n):
if name.lower().startswith(like.lower()):
scope = self._parser.module
n = pr.Name(self._parser.module, [(name, (0, 0))],
scope = self._parser.module()
n = pr.Name(self._parser.module(), [(name, (0, 0))],
(0, 0), (0, 0), scope)
completions.append((n, scope))
return completions

View File

@@ -1,8 +1,11 @@
import re
import os
import sys
from jedi.cache import underscore_memoization
from jedi import cache
from jedi.parser import tokenize
from jedi.parser import fast
from jedi.parser import representation
from jedi import debug
@@ -21,7 +24,7 @@ class UserContext(object):
self._line_temp = None
self._relevant_temp = None
@underscore_memoization
@cache.underscore_memoization
def get_path_until_cursor(self):
""" Get the path under the cursor. """
path, self._start_cursor_pos = self._calc_path_until_cursor(self.position)
@@ -175,3 +178,39 @@ class UserContext(object):
def get_position_line(self):
return self.get_line(self.position[0])[:self.position[1]]
class UserContextParser(object):
def __init__(self, source, path, position, user_context):
self._source = source
self._path = path and os.path.abspath(path)
self._position = position
self._user_context = user_context
@cache.underscore_memoization
def _parser(self):
cache.invalidate_star_import_cache(self._path)
parser = fast.FastParser(self._source, self._path, self._position)
# Don't pickle that module, because the main module is changing quickly
cache.save_parser(self._path, None, parser, pickling=False)
return parser
def user_stmt(self, is_completion=False):
user_stmt = self._parser().user_stmt
debug.speed('parsed')
if is_completion and not user_stmt:
# for statements like `from x import ` (cursor not in statement)
pos = next(self._user_context.get_context(yield_positions=True))
last_stmt = pos and self._parser().module.get_statement_for_position(
pos, include_imports=True)
if isinstance(last_stmt, representation.Import):
user_stmt = last_stmt
return user_stmt
def user_scope(self):
return self._parser().user_scope
def module(self):
return self._parser().module

View File

@@ -104,7 +104,7 @@ def extract(script, new_name):
new_lines = common.source_to_unicode(script.source).splitlines()
old_lines = new_lines[:]
user_stmt = script._parser.user_stmt
user_stmt = script._parser.user_stmt()
# TODO care for multiline extracts
dct = {}