Show diagnostics in a floating window (#700)

* fix comment

* fix indent

* support diagnostics in a floating window

* doc: add g:lsp_diagnostics_float_{cursor,delay}

* fix vint errors except unused variables

* suppress vint unused variable errors

* lint: use robust operator
This commit is contained in:
Fujiwara Takuya
2020-02-10 01:44:05 +09:00
committed by GitHub
parent f33d624290
commit 52539a54ae
14 changed files with 323 additions and 246 deletions

View File

@@ -3,7 +3,7 @@ cmdargs:
policies: policies:
ProhibitUnusedVariable: ProhibitUnusedVariable:
enabled: true enabled: false
ProhibitImplicitScopeVariable: ProhibitImplicitScopeVariable:
enabled: true enabled: true
ProhibitNoAbortFunction: ProhibitNoAbortFunction:

View File

@@ -115,7 +115,7 @@ endfunction
" "exited", "starting", "failed", "running", "not running" " "exited", "starting", "failed", "running", "not running"
function! lsp#get_server_status(...) abort function! lsp#get_server_status(...) abort
if a:0 == 0 if a:0 == 0
let l:strs = map(keys(s:servers), {k, v -> v . ": " . s:server_status(v)}) let l:strs = map(keys(s:servers), {k, v -> v . ': ' . s:server_status(v)})
return join(l:strs, "\n") return join(l:strs, "\n")
else else
return s:server_status(a:1) return s:server_status(a:1)
@@ -189,7 +189,7 @@ function! s:register_events() abort
if exists('##TextChangedP') if exists('##TextChangedP')
autocmd TextChangedP * call s:on_text_document_did_change() autocmd TextChangedP * call s:on_text_document_did_change()
endif endif
if g:lsp_diagnostics_echo_cursor || g:lsp_highlight_references_enabled if g:lsp_diagnostics_echo_cursor || g:lsp_diagnostics_float_cursor || g:lsp_highlight_references_enabled
autocmd CursorMoved * call s:on_cursor_moved() autocmd CursorMoved * call s:on_cursor_moved()
endif endif
autocmd BufWinEnter,BufWinLeave,InsertEnter * call lsp#ui#vim#references#clean_references() autocmd BufWinEnter,BufWinLeave,InsertEnter * call lsp#ui#vim#references#clean_references()
@@ -243,6 +243,8 @@ function! s:on_cursor_moved() abort
if g:lsp_diagnostics_echo_cursor if g:lsp_diagnostics_echo_cursor
call lsp#ui#vim#diagnostics#echo#cursor_moved() call lsp#ui#vim#diagnostics#echo#cursor_moved()
elseif g:lsp_diagnostics_float_cursor && lsp#ui#vim#output#float_supported()
call lsp#ui#vim#diagnostics#float#cursor_moved()
endif endif
if g:lsp_highlight_references_enabled if g:lsp_highlight_references_enabled
@@ -517,7 +519,7 @@ function! s:ensure_init(buf, server_name, cb) abort
if has_key(l:server_info, 'capabilities') if has_key(l:server_info, 'capabilities')
let l:capabilities = l:server_info['capabilities'] let l:capabilities = l:server_info['capabilities']
else else
let l:capabilities = call(g:lsp_get_supported_capabilities[0], [server_info]) let l:capabilities = call(g:lsp_get_supported_capabilities[0], [l:server_info])
endif endif
let l:request = { let l:request = {
@@ -886,8 +888,8 @@ function! s:add_didchange_queue(buf) abort
call add(s:didchange_queue, a:buf) call add(s:didchange_queue, a:buf)
call lsp#log('s:send_didchange_queue() will be triggered') call lsp#log('s:send_didchange_queue() will be triggered')
call timer_stop(s:didchange_timer) call timer_stop(s:didchange_timer)
let lazy = &updatetime > 1000 ? &updatetime : 1000 let l:lazy = &updatetime > 1000 ? &updatetime : 1000
let s:didchange_timer = timer_start(lazy, function('s:send_didchange_queue')) let s:didchange_timer = timer_start(l:lazy, function('s:send_didchange_queue'))
endfunction endfunction
function! s:send_didchange_queue(...) abort function! s:send_didchange_queue(...) abort

View File

@@ -1,5 +1,5 @@
let s:save_cpo = &cpo let s:save_cpo = &cpoptions
set cpo&vim set cpoptions&vim
let s:clients = {} " { client_id: ctx } let s:clients = {} " { client_id: ctx }
@@ -268,10 +268,10 @@ function! s:lsp_get_last_request_id(id) abort
endfunction endfunction
function! s:lsp_is_error(obj_or_response) abort function! s:lsp_is_error(obj_or_response) abort
let vt = type(a:obj_or_response) let l:vt = type(a:obj_or_response)
if vt == type('') if l:vt == type('')
return len(a:obj_or_response) > 0 return len(a:obj_or_response) > 0
elseif vt == type({}) elseif l:vt == type({})
return has_key(a:obj_or_response, 'error') return has_key(a:obj_or_response, 'error')
endif endif
return 0 return 0
@@ -330,6 +330,6 @@ endfunction
" }}} " }}}
let &cpo = s:save_cpo let &cpoptions = s:save_cpo
unlet s:save_cpo unlet s:save_cpo
" vim sw=4 ts=4 et " vim sw=4 ts=4 et

