diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index e2e6d712..32d12b9b 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -126,7 +126,7 @@ class Script(object): return [] path, dot, like = self._get_completion_parts() - user_stmt = self._parser.user_stmt(True) + user_stmt = self._parser.user_stmt_with_whitespace() b = compiled.builtin completions = get_completions(user_stmt, b) @@ -208,7 +208,10 @@ class Script(object): """ debug.dbg('start: %s in %s', goto_path, self._parser.user_scope()) - user_stmt = self._parser.user_stmt(is_completion) + if is_completion: + user_stmt = self._parser.user_stmt_with_whitespace() + else: + user_stmt = self._parser.user_stmt() 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 @@ -488,7 +491,7 @@ class Script(object): if call is None: return [] - user_stmt = self._parser.user_stmt(True) + user_stmt = self._parser.user_stmt_with_whitespace() with common.scale_speed_settings(settings.scale_call_signatures): _callable = lambda: self._evaluator.eval_call(call) origins = cache.cache_call_signatures(_callable, user_stmt) @@ -502,7 +505,7 @@ class Script(object): debug.speed('func_call start') call, index = None, 0 if call is None: - user_stmt = self._parser.user_stmt(True) + user_stmt = self._parser.user_stmt_with_whitespace() 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') @@ -583,7 +586,7 @@ class Interpreter(Script): interpreter.create(self._evaluator, namespaces[0], self._parser.module()) def _simple_complete(self, path, like): - user_stmt = self._parser.user_stmt(True) + user_stmt = self._parser.user_stmt_with_whitespace() 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) diff --git a/jedi/parser/user_context.py b/jedi/parser/user_context.py index c927e95f..e72f301c 100644 --- a/jedi/parser/user_context.py +++ b/jedi/parser/user_context.py @@ -197,16 +197,20 @@ class UserContextParser(object): return parser @cache.underscore_memoization - def _get_user_stmt(self): - return self.module().get_statement_for_position(self._position, - include_imports=True) - - def user_stmt(self, check_whitespace=False): - user_stmt = self._get_user_stmt() - + def user_stmt(self): + module = self.module() debug.speed('parsed') + return module.get_statement_for_position(self._position, include_imports=True) - if check_whitespace and not user_stmt: + @cache.underscore_memoization + def user_stmt_with_whitespace(self): + """ + Returns the statement under the cursor even if the statement lies + before the cursor. + """ + user_stmt = self.user_stmt() + + if not user_stmt: # for statements like `from x import ` (cursor not in statement) # or `abs( ` where the cursor is out in the whitespace. pos = next(self._user_context.get_context(yield_positions=True)) @@ -215,7 +219,7 @@ class UserContextParser(object): @cache.underscore_memoization def user_scope(self): - user_stmt = self._get_user_stmt() + user_stmt = self.user_stmt() if user_stmt is None: def scan(scope): for s in scope.statements + scope.subscopes: