From c5ff6842385bc57cdf90b714757ea6abf3854427 Mon Sep 17 00:00:00 2001 From: Andrej Zieger Date: Mon, 3 Jun 2019 22:23:49 +0200 Subject: [PATCH 01/11] preview information shown in hover at the cursor --- autoload/lsp/ui/vim/output.vim | 89 +++++++++++++++++++++++++++++++++- doc/vim-lsp.txt | 21 ++++++++ plugin/lsp.vim | 1 + 3 files changed, 110 insertions(+), 1 deletion(-) diff --git a/autoload/lsp/ui/vim/output.vim b/autoload/lsp/ui/vim/output.vim index 159c97372..0405b30de 100644 --- a/autoload/lsp/ui/vim/output.vim +++ b/autoload/lsp/ui/vim/output.vim @@ -1,10 +1,83 @@ +let s:supports_floating = exists('*nvim_open_win') +let s:win = v:false + +function! lsp#ui#vim#output#closepreview() abort + if win_getid() == s:win + " Don't close if window got focus + return + endif + pclose + let s:win = v:false + autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * +endfunction + +function! s:get_float_positioning(height, width) + let l:height = a:height + let l:width = a:width + " For a start show it below/above the cursor + " TODO: add option to configure it 'docked' at the bottom/top/right + let l:y = winline() + if l:y + l:height >= &lines + " Float does not fit + if l:y - 2 > l:height + " Fits above + let l:y = winline() - l:height + elseif l:y - 2 > &lines - l:y + " Take space above cursor + let l:y = 1 + let l:height = winline()-2 + else + " Take space below cursor + let l:height = &lines -l:y + endif + endif + let l:col = col(".") + " Positioning is not window but screen relative + let l:opts = { + \ 'relative': 'win', + \ 'row': l:y, + \ 'col': l:col, + \ 'width': l:width, + \ 'height': l:height, + \ } + return l:opts +endfunction + +function! lsp#ui#vim#output#floatingpreview(data) abort + let l:buf = nvim_create_buf(v:false, v:true) + call setbufvar(l:buf, '&signcolumn', 'no') + + " Try to get as much pace right-bolow the cursor, but at least 10x10 + let l:width = max([float2nr(&columns - col(".") - 10), 10]) + let l:height = max([&lines - winline() + 1, 10]) + + let l:opts = s:get_float_positioning(l:height, l:width) + + let s:win = nvim_open_win(buf, v:true, l:opts) + call nvim_win_set_option(s:win, 'winhl', "Normal:Pmenu,NormalNC:Pmenu") + call nvim_win_set_option(s:win, 'foldenable', v:false) + call nvim_win_set_option(s:win, 'wrap', v:true) + call nvim_win_set_option(s:win, 'statusline', '') + call nvim_win_set_option(s:win, 'number', v:false) + call nvim_win_set_option(s:win, 'relativenumber', v:false) + call nvim_win_set_option(s:win, 'cursorline', v:false) + " Enable closing the preview with esc, but map only in the scratch buffer + nmap :pclose + return s:win +endfunction + function! lsp#ui#vim#output#preview(data) abort " Close any previously opened preview window pclose let l:current_window_id = win_getid() - execute &previewheight.'new' + if s:supports_floating && g:lsp_preview_float + call lsp#ui#vim#output#floatingpreview(a:data) + else + execute &previewheight.'new' + endif + let s:win = win_getid() let l:ft = s:append(a:data) " Delete first empty line @@ -13,6 +86,9 @@ function! lsp#ui#vim#output#preview(data) abort setlocal readonly nomodifiable let &l:filetype = l:ft . '.lsp-hover' + " Get size information while still having the buffer active + let l:bufferlines = line("$") + let l:maxwidth = max(map(getline(1, '$'), 'strdisplaywidth(v:val)')) if g:lsp_preview_keep_focus " restore focus to the previous window @@ -21,6 +97,17 @@ function! lsp#ui#vim#output#preview(data) abort echo '' + if s:supports_floating && s:win && g:lsp_preview_float + let l:win_config = {} + let l:height = min([winheight(s:win), l:bufferlines]) + let l:width = min([winwidth(s:win), l:maxwidth]) + let l:win_config = s:get_float_positioning(l:height, l:width) + call nvim_win_set_config(s:win, l:win_config ) + augroup lsp_float_preview_close + autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * + autocmd CursorMoved,CursorMovedI,VimResized * call lsp#ui#vim#output#closepreview() + augroup END + endif return '' endfunction diff --git a/doc/vim-lsp.txt b/doc/vim-lsp.txt index 176f0ac86..cd6ecc965 100644 --- a/doc/vim-lsp.txt +++ b/doc/vim-lsp.txt @@ -13,6 +13,7 @@ CONTENTS *vim-lsp-contents* g:lsp_diagnostics_enabled |g:lsp_diagnostics_enabled| g:lsp_auto_enable |g:lsp_auto_enable| g:lsp_preview_keep_focus |g:lsp_preview_keep_focus| + g:lsp_preview_float |g:lsp_preview_float| g:lsp_insert_text_enabled |g:lsp_insert_text_enabled| g:lsp_text_edit_enabled |g:lsp_text_edit_enabled| g:lsp_diagnostics_echo_cursor |g:lsp_diagnostics_echo_cursor| @@ -154,6 +155,23 @@ g:lsp_preview_keep_focus *g:lsp_preview_keep_focus* * |preview-window| can be closed using the default vim mapping - ``. +g:lsp_preview_float *g:lsp_preview_float* + Type: |Number| + Default: `1` + + If set and nvim_win_open() is available, hover information are shown in a + floating window as |preview-window| at the cursor position. + The |preview-window| is closed automatically on cursor moves, unless it is + focused. While focused it may be closed with . + This feature requires neovim 0.4.0 (current master). + + Example: + " Opens preview windows as floating + let g:lsp_preview_float = 1 + + " Opens preview windows as normal windows + let g:lsp_preview_float = 0 + g:lsp_insert_text_enabled *g:lsp_insert_text_enabled* Type: |Number| Default: `1` @@ -566,6 +584,9 @@ Gets the hover information and displays it in the |preview-window|. * |preview-window| can be closed using the default vim mapping - ``. * To control the default focus of |preview-window| for |LspHover| configure |g:lsp_preview_keep_focus|. + * If using neovim with nvim_win_open() available, |g:lsp_preview_float| can be + set to enable a floating preview at the cursor which is closed automatically + on cursormove if not focused and can be closed with if focused. LspNextError *LspNextError* diff --git a/plugin/lsp.vim b/plugin/lsp.vim index 65ae41bae..dfb55f873 100644 --- a/plugin/lsp.vim +++ b/plugin/lsp.vim @@ -25,6 +25,7 @@ let g:lsp_use_event_queue = get(g:, 'lsp_use_event_queue', has('nvim') || has('p let g:lsp_insert_text_enabled= get(g:, 'lsp_insert_text_enabled', 1) let g:lsp_text_edit_enabled = get(g:, 'lsp_text_edit_enabled', has('patch-8.0.1493')) let g:lsp_highlight_references_enabled = get(g:, 'lsp_highlight_references_enabled', 1) +let g:lsp_preview_float = get(g:, 'lsp_preview_float', 1) let g:lsp_get_vim_completion_item = get(g:, 'lsp_get_vim_completion_item', [function('lsp#omni#default_get_vim_completion_item')]) let g:lsp_get_supported_capabilities = get(g:, 'lsp_get_supported_capabilities', [function('lsp#default_get_supported_capabilities')]) From 12a3def11895b3c8ba9d82fc80c8e0b3973ef858 Mon Sep 17 00:00:00 2001 From: Andrej Zieger Date: Tue, 4 Jun 2019 10:59:23 +0200 Subject: [PATCH 02/11] lint --- autoload/lsp/ui/vim/output.vim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autoload/lsp/ui/vim/output.vim b/autoload/lsp/ui/vim/output.vim index 0405b30de..40948cffd 100644 --- a/autoload/lsp/ui/vim/output.vim +++ b/autoload/lsp/ui/vim/output.vim @@ -11,7 +11,7 @@ function! lsp#ui#vim#output#closepreview() abort autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * endfunction -function! s:get_float_positioning(height, width) +function! s:get_float_positioning(height, width) abort let l:height = a:height let l:width = a:width " For a start show it below/above the cursor @@ -31,7 +31,7 @@ function! s:get_float_positioning(height, width) let l:height = &lines -l:y endif endif - let l:col = col(".") + let l:col = col('.') " Positioning is not window but screen relative let l:opts = { \ 'relative': 'win', @@ -48,13 +48,13 @@ function! lsp#ui#vim#output#floatingpreview(data) abort call setbufvar(l:buf, '&signcolumn', 'no') " Try to get as much pace right-bolow the cursor, but at least 10x10 - let l:width = max([float2nr(&columns - col(".") - 10), 10]) + let l:width = max([float2nr(&columns - col('.') - 10), 10]) let l:height = max([&lines - winline() + 1, 10]) let l:opts = s:get_float_positioning(l:height, l:width) let s:win = nvim_open_win(buf, v:true, l:opts) - call nvim_win_set_option(s:win, 'winhl', "Normal:Pmenu,NormalNC:Pmenu") + call nvim_win_set_option(s:win, 'winhl', 'Normal:Pmenu,NormalNC:Pmenu') call nvim_win_set_option(s:win, 'foldenable', v:false) call nvim_win_set_option(s:win, 'wrap', v:true) call nvim_win_set_option(s:win, 'statusline', '') @@ -87,7 +87,7 @@ function! lsp#ui#vim#output#preview(data) abort let &l:filetype = l:ft . '.lsp-hover' " Get size information while still having the buffer active - let l:bufferlines = line("$") + let l:bufferlines = line('$') let l:maxwidth = max(map(getline(1, '$'), 'strdisplaywidth(v:val)')) if g:lsp_preview_keep_focus From 9b6fa5bbdd5332699d0590447db0738afd46aadb Mon Sep 17 00:00:00 2001 From: Andrej Zieger Date: Thu, 13 Jun 2019 08:34:36 +0200 Subject: [PATCH 03/11] Fix hover float positioning --- autoload/lsp/ui/vim/output.vim | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/autoload/lsp/ui/vim/output.vim b/autoload/lsp/ui/vim/output.vim index 40948cffd..3d54a6305 100644 --- a/autoload/lsp/ui/vim/output.vim +++ b/autoload/lsp/ui/vim/output.vim @@ -11,24 +11,43 @@ function! lsp#ui#vim#output#closepreview() abort autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * endfunction +function! s:bufwidth() + let width = winwidth(0) + let numberwidth = max([&numberwidth, strlen(line('$'))+1]) + let numwidth = (&number || &relativenumber)? numberwidth : 0 + let foldwidth = &foldcolumn + + if &signcolumn == 'yes' + let signwidth = 2 + elseif &signcolumn == 'auto' + let signs = execute(printf('sign place buffer=%d', bufnr(''))) + let signs = split(signs, "\n") + let signwidth = len(signs)>2? 2: 0 + else + let signwidth = 0 + endif + return width - numwidth - foldwidth - signwidth +endfunction + + function! s:get_float_positioning(height, width) abort let l:height = a:height let l:width = a:width " For a start show it below/above the cursor " TODO: add option to configure it 'docked' at the bottom/top/right let l:y = winline() - if l:y + l:height >= &lines + if l:y + l:height >= winheight(0) " Float does not fit if l:y - 2 > l:height " Fits above let l:y = winline() - l:height - elseif l:y - 2 > &lines - l:y + elseif l:y - 2 > winheight(0) - l:y " Take space above cursor let l:y = 1 let l:height = winline()-2 else " Take space below cursor - let l:height = &lines -l:y + let l:height = winheight(0) -l:y endif endif let l:col = col('.') @@ -48,7 +67,7 @@ function! lsp#ui#vim#output#floatingpreview(data) abort call setbufvar(l:buf, '&signcolumn', 'no') " Try to get as much pace right-bolow the cursor, but at least 10x10 - let l:width = max([float2nr(&columns - col('.') - 10), 10]) + let l:width = max([s:bufwidth(), 10]) let l:height = max([&lines - winline() + 1, 10]) let l:opts = s:get_float_positioning(l:height, l:width) From de7a59283f956ecf8a6aff6837202c09b143e0a9 Mon Sep 17 00:00:00 2001 From: Andrej Zieger Date: Thu, 13 Jun 2019 11:51:52 +0200 Subject: [PATCH 04/11] Integrate vim8.1 popup for hover/preview --- autoload/lsp/ui/vim/output.vim | 80 +++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 26 deletions(-) diff --git a/autoload/lsp/ui/vim/output.vim b/autoload/lsp/ui/vim/output.vim index 3d54a6305..f3f3f2466 100644 --- a/autoload/lsp/ui/vim/output.vim +++ b/autoload/lsp/ui/vim/output.vim @@ -1,4 +1,4 @@ -let s:supports_floating = exists('*nvim_open_win') +let s:supports_floating = exists('*nvim_open_win') || has('patch-8.1.1517') let s:win = v:false function! lsp#ui#vim#output#closepreview() abort @@ -63,6 +63,7 @@ function! s:get_float_positioning(height, width) abort endfunction function! lsp#ui#vim#output#floatingpreview(data) abort + if has("nvim") let l:buf = nvim_create_buf(v:false, v:true) call setbufvar(l:buf, '&signcolumn', 'no') @@ -83,6 +84,43 @@ function! lsp#ui#vim#output#floatingpreview(data) abort " Enable closing the preview with esc, but map only in the scratch buffer nmap :pclose return s:win + else + return popup_atcursor('...', { + \ 'moved': 'any', + \ 'border': [1, 1, 1, 1], + \}) + endif +endfunction + +function! s:setcontent(lines, ft) abort + if s:supports_floating && g:lsp_preview_float && !has("nvim") + " vim popup + echom "Vimp Popup SetContent" + call setbufline(winbufnr(s:win), 1, a:lines) + call win_execute(s:win, 'setlocal filetype=' . a:ft . '.lsp-hover') + else + " nvim floating + call setline(1, a:lines) + setlocal readonly nomodifiable + let &l:filetype = a:ft . '.lsp-hover' + endif +endfunction + +function! s:adjust_float_placement(bufferlines, maxwidth) abort + if has("nvim") + let l:win_config = {} + let l:height = min([winheight(s:win), a:bufferlines]) + let l:width = min([winwidth(s:win), a:maxwidth]) + let l:win_config = s:get_float_positioning(l:height, l:width) + call nvim_win_set_config(s:win, l:win_config ) + endif +endfunction + +function! s:add_float_closing_hooks() abort + augroup lsp_float_preview_close + autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * + autocmd CursorMoved,CursorMovedI,VimResized * call lsp#ui#vim#output#closepreview() + augroup END endfunction function! lsp#ui#vim#output#preview(data) abort @@ -92,19 +130,16 @@ function! lsp#ui#vim#output#preview(data) abort let l:current_window_id = win_getid() if s:supports_floating && g:lsp_preview_float - call lsp#ui#vim#output#floatingpreview(a:data) + let s:win = lsp#ui#vim#output#floatingpreview(a:data) else execute &previewheight.'new' + let s:win = win_getid() endif - let s:win = win_getid() - - let l:ft = s:append(a:data) - " Delete first empty line - 0delete _ - setlocal readonly nomodifiable + let l:lines = [] + let l:ft = s:append(a:data, l:lines) + call s:setcontent(l:lines, l:ft) - let &l:filetype = l:ft . '.lsp-hover' " Get size information while still having the buffer active let l:bufferlines = line('$') let l:maxwidth = max(map(getline(1, '$'), 'strdisplaywidth(v:val)')) @@ -116,39 +151,32 @@ function! lsp#ui#vim#output#preview(data) abort echo '' - if s:supports_floating && s:win && g:lsp_preview_float - let l:win_config = {} - let l:height = min([winheight(s:win), l:bufferlines]) - let l:width = min([winwidth(s:win), l:maxwidth]) - let l:win_config = s:get_float_positioning(l:height, l:width) - call nvim_win_set_config(s:win, l:win_config ) - augroup lsp_float_preview_close - autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * - autocmd CursorMoved,CursorMovedI,VimResized * call lsp#ui#vim#output#closepreview() - augroup END + if s:supports_floating && s:win && g:lsp_preview_float && has("nvim") + call s:adjust_float_placement(l:bufferlines, l:maxwidth) + call s:add_float_closing_hooks() endif return '' endfunction -function! s:append(data) abort +function! s:append(data, lines) abort if type(a:data) == type([]) for l:entry in a:data - call s:append(entry) + call s:append(entry, a:lines) endfor return 'markdown' elseif type(a:data) == type('') - silent put =a:data + call extend(a:lines, split(a:data, "\n")) return 'markdown' elseif type(a:data) == type({}) && has_key(a:data, 'language') - silent put ='```'.a:data.language - silent put =a:data.value - silent put ='```' + call add(a:lines, '```'.a:data.language) + call extend(a:lines, split(a:data.value, '\n')) + call add(a:lines, '```') return 'markdown' elseif type(a:data) == type({}) && has_key(a:data, 'kind') - silent put =a:data.value + call add(a:lines, a:data.value) return a:data.kind ==? 'plaintext' ? 'text' : a:data.kind endif From 9e9c69718f09ae2b2957d1e4f46a725a99953905 Mon Sep 17 00:00:00 2001 From: Andrej Zieger Date: Thu, 13 Jun 2019 12:07:02 +0200 Subject: [PATCH 05/11] lint --- autoload/lsp/ui/vim/output.vim | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/autoload/lsp/ui/vim/output.vim b/autoload/lsp/ui/vim/output.vim index f3f3f2466..7877cd79a 100644 --- a/autoload/lsp/ui/vim/output.vim +++ b/autoload/lsp/ui/vim/output.vim @@ -11,15 +11,15 @@ function! lsp#ui#vim#output#closepreview() abort autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * endfunction -function! s:bufwidth() +function! s:bufwidth() abort let width = winwidth(0) let numberwidth = max([&numberwidth, strlen(line('$'))+1]) let numwidth = (&number || &relativenumber)? numberwidth : 0 let foldwidth = &foldcolumn - if &signcolumn == 'yes' + if &signcolumn ==? 'yes' let signwidth = 2 - elseif &signcolumn == 'auto' + elseif &signcolumn ==? 'auto' let signs = execute(printf('sign place buffer=%d', bufnr(''))) let signs = split(signs, "\n") let signwidth = len(signs)>2? 2: 0 @@ -63,7 +63,7 @@ function! s:get_float_positioning(height, width) abort endfunction function! lsp#ui#vim#output#floatingpreview(data) abort - if has("nvim") + if has('nvim') let l:buf = nvim_create_buf(v:false, v:true) call setbufvar(l:buf, '&signcolumn', 'no') @@ -93,9 +93,8 @@ function! lsp#ui#vim#output#floatingpreview(data) abort endfunction function! s:setcontent(lines, ft) abort - if s:supports_floating && g:lsp_preview_float && !has("nvim") + if s:supports_floating && g:lsp_preview_float && !has('nvim') " vim popup - echom "Vimp Popup SetContent" call setbufline(winbufnr(s:win), 1, a:lines) call win_execute(s:win, 'setlocal filetype=' . a:ft . '.lsp-hover') else @@ -107,7 +106,7 @@ function! s:setcontent(lines, ft) abort endfunction function! s:adjust_float_placement(bufferlines, maxwidth) abort - if has("nvim") + if has('nvim') let l:win_config = {} let l:height = min([winheight(s:win), a:bufferlines]) let l:width = min([winwidth(s:win), a:maxwidth]) @@ -151,7 +150,7 @@ function! lsp#ui#vim#output#preview(data) abort echo '' - if s:supports_floating && s:win && g:lsp_preview_float && has("nvim") + if s:supports_floating && s:win && g:lsp_preview_float && has('nvim') call s:adjust_float_placement(l:bufferlines, l:maxwidth) call s:add_float_closing_hooks() endif From 36e9f2508500ff136b4d1ed2b99469ce73f81171 Mon Sep 17 00:00:00 2001 From: Andrej Zieger Date: Thu, 13 Jun 2019 13:41:47 +0200 Subject: [PATCH 06/11] Fix hover float positioning above cursor line --- autoload/lsp/ui/vim/output.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autoload/lsp/ui/vim/output.vim b/autoload/lsp/ui/vim/output.vim index 7877cd79a..db084b8b7 100644 --- a/autoload/lsp/ui/vim/output.vim +++ b/autoload/lsp/ui/vim/output.vim @@ -40,7 +40,7 @@ function! s:get_float_positioning(height, width) abort " Float does not fit if l:y - 2 > l:height " Fits above - let l:y = winline() - l:height + let l:y = winline() - l:height -1 elseif l:y - 2 > winheight(0) - l:y " Take space above cursor let l:y = 1 From b242af3140fed67ed2d19c2887104eb93204b3e8 Mon Sep 17 00:00:00 2001 From: Andrej Zieger Date: Fri, 14 Jun 2019 10:26:12 +0200 Subject: [PATCH 07/11] Closing and focusing floating preview (nvim) --- autoload/lsp/ui/vim/output.vim | 33 ++++++++++++++++++++++++++++++--- doc/vim-lsp.txt | 33 +++++++++++++++++++++++++++++++++ plugin/lsp.vim | 3 +++ 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/autoload/lsp/ui/vim/output.vim b/autoload/lsp/ui/vim/output.vim index db084b8b7..eedddbad8 100644 --- a/autoload/lsp/ui/vim/output.vim +++ b/autoload/lsp/ui/vim/output.vim @@ -1,16 +1,41 @@ let s:supports_floating = exists('*nvim_open_win') || has('patch-8.1.1517') let s:win = v:false +let s:prevwin = v:false function! lsp#ui#vim#output#closepreview() abort if win_getid() == s:win " Don't close if window got focus return endif - pclose + "closing floats in vim8.1 must use popup_close() (nvim could use nvim_win_close but pclose + "works) + if s:supports_floating && s:win && g:lsp_preview_float && !has('nvim') + " TODO: + call popup_close(s:win) + else + pclose + endif let s:win = v:false autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * endfunction +function! lsp#ui#vim#output#focuspreview() abort + " This does not work for vim8.1 popup but will work for nvim and old preview + if s:win + if win_getid() != s:win + let s:prevwin = win_getid() + call win_gotoid(s:win) + elseif s:prevwin + " Temporarily disable hooks + " TODO: remove this when closing logic is able to distinguish different move directions + autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * + call win_gotoid(s:prevwin) + call s:add_float_closing_hooks() + let s:prevwin = v:false + endif + endif +endfunction + function! s:bufwidth() abort let width = winwidth(0) let numberwidth = max([&numberwidth, strlen(line('$'))+1]) @@ -83,13 +108,13 @@ function! lsp#ui#vim#output#floatingpreview(data) abort call nvim_win_set_option(s:win, 'cursorline', v:false) " Enable closing the preview with esc, but map only in the scratch buffer nmap :pclose - return s:win else - return popup_atcursor('...', { + let s:win = popup_atcursor('...', { \ 'moved': 'any', \ 'border': [1, 1, 1, 1], \}) endif + return s:win endfunction function! s:setcontent(lines, ft) abort @@ -116,10 +141,12 @@ function! s:adjust_float_placement(bufferlines, maxwidth) abort endfunction function! s:add_float_closing_hooks() abort + if g:lsp_preview_autoclose augroup lsp_float_preview_close autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * autocmd CursorMoved,CursorMovedI,VimResized * call lsp#ui#vim#output#closepreview() augroup END + endif endfunction function! lsp#ui#vim#output#preview(data) abort diff --git a/doc/vim-lsp.txt b/doc/vim-lsp.txt index cd6ecc965..12356be9e 100644 --- a/doc/vim-lsp.txt +++ b/doc/vim-lsp.txt @@ -14,6 +14,7 @@ CONTENTS *vim-lsp-contents* g:lsp_auto_enable |g:lsp_auto_enable| g:lsp_preview_keep_focus |g:lsp_preview_keep_focus| g:lsp_preview_float |g:lsp_preview_float| + g:lsp_preview_autoclose |g:lsp_preview_autoclose| g:lsp_insert_text_enabled |g:lsp_insert_text_enabled| g:lsp_text_edit_enabled |g:lsp_text_edit_enabled| g:lsp_diagnostics_echo_cursor |g:lsp_diagnostics_echo_cursor| @@ -54,6 +55,9 @@ CONTENTS *vim-lsp-contents* Autocommands |vim-lsp-autocommands| lsp_complete_done |lsp_complete_done| Mappings |vim-lsp-mappings| + (lsp-preview-close) |(lsp-preview-close)| + (lsp-preview-focus) |(lsp-preview-focus)| + Autocomplete |vim-lsp-autocomplete| omnifunc |vim-lsp-omnifunc| asyncomplete.vim |vim-lsp-asyncomplete| @@ -172,6 +176,23 @@ g:lsp_preview_float *g:lsp_preview_float* " Opens preview windows as normal windows let g:lsp_preview_float = 0 +g:lsp_preview_autoclose *g:lsp_preview_autoclose* + Type: |Number| + Default: `1` + + Indicates if an opened floating preview shall be automatically closed upon + movement of the cursor. If set to 1, the window will close automatically if + the cursor is moved and the preview is not focused. If set to 0, it will + remain open until explicitly closed (e.g. with (lsp-preview-close), + or when focused). + + Example: + " Preview closes on cursor move + let g:lsp_preview_autoclose = 1 + + " Preview remains open and waits for an explicit call + let g:lsp_preview_autoclose = 0 + g:lsp_insert_text_enabled *g:lsp_insert_text_enabled* Type: |Number| Default: `1` @@ -661,6 +682,8 @@ Available plug mappings are following: (lsp-hover) (lsp-next-error) (lsp-next-reference) + (lsp-preview-close) + (lsp-preview-focus) (lsp-previous-error) (lsp-previous-reference) (lsp-references) @@ -674,6 +697,16 @@ Available plug mappings are following: See also |vim-lsp-commands| +(lsp-preview-close) *(lsp-preview-close)* + +Closes an opened preview window + +(lsp-preview-focus) *(lsp-preview-focus)* + +Transfers focus to an opened preview window or back to the previous window if +focus is already on the preview window. + + =============================================================================== Autocomplete *vim-lsp-autocomplete* diff --git a/plugin/lsp.vim b/plugin/lsp.vim index dfb55f873..c354fe0c3 100644 --- a/plugin/lsp.vim +++ b/plugin/lsp.vim @@ -26,6 +26,7 @@ let g:lsp_insert_text_enabled= get(g:, 'lsp_insert_text_enabled', 1) let g:lsp_text_edit_enabled = get(g:, 'lsp_text_edit_enabled', has('patch-8.0.1493')) let g:lsp_highlight_references_enabled = get(g:, 'lsp_highlight_references_enabled', 1) let g:lsp_preview_float = get(g:, 'lsp_preview_float', 1) +let g:lsp_preview_autoclose = get(g:, 'lsp_preview_autoclose', 1) let g:lsp_get_vim_completion_item = get(g:, 'lsp_get_vim_completion_item', [function('lsp#omni#default_get_vim_completion_item')]) let g:lsp_get_supported_capabilities = get(g:, 'lsp_get_supported_capabilities', [function('lsp#default_get_supported_capabilities')]) @@ -65,6 +66,8 @@ nnoremap (lsp-definition) :call lsp#ui#vim#definition() nnoremap (lsp-document-symbol) :call lsp#ui#vim#document_symbol() nnoremap (lsp-document-diagnostics) :call lsp#ui#vim#diagnostics#document_diagnostics() nnoremap (lsp-hover) :call lsp#ui#vim#hover#get_hover_under_cursor() +nnoremap (lsp-preview-close) :call lsp#ui#vim#output#closepreview() +nnoremap (lsp-preview-focus) :call lsp#ui#vim#output#focuspreview() nnoremap (lsp-next-error) :call lsp#ui#vim#diagnostics#next_error() nnoremap (lsp-previous-error) :call lsp#ui#vim#diagnostics#previous_error() nnoremap (lsp-references) :call lsp#ui#vim#references() From e71ae1846011f9ae08d5a1f5b84aaddbec03089d Mon Sep 17 00:00:00 2001 From: Andrej Zieger Date: Sun, 16 Jun 2019 11:34:18 +0200 Subject: [PATCH 08/11] Renamed variable of preview window id --- autoload/lsp/ui/vim/output.vim | 52 +++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/autoload/lsp/ui/vim/output.vim b/autoload/lsp/ui/vim/output.vim index eedddbad8..69aa02c26 100644 --- a/autoload/lsp/ui/vim/output.vim +++ b/autoload/lsp/ui/vim/output.vim @@ -1,30 +1,30 @@ let s:supports_floating = exists('*nvim_open_win') || has('patch-8.1.1517') -let s:win = v:false +let s:winid = v:false let s:prevwin = v:false function! lsp#ui#vim#output#closepreview() abort - if win_getid() == s:win + if win_getid() == s:winid " Don't close if window got focus return endif "closing floats in vim8.1 must use popup_close() (nvim could use nvim_win_close but pclose "works) - if s:supports_floating && s:win && g:lsp_preview_float && !has('nvim') + if s:supports_floating && s:winid && g:lsp_preview_float && !has('nvim') " TODO: - call popup_close(s:win) + call popup_close(s:winid) else pclose endif - let s:win = v:false + let s:winid = v:false autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * endfunction function! lsp#ui#vim#output#focuspreview() abort " This does not work for vim8.1 popup but will work for nvim and old preview - if s:win - if win_getid() != s:win + if s:winid + if win_getid() != s:winid let s:prevwin = win_getid() - call win_gotoid(s:win) + call win_gotoid(s:winid) elseif s:prevwin " Temporarily disable hooks " TODO: remove this when closing logic is able to distinguish different move directions @@ -98,30 +98,30 @@ function! lsp#ui#vim#output#floatingpreview(data) abort let l:opts = s:get_float_positioning(l:height, l:width) - let s:win = nvim_open_win(buf, v:true, l:opts) - call nvim_win_set_option(s:win, 'winhl', 'Normal:Pmenu,NormalNC:Pmenu') - call nvim_win_set_option(s:win, 'foldenable', v:false) - call nvim_win_set_option(s:win, 'wrap', v:true) - call nvim_win_set_option(s:win, 'statusline', '') - call nvim_win_set_option(s:win, 'number', v:false) - call nvim_win_set_option(s:win, 'relativenumber', v:false) - call nvim_win_set_option(s:win, 'cursorline', v:false) + let s:winid = nvim_open_win(buf, v:true, l:opts) + call nvim_win_set_option(s:winid, 'winhl', 'Normal:Pmenu,NormalNC:Pmenu') + call nvim_win_set_option(s:winid, 'foldenable', v:false) + call nvim_win_set_option(s:winid, 'wrap', v:true) + call nvim_win_set_option(s:winid, 'statusline', '') + call nvim_win_set_option(s:winid, 'number', v:false) + call nvim_win_set_option(s:winid, 'relativenumber', v:false) + call nvim_win_set_option(s:winid, 'cursorline', v:false) " Enable closing the preview with esc, but map only in the scratch buffer nmap :pclose else - let s:win = popup_atcursor('...', { + let s:winid = popup_atcursor('...', { \ 'moved': 'any', \ 'border': [1, 1, 1, 1], \}) endif - return s:win + return s:winid endfunction function! s:setcontent(lines, ft) abort if s:supports_floating && g:lsp_preview_float && !has('nvim') " vim popup - call setbufline(winbufnr(s:win), 1, a:lines) - call win_execute(s:win, 'setlocal filetype=' . a:ft . '.lsp-hover') + call setbufline(winbufnr(s:winid), 1, a:lines) + call win_execute(s:winid, 'setlocal filetype=' . a:ft . '.lsp-hover') else " nvim floating call setline(1, a:lines) @@ -133,10 +133,10 @@ endfunction function! s:adjust_float_placement(bufferlines, maxwidth) abort if has('nvim') let l:win_config = {} - let l:height = min([winheight(s:win), a:bufferlines]) - let l:width = min([winwidth(s:win), a:maxwidth]) + let l:height = min([winheight(s:winid), a:bufferlines]) + let l:width = min([winwidth(s:winid), a:maxwidth]) let l:win_config = s:get_float_positioning(l:height, l:width) - call nvim_win_set_config(s:win, l:win_config ) + call nvim_win_set_config(s:winid, l:win_config ) endif endfunction @@ -156,10 +156,10 @@ function! lsp#ui#vim#output#preview(data) abort let l:current_window_id = win_getid() if s:supports_floating && g:lsp_preview_float - let s:win = lsp#ui#vim#output#floatingpreview(a:data) + let s:winid = lsp#ui#vim#output#floatingpreview(a:data) else execute &previewheight.'new' - let s:win = win_getid() + let s:winid = win_getid() endif let l:lines = [] @@ -177,7 +177,7 @@ function! lsp#ui#vim#output#preview(data) abort echo '' - if s:supports_floating && s:win && g:lsp_preview_float && has('nvim') + if s:supports_floating && s:winid && g:lsp_preview_float && has('nvim') call s:adjust_float_placement(l:bufferlines, l:maxwidth) call s:add_float_closing_hooks() endif From 920f2f8215bd6e7f5693ef906d097c02e4cd1546 Mon Sep 17 00:00:00 2001 From: Andrej Zieger Date: Sun, 16 Jun 2019 14:01:49 +0200 Subject: [PATCH 09/11] autocmd events for open/close floats --- autoload/lsp.vim | 2 ++ autoload/lsp/ui/vim/output.vim | 31 ++++++++++++++++++++++--------- doc/vim-lsp.txt | 16 +++++++++++++--- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/autoload/lsp.vim b/autoload/lsp.vim index 79b2a4568..5434df9c6 100644 --- a/autoload/lsp.vim +++ b/autoload/lsp.vim @@ -26,6 +26,8 @@ augroup _lsp_silent_ autocmd User lsp_server_init silent autocmd User lsp_server_exit silent autocmd User lsp_complete_done silent + autocmd User lsp_float_opened silent + autocmd User lsp_float_closed silent augroup END function! lsp#log_verbose(...) abort diff --git a/autoload/lsp/ui/vim/output.vim b/autoload/lsp/ui/vim/output.vim index 69aa02c26..947731d22 100644 --- a/autoload/lsp/ui/vim/output.vim +++ b/autoload/lsp/ui/vim/output.vim @@ -17,6 +17,7 @@ function! lsp#ui#vim#output#closepreview() abort endif let s:winid = v:false autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * + doautocmd User lsp_float_closed endfunction function! lsp#ui#vim#output#focuspreview() abort @@ -149,18 +150,27 @@ function! s:add_float_closing_hooks() abort endif endfunction +function! lsp#ui#vim#output#getpreviewwinid() abort + return s:winid +endfunction + +function! s:open_preview(data) abort + if s:supports_floating && g:lsp_preview_float + let l:winid = lsp#ui#vim#output#floatingpreview(a:data) + else + execute &previewheight.'new' + let l:winid = win_getid() + endif + return l:winid +endfunction + function! lsp#ui#vim#output#preview(data) abort " Close any previously opened preview window pclose let l:current_window_id = win_getid() - if s:supports_floating && g:lsp_preview_float - let s:winid = lsp#ui#vim#output#floatingpreview(a:data) - else - execute &previewheight.'new' - let s:winid = win_getid() - endif + let s:winid = s:open_preview(a:data) let l:lines = [] let l:ft = s:append(a:data, l:lines) @@ -177,9 +187,12 @@ function! lsp#ui#vim#output#preview(data) abort echo '' - if s:supports_floating && s:winid && g:lsp_preview_float && has('nvim') - call s:adjust_float_placement(l:bufferlines, l:maxwidth) - call s:add_float_closing_hooks() + if s:supports_floating && s:winid && g:lsp_preview_float + if has('nvim') + call s:adjust_float_placement(l:bufferlines, l:maxwidth) + call s:add_float_closing_hooks() + endif + doautocmd User lsp_float_opened endif return '' endfunction diff --git a/doc/vim-lsp.txt b/doc/vim-lsp.txt index 12356be9e..f7d8b2686 100644 --- a/doc/vim-lsp.txt +++ b/doc/vim-lsp.txt @@ -163,11 +163,16 @@ g:lsp_preview_float *g:lsp_preview_float* Type: |Number| Default: `1` - If set and nvim_win_open() is available, hover information are shown in a - floating window as |preview-window| at the cursor position. + If set and nvim_win_open() or popup_create is available, hover information + are shown in a floating window as |preview-window| at the cursor position. The |preview-window| is closed automatically on cursor moves, unless it is focused. While focused it may be closed with . - This feature requires neovim 0.4.0 (current master). + After opening an autocmd User event lsp_float_opened is issued, as well as + and lsp_float_closed upon closing. This can be used to alter the preview + window (using lsp#ui#vim#output#getpreviewwinid() to get the window id), or + setup custom bindings while a preview is open. + This feature requires neovim 0.4.0 (current master) or + Vim8.1 with has('patch-8.1.1517'). Example: " Opens preview windows as floating @@ -176,6 +181,11 @@ g:lsp_preview_float *g:lsp_preview_float* " Opens preview windows as normal windows let g:lsp_preview_float = 0 + " Close preview window with + autocmd User lsp_float_opened nmap + \ (lsp-preview-close) + autocmd User lsp_float_closed nunmap + g:lsp_preview_autoclose *g:lsp_preview_autoclose* Type: |Number| Default: `1` From 71ae724ba697b781693f84060aad687c48ea7cbe Mon Sep 17 00:00:00 2001 From: Andrej Zieger Date: Mon, 24 Jun 2019 09:53:41 +0200 Subject: [PATCH 10/11] Closing of floating preview & lightlinefix (vim8.1) --- autoload/lsp/ui/vim/output.vim | 13 ++++++++++++- ftplugin/lsp-hover.vim | 7 ++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/autoload/lsp/ui/vim/output.vim b/autoload/lsp/ui/vim/output.vim index 947731d22..5f5d2e001 100644 --- a/autoload/lsp/ui/vim/output.vim +++ b/autoload/lsp/ui/vim/output.vim @@ -10,12 +10,13 @@ function! lsp#ui#vim#output#closepreview() abort "closing floats in vim8.1 must use popup_close() (nvim could use nvim_win_close but pclose "works) if s:supports_floating && s:winid && g:lsp_preview_float && !has('nvim') - " TODO: call popup_close(s:winid) else pclose endif let s:winid = v:false + augroup lsp_float_preview_close + augroup end autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * doautocmd User lsp_float_closed endfunction @@ -122,7 +123,17 @@ function! s:setcontent(lines, ft) abort if s:supports_floating && g:lsp_preview_float && !has('nvim') " vim popup call setbufline(winbufnr(s:winid), 1, a:lines) + let l:lightline_toggle = v:false + if exists('#lightline') && !has("nvim") + " Lightline does not work in popups but does not recognize it yet. + " It is ugly to have an check for an other plugin here, better fix lightline... + let l:lightline_toggle = v:true + call lightline#disable() + endif call win_execute(s:winid, 'setlocal filetype=' . a:ft . '.lsp-hover') + if l:lightline_toggle + call lightline#enable() + endif else " nvim floating call setline(1, a:lines) diff --git a/ftplugin/lsp-hover.vim b/ftplugin/lsp-hover.vim index 53559a7cc..67557341c 100644 --- a/ftplugin/lsp-hover.vim +++ b/ftplugin/lsp-hover.vim @@ -1,6 +1,11 @@ " No usual did_ftplugin header here as we NEED to run this always -setlocal previewwindow buftype=nofile bufhidden=wipe noswapfile nobuflisted +if has('patch-8.1.1517') && g:lsp_preview_float && !has('nvim') + " Can not set buftype or popup_close will fail with 'not a popup window' + setlocal previewwindow bufhidden=wipe noswapfile nobuflisted +else + setlocal previewwindow buftype=nofile bufhidden=wipe noswapfile nobuflisted +endif setlocal nocursorline nofoldenable if has('syntax') From ae5687d019f77e6098f357adc421b3bc9b400cb2 Mon Sep 17 00:00:00 2001 From: Andrej Zieger Date: Tue, 25 Jun 2019 12:39:39 +0200 Subject: [PATCH 11/11] Added doubletap functionality to preview --- autoload/lsp/ui/vim/output.vim | 15 +++++++++++++-- doc/vim-lsp.txt | 19 +++++++++++++++++++ plugin/lsp.vim | 1 + 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/autoload/lsp/ui/vim/output.vim b/autoload/lsp/ui/vim/output.vim index 5f5d2e001..3d7efd907 100644 --- a/autoload/lsp/ui/vim/output.vim +++ b/autoload/lsp/ui/vim/output.vim @@ -1,6 +1,7 @@ let s:supports_floating = exists('*nvim_open_win') || has('patch-8.1.1517') let s:winid = v:false let s:prevwin = v:false +let s:preview_data = v:false function! lsp#ui#vim#output#closepreview() abort if win_getid() == s:winid @@ -12,9 +13,10 @@ function! lsp#ui#vim#output#closepreview() abort if s:supports_floating && s:winid && g:lsp_preview_float && !has('nvim') call popup_close(s:winid) else - pclose + pclose endif let s:winid = v:false + let s:preview_data = v:false augroup lsp_float_preview_close augroup end autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * @@ -124,7 +126,7 @@ function! s:setcontent(lines, ft) abort " vim popup call setbufline(winbufnr(s:winid), 1, a:lines) let l:lightline_toggle = v:false - if exists('#lightline') && !has("nvim") + if exists('#lightline') && !has('nvim') " Lightline does not work in popups but does not recognize it yet. " It is ugly to have an check for an other plugin here, better fix lightline... let l:lightline_toggle = v:true @@ -176,6 +178,14 @@ function! s:open_preview(data) abort endfunction function! lsp#ui#vim#output#preview(data) abort + if s:winid && type(s:preview_data) == type(a:data) + \ && s:preview_data == a:data + \ && type(g:lsp_preview_doubletap) == 3 + \ && len(g:lsp_preview_doubletap) >= 1 + \ && type(g:lsp_preview_doubletap[0]) == 2 + echo '' + return call(g:lsp_preview_doubletap[0], []) + endif " Close any previously opened preview window pclose @@ -183,6 +193,7 @@ function! lsp#ui#vim#output#preview(data) abort let s:winid = s:open_preview(a:data) + let s:preview_data = a:data let l:lines = [] let l:ft = s:append(a:data, l:lines) call s:setcontent(l:lines, l:ft) diff --git a/doc/vim-lsp.txt b/doc/vim-lsp.txt index f7d8b2686..5125c926e 100644 --- a/doc/vim-lsp.txt +++ b/doc/vim-lsp.txt @@ -15,6 +15,7 @@ CONTENTS *vim-lsp-contents* g:lsp_preview_keep_focus |g:lsp_preview_keep_focus| g:lsp_preview_float |g:lsp_preview_float| g:lsp_preview_autoclose |g:lsp_preview_autoclose| + g:lsp_preview_doubletap |g:lsp_preview_doubletap| g:lsp_insert_text_enabled |g:lsp_insert_text_enabled| g:lsp_text_edit_enabled |g:lsp_text_edit_enabled| g:lsp_diagnostics_echo_cursor |g:lsp_diagnostics_echo_cursor| @@ -203,6 +204,24 @@ g:lsp_preview_autoclose *g:lsp_preview_autoclose* " Preview remains open and waits for an explicit call let g:lsp_preview_autoclose = 0 +g:lsp_preview_doubletap *g:lsp_preview_doubletap* + Type: |List| + Default: `[function('lsp#ui#vim#output#focuspreview')]` + + When preview is called twice with the same data while the preview is still + open, the function in `lsp_preview_doubletap` is called instead. To disable + this and just "refresh" the preview, set to ´0´. + + Example: + " Focus preview on repeated preview (does not work for vim8.1 popups) + let g:lsp_preview_doubletap = [function('lsp#ui#vim#output#focuspreview')] + + " Closes the preview window on the second call to preview + let g:lsp_preview_doubletap = [function('lsp#ui#vim#output#closepreview')] + + " Disables double tap feature; refreshes the preview on consecutive taps + let g:lsp_preview_doubletap = 0 + g:lsp_insert_text_enabled *g:lsp_insert_text_enabled* Type: |Number| Default: `1` diff --git a/plugin/lsp.vim b/plugin/lsp.vim index c354fe0c3..f3c746ae2 100644 --- a/plugin/lsp.vim +++ b/plugin/lsp.vim @@ -27,6 +27,7 @@ let g:lsp_text_edit_enabled = get(g:, 'lsp_text_edit_enabled', has('patch-8.0.14 let g:lsp_highlight_references_enabled = get(g:, 'lsp_highlight_references_enabled', 1) let g:lsp_preview_float = get(g:, 'lsp_preview_float', 1) let g:lsp_preview_autoclose = get(g:, 'lsp_preview_autoclose', 1) +let g:lsp_preview_doubletap = get(g:, 'lsp_preview_doubletap', [function('lsp#ui#vim#output#focuspreview')]) let g:lsp_get_vim_completion_item = get(g:, 'lsp_get_vim_completion_item', [function('lsp#omni#default_get_vim_completion_item')]) let g:lsp_get_supported_capabilities = get(g:, 'lsp_get_supported_capabilities', [function('lsp#default_get_supported_capabilities')])