View File

@@ -249,14 +249,14 @@ function! lsp#ui#vim#document_format() abort
endfunction endfunction
function! lsp#ui#vim#stop_server(...) abort function! lsp#ui#vim#stop_server(...) abort
let l:name = get(a:000, 0, '') let l:name = get(a:000, 0, '')
for l:server in lsp#get_whitelisted_servers() for l:server in lsp#get_whitelisted_servers()
if !empty(l:name) && l:server != l:name if !empty(l:name) && l:server != l:name
continue continue
endif endif
echo 'Stopping' l:server 'server ...' echo 'Stopping' l:server 'server ...'
call lsp#stop_server(server) call lsp#stop_server(l:server)
endfor endfor
endfunction endfunction
function! s:get_selection_pos(type) abort function! s:get_selection_pos(type) abort
@@ -439,15 +439,15 @@ function! s:handle_location(ctx, server, type, data) abort "ctx = {counter, list
if has_key(l:loc,'viewstart') " showing a locationLink if has_key(l:loc,'viewstart') " showing a locationLink
let l:view = l:lines[l:loc['viewstart'] : l:loc['viewend']] let l:view = l:lines[l:loc['viewstart'] : l:loc['viewend']]
call lsp#ui#vim#output#preview(a:server, l:view, { call lsp#ui#vim#output#preview(a:server, l:view, {
\ 'statusline': ' LSP Peek ' . a:type, \ 'statusline': ' LSP Peek ' . a:type,
\ 'filetype': &filetype \ 'filetype': &filetype
\ }) \ })
else " showing a location else " showing a location
call lsp#ui#vim#output#preview(a:server, l:lines, { call lsp#ui#vim#output#preview(a:server, l:lines, {
\ 'statusline': ' LSP Peek ' . a:type, \ 'statusline': ' LSP Peek ' . a:type,
\ 'cursor': { 'line': l:loc['lnum'], 'col': l:loc['col'], 'align': g:lsp_peek_alignment }, \ 'cursor': { 'line': l:loc['lnum'], 'col': l:loc['col'], 'align': g:lsp_peek_alignment },
\ 'filetype': &filetype \ 'filetype': &filetype
\ }) \ })
endif endif
endif endif
endif endif
@@ -582,9 +582,9 @@ function! s:get_treeitem_for_tree_hierarchy(Callback, object) dict abort
endfunction endfunction
function! lsp#ui#vim#code_action() abort function! lsp#ui#vim#code_action() abort
call lsp#ui#vim#code_action#do({ call lsp#ui#vim#code_action#do({
\ 'sync': v:false, \ 'sync': v:false,
\ 'selection': v:false, \ 'selection': v:false,
\ 'query': '', \ 'query': '',
\ }) \ })
endfunction endfunction

View File

@@ -35,7 +35,7 @@ function! lsp#ui#vim#diagnostics#document_diagnostics() abort
endif endif
let l:result = [] let l:result = []
for [l:server_name, l:data] in items(l:diagnostics) for l:data in values(l:diagnostics)
let l:result += lsp#ui#vim#utils#diagnostics_to_loc_list(l:data) let l:result += lsp#ui#vim#utils#diagnostics_to_loc_list(l:data)
endfor endfor

View File

@@ -1,6 +1,6 @@
function! lsp#ui#vim#diagnostics#echo#cursor_moved() abort function! lsp#ui#vim#diagnostics#echo#cursor_moved() abort
if mode() isnot# 'n' if mode() isnot# 'n'
" dont' show echo only in normal mode " show echo only in normal mode
return return
endif endif

View File

