forked from VimPlug/jedi
create a customized UserContextParser for user_stmt and user_scope
This commit is contained in:
@@ -17,7 +17,7 @@ from jedi._compatibility import next, unicode, builtins
|
|||||||
from jedi.parser import Parser
|
from jedi.parser import Parser
|
||||||
from jedi.parser import representation as pr
|
from jedi.parser import representation as pr
|
||||||
from jedi.parser import fast
|
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 debug
|
||||||
from jedi import settings
|
from jedi import settings
|
||||||
from jedi import common
|
from jedi import common
|
||||||
@@ -86,6 +86,7 @@ class Script(object):
|
|||||||
debug.reset_time()
|
debug.reset_time()
|
||||||
self.source = common.source_to_unicode(source, encoding)
|
self.source = common.source_to_unicode(source, encoding)
|
||||||
self._user_context = UserContext(self.source, self._pos)
|
self._user_context = UserContext(self.source, self._pos)
|
||||||
|
self._parser = UserContextParser(self.source, path, self._pos, self._user_context)
|
||||||
self._evaluator = Evaluator()
|
self._evaluator = Evaluator()
|
||||||
debug.speed('init')
|
debug.speed('init')
|
||||||
|
|
||||||
@@ -102,31 +103,6 @@ class Script(object):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<%s: %s>' % (self.__class__.__name__, repr(self._source_path))
|
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):
|
def completions(self):
|
||||||
"""
|
"""
|
||||||
Return :class:`classes.Completion` objects. Those objects contain
|
Return :class:`classes.Completion` objects. Those objects contain
|
||||||
@@ -150,7 +126,7 @@ class Script(object):
|
|||||||
return []
|
return []
|
||||||
path, dot, like = self._get_completion_parts()
|
path, dot, like = self._get_completion_parts()
|
||||||
|
|
||||||
user_stmt = self._user_stmt(True)
|
user_stmt = self._parser.user_stmt(True)
|
||||||
b = compiled.builtin
|
b = compiled.builtin
|
||||||
completions = get_completions(user_stmt, b)
|
completions = get_completions(user_stmt, b)
|
||||||
|
|
||||||
@@ -175,7 +151,7 @@ class Script(object):
|
|||||||
and n.lower().startswith(like.lower()) \
|
and n.lower().startswith(like.lower()) \
|
||||||
or n.startswith(like):
|
or n.startswith(like):
|
||||||
if not filter_private_variable(s,
|
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)
|
new = classes.Completion(self._evaluator, c, needs_dot, len(like), s)
|
||||||
k = (new.name, new.complete) # key
|
k = (new.name, new.complete) # key
|
||||||
if k in comp_dct and settings.no_completion_duplicates:
|
if k in comp_dct and settings.no_completion_duplicates:
|
||||||
@@ -196,7 +172,7 @@ class Script(object):
|
|||||||
except NotFoundError:
|
except NotFoundError:
|
||||||
scopes = []
|
scopes = []
|
||||||
scope_generator = self._evaluator.get_names_of_scope(
|
scope_generator = self._evaluator.get_names_of_scope(
|
||||||
self._parser.user_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:
|
||||||
@@ -230,9 +206,9 @@ class Script(object):
|
|||||||
Base for completions/goto. Basically it returns the resolved scopes
|
Base for completions/goto. Basically it returns the resolved scopes
|
||||||
under cursor.
|
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 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
|
# something's strange. Most probably the backwards tokenizer
|
||||||
@@ -254,7 +230,7 @@ class Script(object):
|
|||||||
stmt = r.module.statements[0]
|
stmt = r.module.statements[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise NotFoundError()
|
raise NotFoundError()
|
||||||
stmt.parent = self._parser.user_scope
|
stmt.parent = self._parser.user_scope()
|
||||||
return stmt
|
return stmt
|
||||||
|
|
||||||
def complete(self):
|
def complete(self):
|
||||||
@@ -346,7 +322,7 @@ class Script(object):
|
|||||||
lower_priority_operators = ('()', '(', ',')
|
lower_priority_operators = ('()', '(', ',')
|
||||||
"""Operators that could hide callee."""
|
"""Operators that could hide callee."""
|
||||||
if next(context) in ('class', 'def'):
|
if next(context) in ('class', 'def'):
|
||||||
scopes = set([self._parser.user_scope])
|
scopes = set([self._parser.user_scope()])
|
||||||
elif not goto_path:
|
elif not goto_path:
|
||||||
op = self._user_context.get_operator_under_cursor()
|
op = self._user_context.get_operator_under_cursor()
|
||||||
if op and op not in lower_priority_operators:
|
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()
|
goto_path = self._user_context.get_path_under_cursor()
|
||||||
context = self._user_context.get_context()
|
context = self._user_context.get_context()
|
||||||
user_stmt = self._user_stmt()
|
user_stmt = self._parser.user_stmt()
|
||||||
if next(context) in ('class', 'def'):
|
if next(context) in ('class', 'def'):
|
||||||
user_scope = self._parser.user_scope
|
user_scope = self._parser.user_scope()
|
||||||
definitions = set([user_scope.name])
|
definitions = set([user_scope.name])
|
||||||
search_name = unicode(user_scope.name)
|
search_name = unicode(user_scope.name)
|
||||||
elif isinstance(user_stmt, pr.Import):
|
elif isinstance(user_stmt, pr.Import):
|
||||||
@@ -462,7 +438,7 @@ class Script(object):
|
|||||||
"""
|
"""
|
||||||
temp, settings.dynamic_flow_information = \
|
temp, settings.dynamic_flow_information = \
|
||||||
settings.dynamic_flow_information, False
|
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)
|
definitions, search_name = self._goto(add_import_name=True)
|
||||||
if isinstance(user_stmt, pr.Statement):
|
if isinstance(user_stmt, pr.Statement):
|
||||||
c = user_stmt.expression_list()[0]
|
c = user_stmt.expression_list()[0]
|
||||||
@@ -475,7 +451,7 @@ class Script(object):
|
|||||||
definitions = usages_add_import_modules(self._evaluator, definitions, search_name)
|
definitions = usages_add_import_modules(self._evaluator, definitions, search_name)
|
||||||
|
|
||||||
module = set([d.get_parent_until() for d in definitions])
|
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)
|
names = usages(self._evaluator, definitions, search_name, module)
|
||||||
|
|
||||||
for d in set(definitions):
|
for d in set(definitions):
|
||||||
@@ -512,7 +488,7 @@ class Script(object):
|
|||||||
if call is None:
|
if call is None:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
user_stmt = self._user_stmt()
|
user_stmt = self._parser.user_stmt()
|
||||||
with common.scale_speed_settings(settings.scale_call_signatures):
|
with common.scale_speed_settings(settings.scale_call_signatures):
|
||||||
_callable = lambda: self._evaluator.eval_call(call)
|
_callable = lambda: self._evaluator.eval_call(call)
|
||||||
origins = cache.cache_call_signatures(_callable, user_stmt)
|
origins = cache.cache_call_signatures(_callable, user_stmt)
|
||||||
@@ -526,7 +502,7 @@ class Script(object):
|
|||||||
debug.speed('func_call start')
|
debug.speed('func_call start')
|
||||||
call, index = None, 0
|
call, index = None, 0
|
||||||
if call is None:
|
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):
|
if user_stmt is not None and isinstance(user_stmt, pr.Statement):
|
||||||
call, index, _ = helpers.search_call_signatures(user_stmt, self._pos)
|
call, index, _ = helpers.search_call_signatures(user_stmt, self._pos)
|
||||||
debug.speed('func_call parsed')
|
debug.speed('func_call parsed')
|
||||||
@@ -606,12 +582,12 @@ class Interpreter(Script):
|
|||||||
self.namespaces = namespaces
|
self.namespaces = namespaces
|
||||||
|
|
||||||
# Here we add the namespaces to the current parser.
|
# 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:
|
for ns in namespaces:
|
||||||
importer.import_raw_namespace(ns)
|
importer.import_raw_namespace(ns)
|
||||||
|
|
||||||
def _simple_complete(self, path, like):
|
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)
|
is_simple_path = not path or re.search('^[\w][\w\d.]*$', path)
|
||||||
if isinstance(user_stmt, pr.Import) or not is_simple_path:
|
if isinstance(user_stmt, pr.Import) or not is_simple_path:
|
||||||
return super(type(self), self)._simple_complete(path, like)
|
return super(type(self), self)._simple_complete(path, like)
|
||||||
@@ -644,8 +620,8 @@ class Interpreter(Script):
|
|||||||
for n in namespaces:
|
for n in namespaces:
|
||||||
for name in dir(n):
|
for name in dir(n):
|
||||||
if name.lower().startswith(like.lower()):
|
if name.lower().startswith(like.lower()):
|
||||||
scope = self._parser.module
|
scope = self._parser.module()
|
||||||
n = pr.Name(self._parser.module, [(name, (0, 0))],
|
n = pr.Name(self._parser.module(), [(name, (0, 0))],
|
||||||
(0, 0), (0, 0), scope)
|
(0, 0), (0, 0), scope)
|
||||||
completions.append((n, scope))
|
completions.append((n, scope))
|
||||||
return completions
|
return completions
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import re
|
import re
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from jedi.cache import underscore_memoization
|
from jedi import cache
|
||||||
from jedi.parser import tokenize
|
from jedi.parser import tokenize
|
||||||
|
from jedi.parser import fast
|
||||||
|
from jedi.parser import representation
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
|
|
||||||
|
|
||||||
@@ -21,7 +24,7 @@ class UserContext(object):
|
|||||||
self._line_temp = None
|
self._line_temp = None
|
||||||
self._relevant_temp = None
|
self._relevant_temp = None
|
||||||
|
|
||||||
@underscore_memoization
|
@cache.underscore_memoization
|
||||||
def get_path_until_cursor(self):
|
def get_path_until_cursor(self):
|
||||||
""" Get the path under the cursor. """
|
""" Get the path under the cursor. """
|
||||||
path, self._start_cursor_pos = self._calc_path_until_cursor(self.position)
|
path, self._start_cursor_pos = self._calc_path_until_cursor(self.position)
|
||||||
@@ -175,3 +178,39 @@ class UserContext(object):
|
|||||||
|
|
||||||
def get_position_line(self):
|
def get_position_line(self):
|
||||||
return self.get_line(self.position[0])[:self.position[1]]
|
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
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ def extract(script, new_name):
|
|||||||
new_lines = common.source_to_unicode(script.source).splitlines()
|
new_lines = common.source_to_unicode(script.source).splitlines()
|
||||||
old_lines = new_lines[:]
|
old_lines = new_lines[:]
|
||||||
|
|
||||||
user_stmt = script._parser.user_stmt
|
user_stmt = script._parser.user_stmt()
|
||||||
|
|
||||||
# TODO care for multiline extracts
|
# TODO care for multiline extracts
|
||||||
dct = {}
|
dct = {}
|
||||||
|
|||||||
Reference in New Issue
Block a user