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.
9 function! s:severity_threshold() abort
10 let s = g:lsp_ale_diagnostics_severity
13 elseif s ==? 'warning' || s ==? 'warn'
15 elseif s ==? 'information' || s ==? 'info'
20 throw 'vim-lsp-ale: Unexpected severity "' . s . '". Severity must be one of "error", "warning", "information", "hint"'
24 function! s:get_loc_type(severity) abort
25 if a:severity == s:ERROR
27 elseif a:severity == s:WARN
29 elseif a:severity == s:INFO
31 elseif a:severity == s:HINT
34 throw 'vim-lsp-ale: Unexpected severity: ' . a:severity
38 let s:prev_num_diags = {}
39 function! lsp#ale#_reset_prev_num_diags() abort
40 let s:prev_num_diags = {}
43 function! s:can_skip_diags(server, uri, diags) abort
44 if !has_key(s:prev_num_diags, a:server)
45 let s:prev_num_diags[a:server] = {}
47 let prev = s:prev_num_diags[a:server]
49 let num_diags = len(a:diags)
50 if num_diags == 0 && get(prev, a:uri, -1) == 0
51 " Some language servers send diagnostics notifications even if the
52 " results are not changed from previous. It's hard to check the
53 " notifications are perfectly the same as previous. Here only checks
54 " emptiness and skip if both previous ones and current ones are
56 " I believe programmers usually try to keep no lint errors in the
57 " source code they are writing :)
61 let prev[a:uri] = num_diags
65 function! s:can_skip_all_diags(uri, all_diags) abort
66 for [server, diags] in items(a:all_diags)
67 if !s:can_skip_diags(server, a:uri, diags.params.diagnostics)
74 function! s:is_active_linter() abort
75 if g:lsp_ale_auto_enable_linter
78 let active_linters = get(b:, 'ale_linters', get(g:ale_linters, &filetype, []))
79 return index(active_linters, 'vim-lsp') >= 0
82 function! lsp#ale#on_ale_want_results(bufnr) abort
83 " Note: Checking lsp#internal#diagnostics#state#_is_enabled_for_buffer here. If previous lint
84 " errors remain in a buffer, they won't be updated when vim-lsp is disabled for the buffer.
85 if s:Dispose is v:null || !lsp#internal#diagnostics#state#_is_enabled_for_buffer(a:bufnr)
89 let uri = lsp#utils#get_buffer_uri(a:bufnr)
90 let all_diags = lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(uri)
91 if empty(all_diags) || s:can_skip_all_diags(uri, all_diags)
92 " Do nothing when no diagnostics results
96 if s:is_active_linter()
97 call ale#other_source#StartChecking(a:bufnr, 'vim-lsp')
98 " Avoid the issue that sign and highlight are not set
99 " https://github.com/dense-analysis/ale/issues/3690
100 call timer_start(0, {-> s:notify_diag_to_ale(a:bufnr, all_diags) })
104 function! s:notify_diag_to_ale(bufnr, diags) abort
106 let threshold = s:severity_threshold()
108 for [server, diag] in items(a:diags)
109 " Note: Do not filter `diag` destructively since the object is also used by vim-lsp
110 let locs = lsp#ui#vim#utils#diagnostics_to_loc_list({'response': diag})
113 let severity = get(diag.params.diagnostics[idx], 'severity', s:ERROR)
114 if severity > threshold
117 let loc.text = '[' . server . '] ' . loc.text
118 let loc.type = s:get_loc_type(severity)
124 " Since ale#other_source#StartChecking() was already called, ale#other_source#ShowResults()
125 " needs to be called to notify ALE that checking was done.
126 call ale#other_source#ShowResults(a:bufnr, 'vim-lsp', [])
127 let msg = v:exception . ' at ' . v:throwpoint
128 if msg !~# '^vim-lsp-ale: '
129 " Avoid E608 on rethrowing exceptions from Vim script runtime
130 let msg = 'vim-lsp-ale: Error while notifying results to ALE: ' . msg
134 call ale#other_source#ShowResults(a:bufnr, 'vim-lsp', results)
137 function! s:notify_diag_to_ale_for_buf(bufnr) abort
138 if !s:is_active_linter()
142 let uri = lsp#utils#get_buffer_uri(a:bufnr)
143 let diags = lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(uri)
144 call s:notify_diag_to_ale(a:bufnr, diags)
147 function! s:on_diagnostics(res) abort
148 let uri = a:res.response.params.uri
149 if s:can_skip_diags(a:res.server, uri, a:res.response.params.diagnostics)
153 let path = lsp#utils#uri_to_path(uri)
154 let bufnr = bufnr('^' . path . '$')
156 " This branch is reachable when vim-lsp receives some notifications
157 " but the buffer for them was already deleted. This can happen since
158 " notifications are asynchronous
162 call ale#other_source#StartChecking(bufnr, 'vim-lsp')
163 " Use timer_start to ensure calling s:notify_diag_to_ale after all
164 " subscribers handled the publishDiagnostics event.
165 " lsp_setup is hooked before vim-lsp sets various internal hooks. So this
166 " function is called before the response is not handled by vim-lsp yet.
167 call timer_start(0, {-> s:notify_diag_to_ale_for_buf(bufnr) })
170 function! s:is_diagnostics_response(item) abort
171 if !has_key(a:item, 'server') || !has_key(a:item, 'response')
174 let res = a:item.response
175 if !has_key(res, 'method')
178 return res.method ==# 'textDocument/publishDiagnostics'
181 function! lsp#ale#enable() abort
182 if s:Dispose isnot v:null
186 let s:Dispose = lsp#callbag#pipe(
188 \ lsp#callbag#filter(funcref('s:is_diagnostics_response')),
189 \ lsp#callbag#subscribe({ 'next': funcref('s:on_diagnostics') }),
193 function! lsp#ale#disable() abort
194 if s:Dispose is v:null
198 let s:Dispose = v:null
201 function! lsp#ale#enabled() abort
202 return s:Dispose isnot v:null