@@ -0,0 +1,32 @@
function! lsp#ui#vim#diagnostics#float#cursor_moved() abort
call s:stop_cursor_moved_timer()
let l:current_pos = getcurpos()[0:2]
" use timer to avoid recalculation
if !exists('s:last_pos') || l:current_pos != s:last_pos
let s:last_pos = l:current_pos
let s:cursor_moved_timer = timer_start(g:lsp_diagnostics_float_delay, function('s:float_diagnostics_under_cursor'))
endif
endfunction
function! s:float_diagnostics_under_cursor(...) abort
let l:diagnostic = lsp#ui#vim#diagnostics#get_diagnostics_under_cursor()
if !empty(l:diagnostic) && has_key(l:diagnostic, 'message')
let l:lines = split(l:diagnostic['message'], '\n', 1)
call lsp#ui#vim#output#preview('', l:lines, {
\ 'statusline': ' LSP Diagnostics'
\})
let s:displaying_message = 1
elseif get(s:, 'displaying_message', 0)
call lsp#ui#vim#output#closepreview()
let s:displaying_message = 0
endif
endfunction
function! s:stop_cursor_moved_timer() abort
if exists('s:cursor_moved_timer')
call timer_stop(s:cursor_moved_timer)
unlet s:cursor_moved_timer
endif
endfunction

View File

