mirror of
https://github.com/prabirshrestha/vim-lsp.git
synced 2025-12-14 20:35:59 +01:00
[WIP] Popup documentation (#507)
* Show documentation in Vim popup * Use timer * Reuse logic from output.vim * Change default text * Rename functions * Refactor * Use v:event * Add comment * Remove log * Refactor * Implement documentation in Neovim * Cleanup Neovim popup * Let Neovim float take all available space * Extract get_size_info * Reuse sizing logic from output.vim * Fix Neovim positioning being reset * Update autoload/lsp/ui/vim/documentation.vim Co-Authored-By: Christian Clason <christian.clason@uni-due.de> * Make vint happy * Retrigger Travis CI * add g:lsp_documentation_float flag * fix lint issues Co-authored-by: Christian Clason <christian.clason@uni-due.de> Co-authored-by: Prabir Shrestha <mail@prabir.me>
This commit is contained in:
committed by
GitHub
parent
b39f18ab8c
commit
a3673dde78
@@ -802,6 +802,8 @@ function! s:handle_initialize(server_name, data) abort
|
||||
call l:Init_callback(a:data)
|
||||
endfor
|
||||
|
||||
call lsp#ui#vim#documentation#setup()
|
||||
|
||||
doautocmd User lsp_server_init
|
||||
endfunction
|
||||
|
||||
|
||||
76
autoload/lsp/ui/vim/documentation.vim
Normal file
76
autoload/lsp/ui/vim/documentation.vim
Normal file
@@ -0,0 +1,76 @@
|
||||
let s:use_vim_popup = has('patch-8.1.1517') && !has('nvim')
|
||||
let s:use_nvim_float = exists('*nvim_open_win') && has('nvim')
|
||||
|
||||
let s:last_popup_id = -1
|
||||
|
||||
function! s:complete_done() abort
|
||||
if !g:lsp_documentation_float | return | endif
|
||||
" Use a timer to avoid textlock (see :h textlock).
|
||||
let l:event = deepcopy(v:event)
|
||||
call timer_start(0, {-> s:show_documentation(l:event)})
|
||||
endfunction
|
||||
|
||||
function! s:show_documentation(event) abort
|
||||
call s:close_popup()
|
||||
|
||||
if !has_key(a:event['completed_item'], 'info') || empty(a:event['completed_item']['info'])
|
||||
return
|
||||
endif
|
||||
|
||||
let l:right = wincol() < winwidth(0) / 2
|
||||
|
||||
" TODO: Neovim
|
||||
if l:right
|
||||
let l:line = a:event['row'] + 1
|
||||
let l:col = a:event['col'] + a:event['width'] + 1 + (a:event['scrollbar'] ? 1 : 0)
|
||||
else
|
||||
let l:line = a:event['row'] + 1
|
||||
let l:col = a:event['col'] - 1
|
||||
endif
|
||||
|
||||
" TODO: Support markdown
|
||||
let l:data = split(a:event['completed_item']['info'], '\n')
|
||||
let l:lines = []
|
||||
let l:syntax_lines = []
|
||||
let l:ft = lsp#ui#vim#output#append(l:data, l:lines, l:syntax_lines)
|
||||
|
||||
let l:current_win_id = win_getid()
|
||||
|
||||
if s:use_vim_popup
|
||||
let s:last_popup_id = popup_create('(no documentation available)', {'line': l:line, 'col': l:col, 'pos': l:right ? 'topleft' : 'topright', 'padding': [0, 1, 0, 1]})
|
||||
elseif s:use_nvim_float
|
||||
let l:height = winheight(0) - l:line + 1
|
||||
let l:width = l:right ? winwidth(0) - l:col + 1 : l:col
|
||||
let s:last_popup_id = lsp#ui#vim#output#floatingpreview([])
|
||||
call nvim_win_set_config(s:last_popup_id, {'relative': 'win', 'anchor': l:right ? 'NW' : 'NE', 'row': l:line - 1, 'col': l:col - 1, 'height': l:height, 'width': l:width})
|
||||
endif
|
||||
|
||||
call setbufvar(winbufnr(s:last_popup_id), 'lsp_syntax_highlights', l:syntax_lines)
|
||||
call setbufvar(winbufnr(s:last_popup_id), 'lsp_do_conceal', 1)
|
||||
call lsp#ui#vim#output#setcontent(s:last_popup_id, l:lines, l:ft)
|
||||
let [l:bufferlines, l:maxwidth] = lsp#ui#vim#output#get_size_info()
|
||||
|
||||
call win_gotoid(l:current_win_id)
|
||||
|
||||
if s:use_nvim_float
|
||||
call lsp#ui#vim#output#adjust_float_placement(l:bufferlines, l:maxwidth)
|
||||
call nvim_win_set_config(s:last_popup_id, {'relative': 'win', 'row': l:line - 1, 'col': l:col - 1})
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:close_popup() abort
|
||||
if s:last_popup_id >= 0
|
||||
if s:use_vim_popup | call popup_close(s:last_popup_id) | endif
|
||||
if s:use_nvim_float | call nvim_win_close(s:last_popup_id, 1) | endif
|
||||
|
||||
let s:last_popup_id = -1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#documentation#setup() abort
|
||||
augroup lsp_documentation_popup
|
||||
autocmd!
|
||||
autocmd CompleteChanged * call s:complete_done()
|
||||
autocmd CompleteDone * call s:close_popup()
|
||||
augroup end
|
||||
endfunction
|
||||
@@ -149,10 +149,10 @@ function! lsp#ui#vim#output#floatingpreview(data) abort
|
||||
return s:winid
|
||||
endfunction
|
||||
|
||||
function! s:setcontent(lines, ft) abort
|
||||
function! lsp#ui#vim#output#setcontent(winid, lines, ft) abort
|
||||
if s:use_vim_popup
|
||||
" vim popup
|
||||
call setbufline(winbufnr(s:winid), 1, a:lines)
|
||||
call setbufline(winbufnr(a:winid), 1, a:lines)
|
||||
call win_execute(s:winid, 'setlocal filetype=' . a:ft . '.lsp-hover')
|
||||
else
|
||||
" nvim floating or preview
|
||||
@@ -162,7 +162,7 @@ function! s:setcontent(lines, ft) abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:adjust_float_placement(bufferlines, maxwidth) abort
|
||||
function! lsp#ui#vim#output#adjust_float_placement(bufferlines, maxwidth) abort
|
||||
if s:use_nvim_float
|
||||
let l:win_config = {}
|
||||
let l:height = min([winheight(s:winid), a:bufferlines])
|
||||
@@ -279,6 +279,27 @@ function! s:align_preview(options) abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#output#get_size_info() abort
|
||||
" Get size information while still having the buffer active
|
||||
let l:maxwidth = max(map(getline(1, '$'), 'strdisplaywidth(v:val)'))
|
||||
if g:lsp_preview_max_width > 0
|
||||
let l:bufferlines = 0
|
||||
let l:maxwidth = min([g:lsp_preview_max_width, l:maxwidth])
|
||||
|
||||
" Determine, for each line, how many "virtual" lines it spans, and add
|
||||
" these together for all lines in the buffer
|
||||
for l:line in getline(1, '$')
|
||||
let l:num_lines = str2nr(string(ceil(strdisplaywidth(l:line) * 1.0 / g:lsp_preview_max_width)))
|
||||
let l:bufferlines += max([l:num_lines, 1])
|
||||
endfor
|
||||
else
|
||||
let l:bufferlines = line('$')
|
||||
endif
|
||||
|
||||
return [l:bufferlines, l:maxwidth]
|
||||
return [l:bufferlines, l:maxwidth]
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#output#float_supported() abort
|
||||
return s:use_vim_popup || s:use_nvim_float
|
||||
endfunction
|
||||
@@ -307,7 +328,7 @@ function! lsp#ui#vim#output#preview(server, data, options) abort
|
||||
let s:preview_data = a:data
|
||||
let l:lines = []
|
||||
let l:syntax_lines = []
|
||||
let l:ft = s:append(a:data, l:lines, l:syntax_lines)
|
||||
let l:ft = lsp#ui#vim#output#append(a:data, l:lines, l:syntax_lines)
|
||||
|
||||
" If the server response is empty content, we don't display anything.
|
||||
if empty(l:lines) && empty(l:syntax_lines)
|
||||
@@ -328,23 +349,9 @@ function! lsp#ui#vim#output#preview(server, data, options) abort
|
||||
|
||||
call setbufvar(winbufnr(s:winid), 'lsp_syntax_highlights', l:syntax_lines)
|
||||
call setbufvar(winbufnr(s:winid), 'lsp_do_conceal', l:do_conceal)
|
||||
call s:setcontent(l:lines, l:ft)
|
||||
call lsp#ui#vim#output#setcontent(s:winid, l:lines, l:ft)
|
||||
|
||||
" Get size information while still having the buffer active
|
||||
let l:maxwidth = max(map(getline(1, '$'), 'strdisplaywidth(v:val)'))
|
||||
if g:lsp_preview_max_width > 0
|
||||
let l:bufferlines = 0
|
||||
let l:maxwidth = min([g:lsp_preview_max_width, l:maxwidth])
|
||||
|
||||
" Determine, for each line, how many "virtual" lines it spans, and add
|
||||
" these together for all lines in the buffer
|
||||
for l:line in getline(1, '$')
|
||||
let l:num_lines = str2nr(string(ceil(strdisplaywidth(l:line) * 1.0 / g:lsp_preview_max_width)))
|
||||
let l:bufferlines += max([l:num_lines, 1])
|
||||
endfor
|
||||
else
|
||||
let l:bufferlines = line('$')
|
||||
endif
|
||||
let [l:bufferlines, l:maxwidth] = lsp#ui#vim#output#get_size_info()
|
||||
|
||||
if s:use_preview
|
||||
" Set statusline
|
||||
@@ -361,17 +368,16 @@ function! lsp#ui#vim#output#preview(server, data, options) abort
|
||||
echo ''
|
||||
|
||||
if s:winid && (s:use_vim_popup || s:use_nvim_float)
|
||||
if s:use_nvim_float
|
||||
" Neovim floats
|
||||
call s:adjust_float_placement(l:bufferlines, l:maxwidth)
|
||||
call s:set_cursor(l:current_window_id, a:options)
|
||||
call s:add_float_closing_hooks()
|
||||
elseif s:use_vim_popup
|
||||
" Vim popups
|
||||
call s:set_cursor(l:current_window_id, a:options)
|
||||
endif
|
||||
|
||||
doautocmd User lsp_float_opened
|
||||
if s:use_nvim_float
|
||||
" Neovim floats
|
||||
call lsp#ui#vim#output#adjust_float_placement(l:bufferlines, l:maxwidth)
|
||||
call s:set_cursor(l:current_window_id, a:options)
|
||||
call s:add_float_closing_hooks()
|
||||
elseif s:use_vim_popup
|
||||
" Vim popups
|
||||
call s:set_cursor(l:current_window_id, a:options)
|
||||
endif
|
||||
doautocmd User lsp_float_opened
|
||||
endif
|
||||
|
||||
if !g:lsp_preview_keep_focus
|
||||
@@ -385,10 +391,10 @@ function! s:escape_string_for_display(str) abort
|
||||
return substitute(substitute(a:str, '\r\n', '\n', 'g'), '\r', '\n', 'g')
|
||||
endfunction
|
||||
|
||||
function! s:append(data, lines, syntax_lines) abort
|
||||
if type(a:data) ==# type([])
|
||||
function! lsp#ui#vim#output#append(data, lines, syntax_lines) abort
|
||||
if type(a:data) == type([])
|
||||
for l:entry in a:data
|
||||
call s:append(l:entry, a:lines, a:syntax_lines)
|
||||
call lsp#ui#vim#output#append(l:entry, a:lines, a:syntax_lines)
|
||||
endfor
|
||||
|
||||
return 'markdown'
|
||||
|
||||
@@ -20,10 +20,11 @@ CONTENTS *vim-lsp-contents*
|
||||
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_documentation_float |g:lsp_documentation_float|
|
||||
g:lsp_diagnostics_echo_cursor |g:lsp_diagnostics_echo_cursor|
|
||||
g:lsp_diagnostics_echo_delay |g:lsp_diagnostics_echo_delay|
|
||||
g:lsp_diagnostics_float_cursor |g:lsp_diagnostics_float_cursor|
|
||||
g:lsp_diagnostics_float_delay |g:lsp_diagnostics_float_delay|
|
||||
g:lsp_diagnostics_float_cursor |g:lsp_diagnostics_float_cursor|
|
||||
g:lsp_diagnostics_float_delay |g:lsp_diagnostics_float_delay|
|
||||
g:lsp_signs_enabled |g:lsp_signs_enabled|
|
||||
g:lsp_signs_priority |g:lsp_signs_priority|
|
||||
g:lsp_signs_priority_map |g:lsp_signs_priority_map|
|
||||
@@ -368,6 +369,16 @@ g:lsp_text_edit_enabled *g:lsp_text_edit_enabled*
|
||||
let g:lsp_text_edit_enabled = 1
|
||||
let g:lsp_text_edit_enabled = 0
|
||||
|
||||
g:lsp_documentation_float *g:lsp_documentation_float*
|
||||
Type: |Number|
|
||||
Default: `1`
|
||||
|
||||
Enables floating window documentation for complete items.
|
||||
|
||||
Example: >
|
||||
let g:lsp_documentation_float = 1
|
||||
let g:lsp_documentation_float = 0
|
||||
|
||||
g:lsp_diagnostics_echo_cursor *g:lsp_diagnostics_echo_cursor*
|
||||
Type: |Number|
|
||||
Default: `0`
|
||||
|
||||
@@ -21,6 +21,7 @@ let g:lsp_signs_information = get(g:, 'lsp_signs_information', {})
|
||||
let g:lsp_signs_hint = get(g:, 'lsp_signs_hint', {})
|
||||
let g:lsp_signs_priority = get(g:, 'lsp_signs_priority', 10)
|
||||
let g:lsp_signs_priority_map = get(g:, 'lsp_signs_priority_map', {})
|
||||
let g:lsp_documentation_float = get(g:, 'lsp_documentation_float', 1)
|
||||
let g:lsp_diagnostics_enabled = get(g:, 'lsp_diagnostics_enabled', 1)
|
||||
let g:lsp_diagnostics_echo_cursor = get(g:, 'lsp_diagnostics_echo_cursor', 0)
|
||||
let g:lsp_diagnostics_echo_delay = get(g:, 'lsp_diagnostics_echo_delay', 500)
|
||||
|
||||
Reference in New Issue
Block a user