mirror of
https://github.com/prabirshrestha/vim-lsp.git
synced 2025-12-20 09:11:56 +01:00
* diagnostics list can be v:null Ref #1186 * ditto * Small refactoring * Use lsp#utils#iteratable for the list which possibly be v:null
174 lines
6.5 KiB
VimL
174 lines
6.5 KiB
VimL
" https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
|
|
"
|
|
" Refer to https://github.com/microsoft/language-server-protocol/pull/1019 on normalization of urls.
|
|
" {
|
|
" 'normalized_uri': {
|
|
" 'server_name': {
|
|
" 'method': 'textDocument/publishDiagnostics',
|
|
" 'params': {
|
|
" 'uri': 'uri', " this uri is not normalized and is exactly what server returns
|
|
" 'dignostics': [ " array can never be null but can be empty
|
|
" https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
|
|
" { range, message, severity?, code?, codeDesciption?, source?, tags?, relatedInformation?, data? }
|
|
" ]
|
|
" }
|
|
" }
|
|
" }
|
|
" Note: Do not remove when buffer unloads or doesn't exist since some server
|
|
" may send diagnsotics information regardless of textDocument/didOpen.
|
|
" buffer state is removed when server exits.
|
|
" TODO: reset buffer state when server initializes. ignoring for now for perf.
|
|
let s:diagnostics_state = {}
|
|
|
|
" internal state for whether it is enabled or not to avoid multiple subscriptions
|
|
let s:enabled = 0
|
|
|
|
let s:diagnostic_kinds = {
|
|
\ 1: 'error',
|
|
\ 2: 'warning',
|
|
\ 3: 'information',
|
|
\ 4: 'hint',
|
|
\ }
|
|
|
|
function! lsp#internal#diagnostics#state#_enable() abort
|
|
" don't even bother registering if the feature is disabled
|
|
if !g:lsp_diagnostics_enabled | return | endif
|
|
|
|
if s:enabled | return | endif
|
|
let s:enabled = 1
|
|
|
|
call lsp#internal#diagnostics#state#_reset()
|
|
|
|
let s:Dispose = lsp#callbag#pipe(
|
|
\ lsp#callbag#merge(
|
|
\ lsp#callbag#pipe(
|
|
\ lsp#stream(),
|
|
\ lsp#callbag#filter({x->has_key(x, 'server') && has_key(x, 'response')
|
|
\ && get(x['response'], 'method', '') ==# 'textDocument/publishDiagnostics'}),
|
|
\ lsp#callbag#tap({x->s:on_text_documentation_publish_diagnostics(x['server'], x['response'])}),
|
|
\ ),
|
|
\ lsp#callbag#pipe(
|
|
\ lsp#stream(),
|
|
\ lsp#callbag#filter({x->has_key(x, 'server') && has_key(x, 'response')
|
|
\ && get(x['response'], 'method', '') ==# '$/vimlsp/lsp_server_exit' }),
|
|
\ lsp#callbag#tap({x->s:on_exit(x['response'])}),
|
|
\ ),
|
|
\ ),
|
|
\ lsp#callbag#subscribe(),
|
|
\ )
|
|
|
|
call s:notify_diagnostics_update()
|
|
endfunction
|
|
|
|
function! lsp#internal#diagnostics#state#_disable() abort
|
|
if !s:enabled | return | endif
|
|
if exists('s:Dispose')
|
|
call s:Dispose()
|
|
unlet s:Dispose
|
|
endif
|
|
call lsp#internal#diagnostics#state#_reset()
|
|
call s:notify_diagnostics_update()
|
|
let s:enabled = 0
|
|
endfunction
|
|
|
|
function! lsp#internal#diagnostics#state#_reset() abort
|
|
let s:diagnostics_state = {}
|
|
let s:diagnostics_disabled_buffers = {}
|
|
endfunction
|
|
|
|
" callers should always treat the return value as immutable
|
|
" @return {
|
|
" 'servername': response
|
|
" }
|
|
function! lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(uri) abort
|
|
return get(s:diagnostics_state, lsp#utils#normalize_uri(a:uri), {})
|
|
endfunction
|
|
|
|
" callers should always treat the return value as immutable.
|
|
" callers should treat uri as normalized via lsp#utils#normalize_uri
|
|
" @return {
|
|
" 'normalized_uri': {
|
|
" 'servername': response
|
|
" }
|
|
" }
|
|
function! lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_uri_and_server() abort
|
|
return s:diagnostics_state
|
|
endfunction
|
|
|
|
function! s:on_text_documentation_publish_diagnostics(server, response) abort
|
|
if lsp#client#is_error(a:response) | return | endif
|
|
let l:normalized_uri = lsp#utils#normalize_uri(a:response['params']['uri'])
|
|
if !has_key(s:diagnostics_state, l:normalized_uri)
|
|
let s:diagnostics_state[l:normalized_uri] = {}
|
|
endif
|
|
let s:diagnostics_state[l:normalized_uri][a:server] = a:response
|
|
call s:notify_diagnostics_update(a:server, l:normalized_uri)
|
|
endfunction
|
|
|
|
function! s:on_exit(response) abort
|
|
let l:server = a:response['params']['server']
|
|
let l:notify = 0
|
|
for [l:key, l:value] in items(s:diagnostics_state)
|
|
if has_key(l:value, l:server)
|
|
let l:notify = 1
|
|
call remove(l:value, l:server)
|
|
endif
|
|
endfor
|
|
if l:notify | call s:notify_diagnostics_update(l:server) | endif
|
|
endfunction
|
|
|
|
function! lsp#internal#diagnostics#state#_force_notify_buffer(buffer) abort
|
|
" TODO: optimize buffer only
|
|
call s:notify_diagnostics_update()
|
|
endfunction
|
|
|
|
" call s:notify_diagnostics_update()
|
|
" call s:notify_diagnostics_update('server')
|
|
" call s:notify_diagnostics_update('server', 'uri')
|
|
function! s:notify_diagnostics_update(...) abort
|
|
let l:data = { 'server': '$vimlsp', 'response': { 'method': '$/vimlsp/lsp_diagnostics_updated', 'params': {} } }
|
|
" if a:0 > 0 | let l:data['response']['params']['server'] = a:1 | endif
|
|
" if a:0 > 1 | let l:data['response']['params']['uri'] = a:2 | endif
|
|
call lsp#stream(1, l:data)
|
|
doautocmd <nomodeline> User lsp_diagnostics_updated
|
|
endfunction
|
|
|
|
function! lsp#internal#diagnostics#state#_enable_for_buffer(bufnr) abort
|
|
if getbufvar(a:bufnr, 'lsp_diagnostics_enabled', 1) == 0
|
|
call setbufvar(a:bufnr, 'lsp_diagnostics_enabled', 1)
|
|
call s:notify_diagnostics_update()
|
|
endif
|
|
endfunction
|
|
|
|
function! lsp#internal#diagnostics#state#_disable_for_buffer(bufnr) abort
|
|
if getbufvar(a:bufnr, 'lsp_diagnostics_enabled', 1) != 0
|
|
call setbufvar(a:bufnr, 'lsp_diagnostics_enabled', 0)
|
|
call s:notify_diagnostics_update()
|
|
endif
|
|
endfunction
|
|
|
|
function! lsp#internal#diagnostics#state#_is_enabled_for_buffer(bufnr) abort
|
|
return getbufvar(a:bufnr, 'lsp_diagnostics_enabled', 1) == 1
|
|
endfunction
|
|
|
|
" Return dict with diagnostic counts for the specified buffer
|
|
" { 'error': 1, 'warning': 0, 'information': 0, 'hint': 0 }
|
|
function! lsp#internal#diagnostics#state#_get_diagnostics_count_for_buffer(bufnr) abort
|
|
let l:counts = {
|
|
\ 'error': 0,
|
|
\ 'warning': 0,
|
|
\ 'information': 0,
|
|
\ 'hint': 0,
|
|
\ }
|
|
if lsp#internal#diagnostics#state#_is_enabled_for_buffer(a:bufnr)
|
|
let l:uri = lsp#utils#get_buffer_uri(a:bufnr)
|
|
for [l:_, l:response] in items(lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri))
|
|
for l:diagnostic in lsp#utils#iteratable(l:response['params']['diagnostics'])
|
|
let l:key = get(s:diagnostic_kinds, get(l:diagnostic, 'severity', 1) , 'error')
|
|
let l:counts[l:key] += 1
|
|
endfor
|
|
endfor
|
|
end
|
|
return l:counts
|
|
endfunction
|