@@ -11,58 +11,58 @@ function! s:vim_popup_closed(...) abort
endfunction endfunction
function! lsp#ui#vim#output#closepreview() abort function! lsp#ui#vim#output#closepreview() abort
if win_getid() == s:winid if win_getid() ==# s:winid
" Don't close if window got focus " Don't close if window got focus
return return
endif endif
"closing floats in vim8.1 must use popup_close() (nvim could use nvim_win_close but pclose "closing floats in vim8.1 must use popup_close() (nvim could use nvim_win_close but pclose
"works) "works)
if s:use_vim_popup && s:winid if s:use_vim_popup && s:winid
call popup_close(s:winid) call popup_close(s:winid)
else else
pclose pclose
endif endif
let s:winid = v:false let s:winid = v:false
let s:preview_data = v:false let s:preview_data = v:false
augroup lsp_float_preview_close augroup lsp_float_preview_close
augroup end augroup end
autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized *
doautocmd User lsp_float_closed doautocmd User lsp_float_closed
endfunction endfunction
function! lsp#ui#vim#output#focuspreview() abort function! lsp#ui#vim#output#focuspreview() abort
" This does not work for vim8.1 popup but will work for nvim and old preview " This does not work for vim8.1 popup but will work for nvim and old preview
if s:winid if s:winid
if win_getid() != s:winid if win_getid() !=# s:winid
let s:prevwin = win_getid() let s:prevwin = win_getid()
call win_gotoid(s:winid) call win_gotoid(s:winid)
elseif s:prevwin elseif s:prevwin
" Temporarily disable hooks " Temporarily disable hooks
" TODO: remove this when closing logic is able to distinguish different move directions " TODO: remove this when closing logic is able to distinguish different move directions
autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized *
call win_gotoid(s:prevwin) call win_gotoid(s:prevwin)
call s:add_float_closing_hooks() call s:add_float_closing_hooks()
let s:prevwin = v:false let s:prevwin = v:false
endif
endif endif
endif
endfunction endfunction
function! s:bufwidth() abort function! s:bufwidth() abort
let width = winwidth(0) let l:width = winwidth(0)
let numberwidth = max([&numberwidth, strlen(line('$'))+1]) let l:numberwidth = max([&numberwidth, strlen(line('$'))+1])
let numwidth = (&number || &relativenumber)? numberwidth : 0 let l:numwidth = (&number || &relativenumber)? l:numberwidth : 0
let foldwidth = &foldcolumn let l:foldwidth = &foldcolumn
if &signcolumn ==? 'yes' if &signcolumn ==? 'yes'
let signwidth = 2 let l:signwidth = 2
elseif &signcolumn ==? 'auto' elseif &signcolumn ==? 'auto'
let signs = execute(printf('sign place buffer=%d', bufnr(''))) let l:signs = execute(printf('sign place buffer=%d', bufnr('')))
let signs = split(signs, "\n") let l:signs = split(l:signs, "\n")
let signwidth = len(signs)>2? 2: 0 let l:signwidth = len(l:signs)>2? 2: 0
else else
let signwidth = 0 let l:signwidth = 0
endif endif
return width - numwidth - foldwidth - signwidth return l:width - l:numwidth - l:foldwidth - l:signwidth
endfunction endfunction
@@ -73,118 +73,118 @@ function! s:get_float_positioning(height, width) abort
" TODO: add option to configure it 'docked' at the bottom/top/right " TODO: add option to configure it 'docked' at the bottom/top/right
let l:y = winline() let l:y = winline()
if l:y + l:height >= winheight(0) if l:y + l:height >= winheight(0)
" Float does not fit " Float does not fit
if l:y > l:height if l:y > l:height
" Fits above " Fits above
let l:y = winline() - l:height - 1 let l:y = winline() - l:height - 1
elseif l:y - 2 > winheight(0) - l:y elseif l:y - 2 > winheight(0) - l:y
" Take space above cursor " Take space above cursor
let l:y = 1 let l:y = 1
let l:height = winline()-2 let l:height = winline()-2
else else
" Take space below cursor " Take space below cursor
let l:height = winheight(0) -l:y let l:height = winheight(0) -l:y
endif endif
endif endif
let l:col = col('.') let l:col = col('.')
let l:style = 'minimal' let l:style = 'minimal'
" Positioning is not window but screen relative " Positioning is not window but screen relative
let l:opts = { let l:opts = {
\ 'relative': 'win', \ 'relative': 'win',
\ 'row': l:y, \ 'row': l:y,
\ 'col': l:col, \ 'col': l:col,
\ 'width': l:width, \ 'width': l:width,
\ 'height': l:height, \ 'height': l:height,
\ 'style': l:style, \ 'style': l:style,
\ } \ }
return l:opts return l:opts
endfunction endfunction
function! lsp#ui#vim#output#floatingpreview(data) abort function! lsp#ui#vim#output#floatingpreview(data) abort
if s:use_nvim_float if s:use_nvim_float
let l:buf = nvim_create_buf(v:false, v:true) let l:buf = nvim_create_buf(v:false, v:true)
call setbufvar(l:buf, '&signcolumn', 'no') call setbufvar(l:buf, '&signcolumn', 'no')
" Try to get as much space around the cursor, but at least 10x10 " Try to get as much space around the cursor, but at least 10x10
let l:width = max([s:bufwidth(), 10]) let l:width = max([s:bufwidth(), 10])
let l:height = max([&lines - winline() + 1, winline() - 1, 10]) let l:height = max([&lines - winline() + 1, winline() - 1, 10])
if g:lsp_preview_max_height > 0 if g:lsp_preview_max_height > 0
let l:height = min([g:lsp_preview_max_height, l:height]) let l:height = min([g:lsp_preview_max_height, l:height])
endif
let l:opts = s:get_float_positioning(l:height, l:width)
let s:winid = nvim_open_win(l: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 <buffer><silent> <esc> :pclose<cr>
elseif s:use_vim_popup
let l:options = {
\ 'moved': 'any',
\ 'border': [1, 1, 1, 1],
\ 'callback': function('s:vim_popup_closed')
\ }
if g:lsp_preview_max_width > 0
let l:options['maxwidth'] = g:lsp_preview_max_width
endif
if g:lsp_preview_max_height > 0
let l:options['maxheight'] = g:lsp_preview_max_height
endif
let s:winid = popup_atcursor('...', l:options)
endif endif
return s:winid
let l:opts = s:get_float_positioning(l:height, l:width)
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 <buffer><silent> <esc> :pclose<cr>
elseif s:use_vim_popup
let l:options = {
\ 'moved': 'any',
\ 'border': [1, 1, 1, 1],
\ 'callback': function('s:vim_popup_closed')
\ }
if g:lsp_preview_max_width > 0
let l:options['maxwidth'] = g:lsp_preview_max_width
endif
if g:lsp_preview_max_height > 0
let l:options['maxheight'] = g:lsp_preview_max_height
endif
let s:winid = popup_atcursor('...', l:options)
endif
return s:winid
endfunction endfunction
function! s:setcontent(lines, ft) abort function! s:setcontent(lines, ft) abort
if s:use_vim_popup if s:use_vim_popup
" vim popup " vim popup
call setbufline(winbufnr(s:winid), 1, a:lines) call setbufline(winbufnr(s:winid), 1, a:lines)
let l:lightline_toggle = v:false 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. " 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... " It is ugly to have an check for an other plugin here, better fix lightline...
let l:lightline_toggle = v:true let l:lightline_toggle = v:true
call lightline#disable() call lightline#disable()
endif endif
call win_execute(s:winid, 'setlocal filetype=' . a:ft . '.lsp-hover') call win_execute(s:winid, 'setlocal filetype=' . a:ft . '.lsp-hover')
if l:lightline_toggle if l:lightline_toggle
call lightline#enable() call lightline#enable()
endif endif
else else
" nvim floating or preview " nvim floating or preview
call setline(1, a:lines) call setline(1, a:lines)
setlocal readonly nomodifiable setlocal readonly nomodifiable
silent! let &l:filetype = a:ft . '.lsp-hover' silent! let &l:filetype = a:ft . '.lsp-hover'
endif endif
endfunction endfunction
function! s:adjust_float_placement(bufferlines, maxwidth) abort function! s:adjust_float_placement(bufferlines, maxwidth) abort
if s:use_nvim_float if s:use_nvim_float
let l:win_config = {} let l:win_config = {}
let l:height = min([winheight(s:winid), a:bufferlines]) let l:height = min([winheight(s:winid), a:bufferlines])
let l:width = min([winwidth(s:winid), a:maxwidth]) let l:width = min([winwidth(s:winid), a:maxwidth])
let l:win_config = s:get_float_positioning(l:height, l:width) let l:win_config = s:get_float_positioning(l:height, l:width)
call nvim_win_set_config(s:winid, l:win_config ) call nvim_win_set_config(s:winid, l:win_config )
endif endif
endfunction endfunction
function! s:add_float_closing_hooks() abort function! s:add_float_closing_hooks() abort
if g:lsp_preview_autoclose if g:lsp_preview_autoclose
augroup lsp_float_preview_close augroup lsp_float_preview_close
autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized * autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized *
autocmd CursorMoved,CursorMovedI,VimResized * call lsp#ui#vim#output#closepreview() autocmd CursorMoved,CursorMovedI,VimResized * call lsp#ui#vim#output#closepreview()
augroup END augroup END
endif endif
endfunction endfunction
@@ -194,10 +194,10 @@ endfunction
function! s:open_preview(data) abort function! s:open_preview(data) abort
if s:use_vim_popup || s:use_nvim_float if s:use_vim_popup || s:use_nvim_float
let l:winid = lsp#ui#vim#output#floatingpreview(a:data) let l:winid = lsp#ui#vim#output#floatingpreview(a:data)
else else
execute &previewheight.'new' execute &previewheight.'new'
let l:winid = win_getid() let l:winid = win_getid()
endif endif
return l:winid return l:winid
endfunction endfunction
@@ -208,37 +208,37 @@ function! s:set_cursor(current_window_id, options) abort
endif endif
if s:use_nvim_float if s:use_nvim_float
" Neovim floats " Neovim floats
" Go back to the preview window to set the cursor " Go back to the preview window to set the cursor
call win_gotoid(s:winid) call win_gotoid(s:winid)
let l:old_scrolloff = &scrolloff let l:old_scrolloff = &scrolloff
let &scrolloff = 0 let &scrolloff = 0
call nvim_win_set_cursor(s:winid, [a:options['cursor']['line'], a:options['cursor']['col']]) call nvim_win_set_cursor(s:winid, [a:options['cursor']['line'], a:options['cursor']['col']])
call s:align_preview(a:options) call s:align_preview(a:options)
" Finally, go back to the original window " Finally, go back to the original window
call win_gotoid(a:current_window_id) call win_gotoid(a:current_window_id)
let &scrolloff = l:old_scrolloff let &scrolloff = l:old_scrolloff
elseif s:use_vim_popup elseif s:use_vim_popup
" Vim popups " Vim popups
function! AlignVimPopup(timer) closure abort function! AlignVimPopup(timer) closure abort
call s:align_preview(a:options) call s:align_preview(a:options)
endfunction endfunction
call timer_start(0, function('AlignVimPopup')) call timer_start(0, function('AlignVimPopup'))
else else
" Preview " Preview
" Don't use 'scrolloff', it might mess up the cursor's position " Don't use 'scrolloff', it might mess up the cursor's position
let &l:scrolloff = 0 let &l:scrolloff = 0
call cursor(a:options['cursor']['line'], a:options['cursor']['col']) call cursor(a:options['cursor']['line'], a:options['cursor']['col'])
call s:align_preview(a:options) call s:align_preview(a:options)
endif endif
endfunction endfunction
function! s:align_preview(options) abort function! s:align_preview(options) abort
if !has_key(a:options, 'cursor') || if !has_key(a:options, 'cursor') ||
\ !has_key(a:options['cursor'], 'align') \ !has_key(a:options['cursor'], 'align')
return return
endif endif
@@ -256,13 +256,13 @@ function! s:align_preview(options) abort
let l:width = l:pos['core_width'] let l:width = l:pos['core_width']
let l:options = { let l:options = {
\ 'minwidth': l:width, \ 'minwidth': l:width,
\ 'maxwidth': l:width, \ 'maxwidth': l:width,
\ 'minheight': l:height, \ 'minheight': l:height,
\ 'maxheight': l:height, \ 'maxheight': l:height,
\ 'pos': l:below ? 'topleft' : 'botleft', \ 'pos': l:below ? 'topleft' : 'botleft',
\ 'line': l:below ? 'cursor+1' : 'cursor-1' \ 'line': l:below ? 'cursor+1' : 'cursor-1'
\ } \ }
if l:align ==? 'top' if l:align ==? 'top'
let l:options['firstline'] = a:options['cursor']['line'] let l:options['firstline'] = a:options['cursor']['line']
@@ -286,13 +286,17 @@ function! s:align_preview(options) abort
endif endif
endfunction endfunction
function! lsp#ui#vim#output#float_supported() abort
return s:use_vim_popup || s:use_nvim_float
endfunction
function! lsp#ui#vim#output#preview(server, data, options) abort function! lsp#ui#vim#output#preview(server, data, options) abort
if s:winid && type(s:preview_data) == type(a:data) if s:winid && type(s:preview_data) ==# type(a:data)
\ && s:preview_data == a:data \ && s:preview_data ==# a:data
\ && type(g:lsp_preview_doubletap) == 3 \ && type(g:lsp_preview_doubletap) ==# 3
\ && len(g:lsp_preview_doubletap) >= 1 \ && len(g:lsp_preview_doubletap) >= 1
\ && type(g:lsp_preview_doubletap[0]) == 2 \ && type(g:lsp_preview_doubletap[0]) ==# 2
\ && index(['i', 's'], mode()[0]) == -1 \ && index(['i', 's'], mode()[0]) ==# -1
echo '' echo ''
return call(g:lsp_preview_doubletap[0], []) return call(g:lsp_preview_doubletap[0], [])
endif endif
@@ -310,8 +314,8 @@ function! lsp#ui#vim#output#preview(server, data, options) abort
" If the server response is empty content, we don't display anything. " If the server response is empty content, we don't display anything.
if empty(l:lines) && empty(l:syntax_lines) if empty(l:lines) && empty(l:syntax_lines)
echo '' echo ''
return return
endif endif
let s:winid = s:open_preview(a:data) let s:winid = s:open_preview(a:data)
@@ -320,12 +324,10 @@ function! lsp#ui#vim#output#preview(server, data, options) abort
let l:ft = a:options['filetype'] let l:ft = a:options['filetype']
endif endif
let l:server_info = lsp#get_server_info(a:server) let l:do_conceal = g:lsp_hover_conceal
try let l:server_info = a:server !=# '' ? lsp#get_server_info(a:server) : {}
let l:do_conceal = l:server_info['config']['hover_conceal'] let l:config = get(l:server_info, 'config', {})
catch let l:do_conceal = get(l:config, 'hover_conceal', l:do_conceal)
let l:do_conceal = g:lsp_hover_conceal
endtry
call setbufvar(winbufnr(s:winid), 'lsp_syntax_highlights', l:syntax_lines) call setbufvar(winbufnr(s:winid), 'lsp_syntax_highlights', l:syntax_lines)
call setbufvar(winbufnr(s:winid), 'lsp_do_conceal', l:do_conceal) call setbufvar(winbufnr(s:winid), 'lsp_do_conceal', l:do_conceal)
@@ -334,17 +336,17 @@ function! lsp#ui#vim#output#preview(server, data, options) abort
" Get size information while still having the buffer active " Get size information while still having the buffer active
let l:maxwidth = max(map(getline(1, '$'), 'strdisplaywidth(v:val)')) let l:maxwidth = max(map(getline(1, '$'), 'strdisplaywidth(v:val)'))
if g:lsp_preview_max_width > 0 if g:lsp_preview_max_width > 0
let l:bufferlines = 0 let l:bufferlines = 0
let l:maxwidth = min([g:lsp_preview_max_width, l:maxwidth]) let l:maxwidth = min([g:lsp_preview_max_width, l:maxwidth])
" Determine, for each line, how many "virtual" lines it spans, and add " Determine, for each line, how many "virtual" lines it spans, and add
" these together for all lines in the buffer " these together for all lines in the buffer
for l:line in getline(1, '$') 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:num_lines = str2nr(string(ceil(strdisplaywidth(l:line) * 1.0 / g:lsp_preview_max_width)))
let l:bufferlines += max([l:num_lines, 1]) let l:bufferlines += max([l:num_lines, 1])
endfor endfor
else else
let l:bufferlines = line('$') let l:bufferlines = line('$')
endif endif
if s:use_preview if s:use_preview
@@ -362,22 +364,22 @@ function! lsp#ui#vim#output#preview(server, data, options) abort
echo '' echo ''
if s:winid && (s:use_vim_popup || s:use_nvim_float) if s:winid && (s:use_vim_popup || s:use_nvim_float)
if s:use_nvim_float if s:use_nvim_float
" Neovim floats " Neovim floats
call s:adjust_float_placement(l:bufferlines, l:maxwidth) call s:adjust_float_placement(l:bufferlines, l:maxwidth)
call s:set_cursor(l:current_window_id, a:options) call s:set_cursor(l:current_window_id, a:options)
call s:add_float_closing_hooks() call s:add_float_closing_hooks()
elseif s:use_vim_popup elseif s:use_vim_popup
" Vim popups " Vim popups
call s:set_cursor(l:current_window_id, a:options) call s:set_cursor(l:current_window_id, a:options)
endif endif
doautocmd User lsp_float_opened doautocmd User lsp_float_opened
endif endif
if !g:lsp_preview_keep_focus if !g:lsp_preview_keep_focus
" set the focus to the preview window " set the focus to the preview window
call win_gotoid(s:winid) call win_gotoid(s:winid)
endif endif
return '' return ''
endfunction endfunction
@@ -387,19 +389,19 @@ function! s:escape_string_for_display(str) abort
endfunction endfunction
function! s:append(data, lines, syntax_lines) abort function! s:append(data, lines, syntax_lines) abort
if type(a:data) == type([]) if type(a:data) ==# type([])
for l:entry in a:data for l:entry in a:data
call s:append(entry, a:lines, a:syntax_lines) call s:append(l:entry, a:lines, a:syntax_lines)
endfor endfor
return 'markdown' return 'markdown'
elseif type(a:data) == type('') elseif type(a:data) ==# type('')
if !empty(a:data) if !empty(a:data)
call extend(a:lines, split(s:escape_string_for_display(a:data), "\n", v:true)) call extend(a:lines, split(s:escape_string_for_display(a:data), "\n", v:true))
endif endif
return 'markdown' return 'markdown'
elseif type(a:data) == type({}) && has_key(a:data, 'language') elseif type(a:data) ==# type({}) && has_key(a:data, 'language')
if !empty(a:data.value) if !empty(a:data.value)
let l:new_lines = split(s:escape_string_for_display(a:data.value), '\n') let l:new_lines = split(s:escape_string_for_display(a:data.value), '\n')
@@ -413,9 +415,9 @@ function! s:append(data, lines, syntax_lines) abort
endif endif
return 'markdown' return 'markdown'
elseif type(a:data) == type({}) && has_key(a:data, 'kind') elseif type(a:data) ==# type({}) && has_key(a:data, 'kind')
if !empty(a:data.value) if !empty(a:data.value)
call extend(a:lines, split(s:escape_string_for_display(a:data.value), '\n', v:true)) call extend(a:lines, split(s:escape_string_for_display(a:data.value), '\n', v:true))
endif endif
return a:data.kind ==? 'plaintext' ? 'text' : a:data.kind return a:data.kind ==? 'plaintext' ? 'text' : a:data.kind

View File

@@ -19,7 +19,7 @@ function! lsp#ui#vim#signature_help#get_signature_help_under_cursor() abort
\ 'method': 'textDocument/signatureHelp', \ 'method': 'textDocument/signatureHelp',
\ 'params': { \ 'params': {
\ 'textDocument': lsp#get_text_document_identifier(), \ 'textDocument': lsp#get_text_document_identifier(),
\ 'position': position, \ 'position': l:position,
\ }, \ },
\ 'on_notification': function('s:handle_signature_help', [l:server]), \ 'on_notification': function('s:handle_signature_help', [l:server]),
\ }) \ })

