diff --git a/jedi_vim.py b/jedi_vim.py index c92b7f1..8d3a92b 100644 --- a/jedi_vim.py +++ b/jedi_vim.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """ The Python parts of the Jedi library for VIM. It is mostly about communicating with VIM. @@ -18,7 +19,10 @@ except ImportError: is_py3 = sys.version_info[0] >= 3 if is_py3: + ELLIPSIS = "…" unicode = str +else: + ELLIPSIS = u"…" class PythonToVimStr(unicode): @@ -406,32 +410,65 @@ def cmdline_call_signatures(signatures): def get_params(s): return [p.description.replace('\n', '') for p in s.params] + def escape(string): + return string.replace('"', '\\"').replace(r'\n', r'\\n') + + def join(): + return ', '.join(filter(None, (left, center, right))) + + def too_long(): + return len(join()) > max_msg_len + if len(signatures) > 1: params = zip_longest(*map(get_params, signatures), fillvalue='_') params = ['(' + ', '.join(p) + ')' for p in params] else: params = get_params(signatures[0]) - text = ', '.join(params).replace('"', '\\"').replace(r'\n', r'\\n') - # Allow 12 characters for ruler/showcmd - setting noruler/noshowcmd - # here causes incorrect undo history + index = next(iter(s.index for s in signatures if s.index is not None), None) + + # Allow 12 characters for showcmd plus 18 for ruler - setting + # noruler/noshowcmd here causes incorrect undo history max_msg_len = int(vim_eval('&columns')) - 12 - max_num_spaces = (max_msg_len - len(signatures[0].call_name) - - len(text) - 2) # 2 accounts for parentheses - if max_num_spaces < 0: - return # No room for the message - _, column = signatures[0].bracket_start - num_spaces = min(int(vim_eval('g:jedi#first_col +' - 'wincol() - col(".")')) + - column - len(signatures[0].call_name), - max_num_spaces) - spaces = ' ' * num_spaces + if int(vim_eval('&ruler')): + max_msg_len -= 18 + max_msg_len -= len(signatures[0].call_name) + 2 # call name + parentheses - try: - index = [s.index for s in signatures if isinstance(s.index, int)][0] - escaped_param = params[index].replace(r'\n', r'\\n') - left = text.index(escaped_param) - right = left + len(escaped_param) + if max_msg_len < 0: + return + elif index is None: + pass + elif max_msg_len < len(ELLIPSIS): + return + else: + left = escape(', '.join(params[:index])) + center = escape(params[index]) + right = escape(', '.join(params[index + 1:])) + while too_long(): + if left and left != ELLIPSIS: + left = ELLIPSIS + continue + if right and right != ELLIPSIS: + right = ELLIPSIS + continue + if (left or right) and center != ELLIPSIS: + left = right = None + center = ELLIPSIS + continue + if too_long(): + # Should never reach here + return + + max_num_spaces = max_msg_len + if index is not None: + max_num_spaces -= len(join()) + _, column = signatures[0].bracket_start + spaces = min(int(vim_eval('g:jedi#first_col +' + 'wincol() - col(".")')) + + column - len(signatures[0].call_name), + max_num_spaces) * ' ' + + if index is not None: vim_command(' echon "%s" | ' 'echohl Function | echon "%s" | ' 'echohl None | echon "(" | ' @@ -439,15 +476,14 @@ def cmdline_call_signatures(signatures): 'echohl jediFat | echon "%s" | ' 'echohl jediFunction | echon "%s" | ' 'echohl None | echon ")"' - % (spaces, signatures[0].call_name, text[:left], - text[left:right], text[right:])) - except (TypeError, IndexError): + % (spaces, signatures[0].call_name, + left + ', ' if left else '', + center, ', ' + right if right else '')) + else: vim_command(' echon "%s" | ' 'echohl Function | echon "%s" | ' - 'echohl None | echon "(" | ' - 'echohl jediFunction | echon "%s" | ' - 'echohl None | echon ")"' - % (spaces, signatures[0].call_name, text)) + 'echohl None | echon "()"' + % (spaces, signatures[0].call_name)) @_check_jedi_availability(show_error=True) diff --git a/test/signatures.vim b/test/signatures.vim index b2c57e7..70f417c 100644 --- a/test/signatures.vim +++ b/test/signatures.vim @@ -53,6 +53,39 @@ describe 'signatures' Expect msg == "\n" end + it 'command line truncation' + let g:jedi#show_call_signatures = 2 + call jedi#configure_call_signatures() + + function! Signature() + redir => msg + Python jedi_vim.show_call_signatures() + redir END + return msg + endfunction + + let funcname = repeat('a', &columns - 30) + put = 'def '.funcname.'(arg1, arg2, arg3, a, b, c):' + put = ' pass' + execute "normal o".funcname."( " + Expect Signature() == "\n".funcname."(arg1, …)" + + normal sarg1, + Expect Signature() == "\n".funcname."(…, arg2, …)" + + normal sarg2, arg3, + Expect Signature() == "\n".funcname."(…, a, b, c)" + + normal sa, b, + Expect Signature() == "\n".funcname."(…, c)" + + g/^/d + put = 'def '.funcname.'('.repeat('b', 20).', arg2):' + put = ' pass' + execute "normal o".funcname."( " + Expect Signature() == "\n".funcname."(…)" + end + it 'command line no signature' let g:jedi#show_call_signatures = 2 call jedi#configure_call_signatures()