diff --git a/builtin.py b/builtin.py index 520e483c..e388fd7b 100644 --- a/builtin.py +++ b/builtin.py @@ -378,6 +378,8 @@ def parse_function_doc(func): end = 0 param_str = '' + param_str = param_str.replace('-', '_') # see: isinstance.__doc__ + if doc is not None: r = re.search('-[>-]* ', doc[end:end + 7]) if doc is None or r is None: diff --git a/functions.py b/functions.py index 0d5bea98..0369f925 100644 --- a/functions.py +++ b/functions.py @@ -13,7 +13,7 @@ import keywords from _compatibility import next __all__ = ['complete', 'goto', 'get_definition', 'related_names', - 'NotFoundError', 'set_debug_function'] + 'NotFoundError', 'set_debug_function', 'get_in_function_call'] class NotFoundError(Exception): @@ -112,6 +112,29 @@ class Definition(dynamic.BaseOutput): return "%s:%s%s" % (self.module_name, self.description, position) +class CallDef(object): + def __init__(self, executable, index): + self.executable = executable + self.index = index + + @property + def params(self): + if isinstance(self.executable, evaluate.Function): + return self.executable.params + else: + try: + sub = self.executable.get_subscope_by_name('__init__') + return sub.params + except KeyError: + print self.executable.subscopes + print 'LALA' + return [] + + def __repr__(self): + return '<%s: %s index %s>' % (self.__class__.__name__, self.executable, + self.index) + + def _get_completion_parts(path): """ Returns the parts for the completion @@ -173,8 +196,10 @@ def complete(source, line, column, source_path): needs_dot = not dot and path c = [Completion(c, needs_dot, len(like), s) for c, s in set(completions)] + call_def = _get_in_function_call(f, pos) + _clear_caches() - return c + return c, call_def def _prepare_goto(position, source_path, module, goto_path, @@ -365,3 +390,54 @@ def set_debug_function(func_cb): def _clear_caches(): evaluate.clear_caches() + +def get_in_function_call(source, line, column, source_path): + pos = (line, column) + f = modules.ModuleWithCursor(source_path, source=source, position=pos) + + return _get_in_function_call(f, pos) + +def _get_in_function_call(module, pos): + def scan_array_for_pos(arr, pos): + """ Returns the function Call that match search_name in an Array. """ + index = None + call = None + for index, sub in enumerate(arr): + call = None + for s in sub: + if isinstance(s, parsing.Array): + new = scan_array_for_pos(s, pos) + if new[0] is not None: + call, index = new + elif isinstance(s, parsing.Call): + while s is not None: + if s.start_pos >= pos: + return call, index + if s.execution is not None: + if s.execution.start_pos <= pos: + call = s + else: + return call, index + c, index = scan_array_for_pos(s.execution, pos) + if c is not None: + call = c + s = s.next + return call, index + + user_stmt = module.parser.user_stmt + if user_stmt is None: + return None + ass = user_stmt.get_assignment_calls() + + call, index = scan_array_for_pos(ass, pos) + if call is None: + return None + + call.execution, temp = None, call.execution + origins = evaluate.follow_call(call) + call.execution = temp + + if len(origins) == 0: + return None + executable = origins[0] # just take entry zero, because we need just one. + return CallDef(executable, index) diff --git a/parsing.py b/parsing.py index a9bea4b8..8c5db7c6 100644 --- a/parsing.py +++ b/parsing.py @@ -298,6 +298,9 @@ class Module(Scope): self._name = Name(names, self.start_pos, self.end_pos, self) return self._name + def is_builtin(self): + return not self.path.endswith('.py') + class Class(Scope): """ diff --git a/plugin/jedi.vim b/plugin/jedi.vim index d4b83b76..29e91621 100644 --- a/plugin/jedi.vim +++ b/plugin/jedi.vim @@ -45,7 +45,7 @@ if 1: # here again, the hacks, because jedi has a different interface than vim column += len(base) try: - completions = functions.complete(source, row, column, buf_path) + completions, call_def = functions.complete(source, row, column, buf_path) out = [] for c in completions: d = dict(word=c.word[:len(base)] + c.complete, @@ -64,9 +64,10 @@ if 1: print(traceback.format_exc()) strout = '' completions = [] + call_def = None #print 'end', strout - show_func_def(len(completions)) + show_func_def(call_def, len(completions)) vim.command('return ' + strout) PYTHONEOF endfunction @@ -459,7 +460,8 @@ def _goto(is_definition=False, is_related_name=False, no_output=False): vim.command('call add_goto_window()') return definitions -def show_func_def(completion_lines=0): + +def show_func_def(call_def, completion_lines=0): row, column = vim.current.window.cursor vim.eval('jedi#clear_func_def()') @@ -470,6 +472,8 @@ def show_func_def(completion_lines=0): line = vim.eval("getline(%s)" % row_to_replace) insert_column = column - 2 # because it has stuff at the beginning + + print call_def, call_def.params text = " (*asdf*, basdf) " text = ' ' * (insert_column - len(line)) + text end_column = insert_column + len(text) - 2 # -2 because of bold symbols diff --git a/test/regression.py b/test/regression.py index 0f35e508..510d06e2 100755 --- a/test/regression.py +++ b/test/regression.py @@ -18,6 +18,11 @@ class TestRegression(unittest.TestCase): def complete(self, src, pos): return functions.complete(src, pos[0], pos[1], '') + def get_in_function_call(self, src, pos=None): + if pos is None: + pos = 1, len(src) + return functions.get_in_function_call(src, pos[0], pos[1], '') + def test_get_definition_cursor(self): s = ("class A():\n" @@ -100,6 +105,16 @@ class TestRegression(unittest.TestCase): ) functions.related_names(s, 2, 2, '/') + def test_get_in_function_call(self): + s = "isinstance(a, abs(" + s2 = "isinstance(), " + print + check = lambda call_def, index: call_def and call_def.index == index + assert check(self.get_in_function_call(s, (1,11)), 0) + assert check(self.get_in_function_call(s, (1,14)), 1) + assert check(self.get_in_function_call(s, (1,15)), 1) + assert check(self.get_in_function_call(s, (1,18)), 0) + assert self.get_in_function_call(s2) is None if __name__ == '__main__': unittest.main() diff --git a/test/run.py b/test/run.py index 77cf9b71..8b80e3ad 100755 --- a/test/run.py +++ b/test/run.py @@ -24,7 +24,8 @@ def run_completion_test(correct, source, line_nr, index, line, path): # lines start with 1 and column is just the last (makes no # difference for testing) try: - completions = functions.complete(source, line_nr, index, path) + completions, call_def = functions.complete(source, line_nr, index, + path) #import cProfile as profile #profile.run('functions.complete("""%s""", %i, %i, "%s")' # % (source, line_nr, len(line), path))