View File

@@ -28,12 +28,12 @@ function! s:encode_uri(path, start_pos_encode, default_prefix) abort
let l:result = strpart(a:path, 0, a:start_pos_encode) let l:result = strpart(a:path, 0, a:start_pos_encode)
for i in range(a:start_pos_encode, len(l:path) - 1) for l:i in range(a:start_pos_encode, len(l:path) - 1)
" Don't encode '/' here, `path` is expected to be a valid path. " Don't encode '/' here, `path` is expected to be a valid path.
if l:path[i] =~# '^[a-zA-Z0-9_.~/-]$' if l:path[l:i] =~# '^[a-zA-Z0-9_.~/-]$'
let l:result .= l:path[i] let l:result .= l:path[l:i]
else else
let l:result .= s:urlencode_char(l:path[i]) let l:result .= s:urlencode_char(l:path[l:i])
endif endif
endfor endfor
@@ -116,8 +116,8 @@ endfunction
function! lsp#utils#find_nearest_parent_file_directory(path, filename) abort function! lsp#utils#find_nearest_parent_file_directory(path, filename) abort
if type(a:filename) == 3 if type(a:filename) == 3
let l:matched_paths = {} let l:matched_paths = {}
for current_name in a:filename for l:current_name in a:filename
let l:path = lsp#utils#find_nearest_parent_file_directory(a:path, current_name) let l:path = lsp#utils#find_nearest_parent_file_directory(a:path, l:current_name)
if !empty(l:path) if !empty(l:path)
if has_key(l:matched_paths, l:path) if has_key(l:matched_paths, l:path)

View File

@@ -56,7 +56,7 @@ function! lsp#utils#buffer#_open_lsp_location(location) abort
endif endif
execute l:cmd . ' | call cursor('.l:start_line.','.l:start_col.')' execute l:cmd . ' | call cursor('.l:start_line.','.l:start_col.')'
normal V normal! V
call setpos("'<", [l:bufnr, l:start_line, l:start_col]) call setpos("'<", [l:bufnr, l:start_line, l:start_col])
call setpos("'>", [l:bufnr, l:end_line, l:end_col]) call setpos("'>", [l:bufnr, l:end_line, l:end_col])
endfunction endfunction

View File

@@ -3,7 +3,7 @@ function! lsp#utils#workspace_config#get_value(server_name, item) abort
let l:server_info = lsp#get_server_info(a:server_name) let l:server_info = lsp#get_server_info(a:server_name)
let l:config = l:server_info['workspace_config'] let l:config = l:server_info['workspace_config']
for section in split(a:item['section'], '\.') for l:section in split(a:item['section'], '\.')
let l:config = l:config[l:section] let l:config = l:config[l:section]
endfor endfor

View File

@@ -20,6 +20,9 @@ CONTENTS *vim-lsp-contents*
g:lsp_insert_text_enabled |g:lsp_insert_text_enabled| g:lsp_insert_text_enabled |g:lsp_insert_text_enabled|
g:lsp_text_edit_enabled |g:lsp_text_edit_enabled| g:lsp_text_edit_enabled |g:lsp_text_edit_enabled|
g:lsp_diagnostics_echo_cursor |g:lsp_diagnostics_echo_cursor| 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_signs_enabled |g:lsp_signs_enabled| g:lsp_signs_enabled |g:lsp_signs_enabled|
g:lsp_signs_priority |g:lsp_signs_priority| g:lsp_signs_priority |g:lsp_signs_priority|
g:lsp_signs_priority_map |g:lsp_signs_priority_map| g:lsp_signs_priority_map |g:lsp_signs_priority_map|
@@ -344,6 +347,42 @@ g:lsp_diagnostics_echo_cursor *g:lsp_diagnostics_echo_cursor*
let g:lsp_diagnostics_echo_cursor = 1 let g:lsp_diagnostics_echo_cursor = 1
let g:lsp_diagnostics_echo_cursor = 0 let g:lsp_diagnostics_echo_cursor = 0
g:lsp_diagnostics_echo_delay *g:lsp_diagnostics_echo_delay*
Type: |Number|
Default: `500`
Delay milliseconds to echo diagnostic error for the current line to status. Requires
Enables echo of diagnostic error for the current line to status. Requires
|g:lsp_diagnostics_enabled| and |g:lsp_diagnostics_echo_cursor| set to 1.
Example: >
let g:lsp_diagnostics_echo_delay = 200
let g:lsp_diagnostics_echo_delay = 1000
g:lsp_diagnostics_float_cursor *g:lsp_diagnostics_float_cursor*
Type: |Number|
Default: `0`
Enables a floating window of diagnostic error for the current line to status. Requires
nvim_win_open() or popup_create is available, and |g:lsp_diagnostics_enabled| set to 1.
Example: >
let g:lsp_diagnostics_float_cursor = 1
let g:lsp_diagnostics_float_cursor = 0
g:lsp_diagnostics_float_delay *g:lsp_diagnostics_float_delay*
Type: |Number|
Default: `500`
Delay milliseconds to show diagnostic error for the current line to status
in a float window. Requires Enables float of diagnostic error for the
current line to status. Requires |g:lsp_diagnostics_enabled| and
|g:lsp_diagnostics_echo_cursor| set to 1.
Example: >
let g:lsp_diagnostics_echo_delay = 200
let g:lsp_diagnostics_echo_delay = 1000
g:lsp_signs_enabled *g:lsp_signs_enabled* g:lsp_signs_enabled *g:lsp_signs_enabled*
Type: |Number| Type: |Number|
Default: `1` for vim/neovim with patch 8.1.0772 Default: `1` for vim/neovim with patch 8.1.0772

