All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
1 " https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
3 " Refer to https://github.com/microsoft/language-server-protocol/pull/1019 on normalization of urls.
7 " 'method': 'textDocument/publishDiagnostics',
9 " 'uri': 'uri', " this uri is not normalized and is exactly what server returns
10 " 'dignostics': [ " array can never be null but can be empty
11 " https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
12 " { range, message, severity?, code?, codeDesciption?, source?, tags?, relatedInformation?, data? }
17 " Note: Do not remove when buffer unloads or doesn't exist since some server
18 " may send diagnsotics information regardless of textDocument/didOpen.
19 " buffer state is removed when server exits.
20 " TODO: reset buffer state when server initializes. ignoring for now for perf.
21 let s:diagnostics_state = {}
23 " internal state for whether it is enabled or not to avoid multiple subscriptions
26 let s:diagnostic_kinds = {
33 function! lsp#internal#diagnostics#state#_enable() abort
34 " don't even bother registering if the feature is disabled
35 if !g:lsp_diagnostics_enabled | return | endif
37 if s:enabled | return | endif
40 call lsp#internal#diagnostics#state#_reset()
42 let s:Dispose = lsp#callbag#pipe(
46 \ lsp#callbag#filter({x->has_key(x, 'server') && has_key(x, 'response')
47 \ && get(x['response'], 'method', '') ==# 'textDocument/publishDiagnostics'}),
48 \ lsp#callbag#tap({x->s:on_text_documentation_publish_diagnostics(x['server'], x['response'])}),
52 \ lsp#callbag#filter({x->has_key(x, 'server') && has_key(x, 'response')
53 \ && get(x['response'], 'method', '') ==# '$/vimlsp/lsp_server_exit' }),
54 \ lsp#callbag#tap({x->s:on_exit(x['response'])}),
57 \ lsp#callbag#subscribe(),
60 call s:notify_diagnostics_update()
63 function! lsp#internal#diagnostics#state#_disable() abort
64 if !s:enabled | return | endif
65 if exists('s:Dispose')
69 call lsp#internal#diagnostics#state#_reset()
70 call s:notify_diagnostics_update()
74 function! lsp#internal#diagnostics#state#_reset() abort
75 let s:diagnostics_state = {}
76 let s:diagnostics_disabled_buffers = {}
79 " callers should always treat the return value as immutable
81 " 'servername': response
83 function! lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(uri) abort
84 return get(s:diagnostics_state, lsp#utils#normalize_uri(a:uri), {})
87 " callers should always treat the return value as immutable.
88 " callers should treat uri as normalized via lsp#utils#normalize_uri
91 " 'servername': response
94 function! lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_uri_and_server() abort
95 return s:diagnostics_state
98 function! s:on_text_documentation_publish_diagnostics(server, response) abort
99 if lsp#client#is_error(a:response) | return | endif
100 let l:normalized_uri = lsp#utils#normalize_uri(a:response['params']['uri'])
101 if !has_key(s:diagnostics_state, l:normalized_uri)
102 let s:diagnostics_state[l:normalized_uri] = {}
104 let s:diagnostics_state[l:normalized_uri][a:server] = a:response
105 call s:notify_diagnostics_update(a:server, l:normalized_uri)
108 function! s:on_exit(response) abort
109 let l:server = a:response['params']['server']
111 for [l:key, l:value] in items(s:diagnostics_state)
112 if has_key(l:value, l:server)
114 call remove(l:value, l:server)
117 if l:notify | call s:notify_diagnostics_update(l:server) | endif
120 function! lsp#internal#diagnostics#state#_force_notify_buffer(buffer) abort
121 " TODO: optimize buffer only
122 call s:notify_diagnostics_update()
125 " call s:notify_diagnostics_update()
126 " call s:notify_diagnostics_update('server')
127 " call s:notify_diagnostics_update('server', 'uri')
128 function! s:notify_diagnostics_update(...) abort
129 let l:data = { 'server': '$vimlsp', 'response': { 'method': '$/vimlsp/lsp_diagnostics_updated', 'params': {} } }
130 " if a:0 > 0 | let l:data['response']['params']['server'] = a:1 | endif
131 " if a:0 > 1 | let l:data['response']['params']['uri'] = a:2 | endif
132 call lsp#stream(1, l:data)
133 doautocmd <nomodeline> User lsp_diagnostics_updated
136 function! lsp#internal#diagnostics#state#_enable_for_buffer(bufnr) abort
137 if getbufvar(a:bufnr, 'lsp_diagnostics_enabled', 1) == 0
138 call setbufvar(a:bufnr, 'lsp_diagnostics_enabled', 1)
139 call s:notify_diagnostics_update()
143 function! lsp#internal#diagnostics#state#_disable_for_buffer(bufnr) abort
144 if getbufvar(a:bufnr, 'lsp_diagnostics_enabled', 1) != 0
145 call setbufvar(a:bufnr, 'lsp_diagnostics_enabled', 0)
146 call s:notify_diagnostics_update()
150 function! lsp#internal#diagnostics#state#_is_enabled_for_buffer(bufnr) abort
151 return getbufvar(a:bufnr, 'lsp_diagnostics_enabled', 1) == 1
154 " Return dict with diagnostic counts for the specified buffer
155 " { 'error': 1, 'warning': 0, 'information': 0, 'hint': 0 }
156 function! lsp#internal#diagnostics#state#_get_diagnostics_count_for_buffer(bufnr) abort
163 if lsp#internal#diagnostics#state#_is_enabled_for_buffer(a:bufnr)
164 let l:uri = lsp#utils#get_buffer_uri(a:bufnr)
165 for [l:_, l:response] in items(lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri))
166 for l:diagnostic in lsp#utils#iteratable(l:response['params']['diagnostics'])
167 let l:key = get(s:diagnostic_kinds, get(l:diagnostic, 'severity', 1) , 'error')
168 let l:counts[l:key] += 1