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:
ProhibitUnusedVariable:
enabled: true
enabled: false
ProhibitImplicitScopeVariable:
enabled: true
ProhibitNoAbortFunction:

View File

@@ -115,7 +115,7 @@ endfunction
" "exited", "starting", "failed", "running", "not running"
function! lsp#get_server_status(...) abort
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")
else
return s:server_status(a:1)
@@ -189,7 +189,7 @@ function! s:register_events() abort
if exists('##TextChangedP')
autocmd TextChangedP * call s:on_text_document_did_change()
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()
endif
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
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
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')
let l:capabilities = l:server_info['capabilities']
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
let l:request = {
@@ -886,8 +888,8 @@ function! s:add_didchange_queue(buf) abort
call add(s:didchange_queue, a:buf)
call lsp#log('s:send_didchange_queue() will be triggered')
call timer_stop(s:didchange_timer)
let lazy = &updatetime > 1000 ? &updatetime : 1000
let s:didchange_timer = timer_start(lazy, function('s:send_didchange_queue'))
let l:lazy = &updatetime > 1000 ? &updatetime : 1000
let s:didchange_timer = timer_start(l:lazy, function('s:send_didchange_queue'))
endfunction
function! s:send_didchange_queue(...) abort

View File

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

View File

@@ -255,7 +255,7 @@ function! lsp#ui#vim#stop_server(...) abort
continue
endif
echo 'Stopping' l:server 'server ...'
call lsp#stop_server(server)
call lsp#stop_server(l:server)
endfor
endfunction

View File

@@ -35,7 +35,7 @@ function! lsp#ui#vim#diagnostics#document_diagnostics() abort
endif
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)
endfor

View File

@@ -1,6 +1,6 @@
function! lsp#ui#vim#diagnostics#echo#cursor_moved() abort
if mode() isnot# 'n'
" dont' show echo only in normal mode
" show echo only in normal mode
return
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,7 +11,7 @@ function! s:vim_popup_closed(...) abort
endfunction
function! lsp#ui#vim#output#closepreview() abort
if win_getid() == s:winid
if win_getid() ==# s:winid
" Don't close if window got focus
return
endif
@@ -33,7 +33,7 @@ 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:winid
if win_getid() != s:winid
if win_getid() !=# s:winid
let s:prevwin = win_getid()
call win_gotoid(s:winid)
elseif s:prevwin
@@ -48,21 +48,21 @@ function! lsp#ui#vim#output#focuspreview() abort
endfunction
function! s:bufwidth() abort
let width = winwidth(0)
let numberwidth = max([&numberwidth, strlen(line('$'))+1])
let numwidth = (&number || &relativenumber)? numberwidth : 0
let foldwidth = &foldcolumn
let l:width = winwidth(0)
let l:numberwidth = max([&numberwidth, strlen(line('$'))+1])
let l:numwidth = (&number || &relativenumber)? l:numberwidth : 0
let l:foldwidth = &foldcolumn
if &signcolumn ==? 'yes'
let signwidth = 2
let l: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
let l:signs = execute(printf('sign place buffer=%d', bufnr('')))
let l:signs = split(l:signs, "\n")
let l:signwidth = len(l:signs)>2? 2: 0
else
let signwidth = 0
let l:signwidth = 0
endif
return width - numwidth - foldwidth - signwidth
return l:width - l:numwidth - l:foldwidth - l:signwidth
endfunction
@@ -115,7 +115,7 @@ function! lsp#ui#vim#output#floatingpreview(data) abort
let l:opts = s:get_float_positioning(l:height, l:width)
let s:winid = nvim_open_win(buf, v:true, l:opts)
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)
@@ -286,13 +286,17 @@ function! s:align_preview(options) abort
endif
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
if s:winid && type(s:preview_data) == type(a:data)
\ && s:preview_data == a:data
\ && type(g:lsp_preview_doubletap) == 3
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
\ && index(['i', 's'], mode()[0]) == -1
\ && type(g:lsp_preview_doubletap[0]) ==# 2
\ && index(['i', 's'], mode()[0]) ==# -1
echo ''
return call(g:lsp_preview_doubletap[0], [])
endif
@@ -320,12 +324,10 @@ function! lsp#ui#vim#output#preview(server, data, options) abort
let l:ft = a:options['filetype']
endif
let l:server_info = lsp#get_server_info(a:server)
try
let l:do_conceal = l:server_info['config']['hover_conceal']
catch
let l:do_conceal = g:lsp_hover_conceal
endtry
let l:server_info = a:server !=# '' ? lsp#get_server_info(a:server) : {}
let l:config = get(l:server_info, 'config', {})
let l:do_conceal = get(l:config, 'hover_conceal', l:do_conceal)
call setbufvar(winbufnr(s:winid), 'lsp_syntax_highlights', l:syntax_lines)
call setbufvar(winbufnr(s:winid), 'lsp_do_conceal', l:do_conceal)
@@ -387,19 +389,19 @@ function! s:escape_string_for_display(str) abort
endfunction
function! s:append(data, lines, syntax_lines) abort
if type(a:data) == type([])
if type(a:data) ==# type([])
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
return 'markdown'
elseif type(a:data) == type('')
elseif type(a:data) ==# type('')
if !empty(a:data)
call extend(a:lines, split(s:escape_string_for_display(a:data), "\n", v:true))
endif
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)
let l:new_lines = split(s:escape_string_for_display(a:data.value), '\n')
@@ -413,7 +415,7 @@ function! s:append(data, lines, syntax_lines) abort
endif
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)
call extend(a:lines, split(s:escape_string_for_display(a:data.value), '\n', v:true))
endif

View File

@@ -19,7 +19,7 @@ function! lsp#ui#vim#signature_help#get_signature_help_under_cursor() abort
\ 'method': 'textDocument/signatureHelp',
\ 'params': {
\ 'textDocument': lsp#get_text_document_identifier(),
\ 'position': position,
\ 'position': l:position,
\ },
\ '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)
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.
if l:path[i] =~# '^[a-zA-Z0-9_.~/-]$'
let l:result .= l:path[i]
if l:path[l:i] =~# '^[a-zA-Z0-9_.~/-]$'
let l:result .= l:path[l:i]
else
let l:result .= s:urlencode_char(l:path[i])
let l:result .= s:urlencode_char(l:path[l:i])
endif
endfor
@@ -116,8 +116,8 @@ endfunction
function! lsp#utils#find_nearest_parent_file_directory(path, filename) abort
if type(a:filename) == 3
let l:matched_paths = {}
for current_name in a:filename
let l:path = lsp#utils#find_nearest_parent_file_directory(a:path, current_name)
for l:current_name in a:filename
let l:path = lsp#utils#find_nearest_parent_file_directory(a:path, l:current_name)
if !empty(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
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:end_line, l:end_col])
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: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]
endfor

View File

@@ -20,6 +20,9 @@ CONTENTS *vim-lsp-contents*
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|
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_priority |g:lsp_signs_priority|
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 = 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*
Type: |Number|
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_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_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_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'))