View File

@@ -23,6 +23,8 @@ let g:lsp_signs_priority_map = get(g:, 'lsp_signs_priority_map', {})
let g:lsp_diagnostics_enabled = get(g:, 'lsp_diagnostics_enabled', 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_cursor = get(g:, 'lsp_diagnostics_echo_cursor', 0)
let g:lsp_diagnostics_echo_delay = get(g:, 'lsp_diagnostics_echo_delay', 500) let g:lsp_diagnostics_echo_delay = get(g:, 'lsp_diagnostics_echo_delay', 500)
let g:lsp_diagnostics_float_cursor = get(g:, 'lsp_diagnostics_float_cursor', 0)
let g:lsp_diagnostics_float_delay = get(g:, 'lsp_diagnostics_float_delay', 500)
let g:lsp_next_sign_id = get(g:, 'lsp_next_sign_id', 6999) let g:lsp_next_sign_id = get(g:, 'lsp_next_sign_id', 6999)
let g:lsp_preview_keep_focus = get(g:, 'lsp_preview_keep_focus', 1) let g:lsp_preview_keep_focus = get(g:, 'lsp_preview_keep_focus', 1)
let g:lsp_use_event_queue = get(g:, 'lsp_use_event_queue', has('nvim') || has('patch-8.1.0889')) let g:lsp_use_event_queue = get(g:, 'lsp_use_event_queue', has('nvim') || has('patch-8.1.0889'))