From cfd71a6b548ac26af8468071908f18f341467dc2 Mon Sep 17 00:00:00 2001 From: Jacob Niehus Date: Sun, 19 Oct 2014 14:35:11 -0700 Subject: [PATCH 1/7] Add option to show call signatures in command line --- after/syntax/python.vim | 2 +- autoload/jedi.vim | 50 ++++++++++++++++++++++++++++++++++ doc/jedi-vim.txt | 5 ++-- ftplugin/python/jedi.vim | 2 +- jedi_vim.py | 58 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 113 insertions(+), 4 deletions(-) diff --git a/after/syntax/python.vim b/after/syntax/python.vim index 3fa6608..72ca838 100644 --- a/after/syntax/python.vim +++ b/after/syntax/python.vim @@ -1,4 +1,4 @@ -if g:jedi#show_call_signatures == 1 && has('conceal') +if g:jedi#show_call_signatures > 0 && has('conceal') " conceal is normal for vim >= 7.3 let s:e = g:jedi#call_signature_escape diff --git a/autoload/jedi.vim b/autoload/jedi.vim index 159e6e8..54cb533 100644 --- a/autoload/jedi.vim +++ b/autoload/jedi.vim @@ -155,10 +155,60 @@ endfunction function! jedi#configure_call_signatures() + if g:jedi#show_call_signatures == 2 " Command line call signatures + " Need to track changes to avoid multiple undo points for a single edit + let b:normaltick = b:changedtick + autocmd TextChanged,InsertLeave,BufWinEnter let b:normaltick = b:changedtick + endif + autocmd InsertEnter let g:jedi#first_col = s:save_first_col() autocmd InsertLeave Python jedi_vim.clear_call_signatures() autocmd CursorMovedI Python jedi_vim.show_call_signatures() endfunction +" Determine where the current window is on the screen for displaying call +" signatures in the correct column. +function! s:save_first_col() + let gutterwidth = &fdc + &number * max([&numberwidth, len(line('$')) + 1]) + if bufname('%') ==# '[Command Line]' | return gutterwidth + 1 | endif + if winnr('$') == 1 | return gutterwidth | endif + + let l:eventignore = &eventignore + set eventignore=all + let startwin = winnr() + let startaltwin = winnr('#') + let winwidth = winwidth(0) + + try + wincmd h + let win_on_left = winnr() == startwin + if win_on_left + return gutterwidth + else + " Walk left and count up window widths until hitting the edge + execute startwin."wincmd w" + let width = 0 + let winnr = winnr() + wincmd h + while winnr != winnr() + let width += winwidth(0) + 1 " Extra column for window divider + let winnr = winnr() + wincmd h + endwhile + return width + gutterwidth + endif + finally + let &eventignore = l:eventignore + execute startaltwin."wincmd w" + execute startwin."wincmd w" + " If the event that triggered InsertEnter made a change (e.g. open a + " new line, substitude a word), join that change with the rest of this + " edit. + if b:normaltick != b:changedtick + undojoin + endif + endtry +endfunction + " Helper function instead of `python vim.eval()`, and `.command()` because " these also return error definitions. function! jedi#_vim_exceptions(str, is_eval) diff --git a/doc/jedi-vim.txt b/doc/jedi-vim.txt index bd55852..8cbfa63 100644 --- a/doc/jedi-vim.txt +++ b/doc/jedi-vim.txt @@ -379,9 +379,10 @@ Default: 1 (Automatically close preview window upon leaving insert mode) Jedi-vim can display a small window detailing the arguments of the currently completed function and highlighting the currently selected argument. This can -be disabled by setting this option to 0. +be disabled by setting this option to 0. Setting this option to 2 shows call +signatures in the command line instead of a popup window. -Options: 0 or 1 +Options: 0, 1, or 2 Default: 1 (Show call signatures window) Note: This setting is ignored if |g:jedi#auto_initialization| is set to 0. In diff --git a/ftplugin/python/jedi.vim b/ftplugin/python/jedi.vim index 938b10c..b2f4104 100644 --- a/ftplugin/python/jedi.vim +++ b/ftplugin/python/jedi.vim @@ -25,7 +25,7 @@ if g:jedi#auto_initialization execute "nnoremap ".g:jedi#documentation_command." :call jedi#show_documentation()" endif - if g:jedi#show_call_signatures == 1 && has('conceal') + if g:jedi#show_call_signatures > 0 && has('conceal') call jedi#configure_call_signatures() endif diff --git a/jedi_vim.py b/jedi_vim.py index f5f9fda..77504f2 100644 --- a/jedi_vim.py +++ b/jedi_vim.py @@ -8,6 +8,10 @@ import re import os import sys from shlex import split as shsplit +try: + from itertools import zip_longest +except ImportError: + from itertools import izip_longest as zip_longest # Python 2 import vim import jedi @@ -228,6 +232,10 @@ def show_documentation(): @catch_and_print_exceptions def clear_call_signatures(): + # Check if using command line call signatures + if vim_eval("g:jedi#show_call_signatures") == '2': + vim_command('echo ""') + return cursor = vim.current.window.cursor e = vim_eval('g:jedi#call_signature_escape') regex = r'%sjedi=([0-9]+), ([^%s]*)%s.*%sjedi%s'.replace('%s', e) @@ -255,6 +263,9 @@ def show_call_signatures(signatures=()): if not signatures: return + if vim_eval("g:jedi#show_call_signatures") == '2': + return cmdline_call_signatures(signatures) + for i, signature in enumerate(signatures): line, column = signature.bracket_start # signatures are listed above each other @@ -310,6 +321,53 @@ def show_call_signatures(signatures=()): vim_eval('setline(%s, %s)' % (line_to_replace, repr(PythonToVimStr(repl)))) +@catch_and_print_exceptions +def cmdline_call_signatures(signatures): + def get_params(s): + return [p.description.replace('\n', '') for p in s.params] + + 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) + + # Allow 12 characters for ruler/showcmd - 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')) + + column - len(signatures[0].call_name), + max_num_spaces) + spaces = ' ' * num_spaces + + try: + index = [s.index for s in signatures if isinstance(s.index, int)][0] + left = text.index(params[index]) + right = left + len(params[index]) + vim_command(' echon "%s" | ' + 'echohl Function | echon "%s" | ' + 'echohl None | echon "(" | ' + 'echohl jediFunction | echon "%s" | ' + '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): + vim_command(' echon "%s" | ' + 'echohl Function | echon "%s" | ' + 'echohl None | echon "(" | ' + 'echohl jediFunction | echon "%s" | ' + 'echohl None | echon ")"' + % (spaces, signatures[0].call_name, text)) + + @catch_and_print_exceptions def rename(): if not int(vim.eval('a:0')): From 048b9dc286a9a3e8a9787f30a33060736f51fecc Mon Sep 17 00:00:00 2001 From: Jacob Niehus Date: Mon, 20 Oct 2014 15:49:49 -0700 Subject: [PATCH 2/7] Fix autocmd outside of if statement --- autoload/jedi.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autoload/jedi.vim b/autoload/jedi.vim index 54cb533..50d29df 100644 --- a/autoload/jedi.vim +++ b/autoload/jedi.vim @@ -159,8 +159,8 @@ function! jedi#configure_call_signatures() " Need to track changes to avoid multiple undo points for a single edit let b:normaltick = b:changedtick autocmd TextChanged,InsertLeave,BufWinEnter let b:normaltick = b:changedtick + autocmd InsertEnter let g:jedi#first_col = s:save_first_col() endif - autocmd InsertEnter let g:jedi#first_col = s:save_first_col() autocmd InsertLeave Python jedi_vim.clear_call_signatures() autocmd CursorMovedI Python jedi_vim.show_call_signatures() endfunction From e1a49790cb2520225c839bbd6e74ae5b0ce16bb9 Mon Sep 17 00:00:00 2001 From: Jacob Niehus Date: Mon, 20 Oct 2014 15:50:44 -0700 Subject: [PATCH 3/7] Remove manual width calculation and handle horizontal scroll --- autoload/jedi.vim | 10 +++++----- jedi_vim.py | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/autoload/jedi.vim b/autoload/jedi.vim index 50d29df..cb5365d 100644 --- a/autoload/jedi.vim +++ b/autoload/jedi.vim @@ -168,9 +168,9 @@ endfunction " Determine where the current window is on the screen for displaying call " signatures in the correct column. function! s:save_first_col() - let gutterwidth = &fdc + &number * max([&numberwidth, len(line('$')) + 1]) - if bufname('%') ==# '[Command Line]' | return gutterwidth + 1 | endif - if winnr('$') == 1 | return gutterwidth | endif + if bufname('%') ==# '[Command Line]' || winnr('$') == 1 + return 0 + endif let l:eventignore = &eventignore set eventignore=all @@ -182,7 +182,7 @@ function! s:save_first_col() wincmd h let win_on_left = winnr() == startwin if win_on_left - return gutterwidth + return 0 else " Walk left and count up window widths until hitting the edge execute startwin."wincmd w" @@ -194,7 +194,7 @@ function! s:save_first_col() let winnr = winnr() wincmd h endwhile - return width + gutterwidth + return width endif finally let &eventignore = l:eventignore diff --git a/jedi_vim.py b/jedi_vim.py index 77504f2..9868164 100644 --- a/jedi_vim.py +++ b/jedi_vim.py @@ -341,7 +341,8 @@ def cmdline_call_signatures(signatures): 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')) + + num_spaces = min(int(vim_eval('g:jedi#first_col +' + 'wincol() - col(".")')) + column - len(signatures[0].call_name), max_num_spaces) spaces = ' ' * num_spaces From fb1eaa611e1212e6f5f002cbf814ca57d953ca8e Mon Sep 17 00:00:00 2001 From: Jacob Niehus Date: Mon, 20 Oct 2014 16:39:36 -0700 Subject: [PATCH 4/7] Add vspec tests for cmdline call signatures --- test/signatures.vim | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/signatures.vim b/test/signatures.vim index e47f67d..30f3b92 100644 --- a/test/signatures.vim +++ b/test/signatures.vim @@ -36,4 +36,31 @@ describe 'signatures' let g:jedi#show_call_signatures = 1 end + + it 'command line simple' + let g:jedi#show_call_signatures = 2 + call jedi#configure_call_signatures() + + normal oabs( + redir => msg + Python jedi_vim.show_call_signatures() + redir END + Expect msg == "\nabs(number)" + + redir => msg + doautocmd InsertLeave + redir END + Expect msg == "\n\n" + end + + it 'command line no signature' + let g:jedi#show_call_signatures = 2 + call jedi#configure_call_signatures() + + normal ostr + redir => msg + Python jedi_vim.show_call_signatures() + redir END + Expect msg == "\n" + end end From 9ea98e2e81d11b4df893c21f188bed867546cdee Mon Sep 17 00:00:00 2001 From: Jacob Niehus Date: Fri, 31 Oct 2014 19:09:54 -0700 Subject: [PATCH 5/7] Fix obscure undojoin bug --- autoload/jedi.vim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/autoload/jedi.vim b/autoload/jedi.vim index cb5365d..97111d1 100644 --- a/autoload/jedi.vim +++ b/autoload/jedi.vim @@ -204,7 +204,11 @@ function! s:save_first_col() " new line, substitude a word), join that change with the rest of this " edit. if b:normaltick != b:changedtick - undojoin + try + undojoin + catch /^Vim\%((\a\+)\)\=:E790/ + " This can happen if an undo happens during a :normal command. + endtry endif endtry endfunction From f44ae4efe0aacefbf0f91564d596b7cd9ea5de5a Mon Sep 17 00:00:00 2001 From: Jacob Niehus Date: Thu, 20 Nov 2014 20:17:04 -0700 Subject: [PATCH 6/7] Fix autocmd error in Vim <7.3.867 --- autoload/jedi.vim | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/autoload/jedi.vim b/autoload/jedi.vim index 97111d1..d4f731d 100644 --- a/autoload/jedi.vim +++ b/autoload/jedi.vim @@ -157,8 +157,10 @@ endfunction function! jedi#configure_call_signatures() if g:jedi#show_call_signatures == 2 " Command line call signatures " Need to track changes to avoid multiple undo points for a single edit - let b:normaltick = b:changedtick - autocmd TextChanged,InsertLeave,BufWinEnter let b:normaltick = b:changedtick + if v:version >= 704 || has("patch-7.3.867") + let b:normaltick = b:changedtick + autocmd TextChanged,InsertLeave,BufWinEnter let b:normaltick = b:changedtick + endif autocmd InsertEnter let g:jedi#first_col = s:save_first_col() endif autocmd InsertLeave Python jedi_vim.clear_call_signatures() @@ -203,7 +205,7 @@ function! s:save_first_col() " If the event that triggered InsertEnter made a change (e.g. open a " new line, substitude a word), join that change with the rest of this " edit. - if b:normaltick != b:changedtick + if exists('b:normaltick') && b:normaltick != b:changedtick try undojoin catch /^Vim\%((\a\+)\)\=:E790/ From 8ce612e3a6afb73e583e402ba56170733f70b4b0 Mon Sep 17 00:00:00 2001 From: Jacob Niehus Date: Fri, 21 Nov 2014 11:12:32 -0700 Subject: [PATCH 7/7] Describe call signature options in readme --- README.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 0ec9e08..1c1e2e5 100644 --- a/README.rst +++ b/README.rst @@ -147,6 +147,16 @@ and usually saves one keypress. let g:jedi#popup_select_first = 0 +Jedi displays function call signatures in insert mode in real-time, highlighting +the current argument. The call signatures can be displayed as a pop-up in the +buffer (set to 1, the default), which has the advantage of being easier to refer +to, or in Vim's command line aligned with the function call (set to 2), which +can improve the integrity of Vim's undo history. + +.. code-block:: vim + + let g:jedi#show_call_signatures = "1" + Here are a few more defaults for actions, read the docs (``:help jedi-vim``) to get more information. If you set them to ``""``, they are not assigned. @@ -158,7 +168,6 @@ get more information. If you set them to ``""``, they are not assigned. let g:jedi#usages_command = "n" let g:jedi#completions_command = "" let g:jedi#rename_command = "r" - let g:jedi#show_call_signatures = "1" Finally, if you don't want completion, but all the other features, use: