vim-lsp
vim-lsp copied to clipboard
use error quicklist for LSP diagnostics?
Right now, I can't use :cp, :cn etc. for LSP diagnostics, instead there's a totally separate mechanism. Is there any way to make this possible?
Using latest vim.
Since things like lsp-call-hierarchy-incoming loads into the quicklist, it seems inconsistent that the diagnostics list is completely separate.
I think this is #761 but I can't reopen that.
I made this change:
function! lsp#internal#diagnostics#document_diagnostics_command#do(options) abort
...
if empty(l:result)
call lsp#utils#error('No diagnostics results')
return
else
"call setloclist(0, l:result)
call setqflist(l:result)
echo 'Retrieved diagnostics results'
"botright lopen
endif
which works but I have to call :LspDocumentDiagnostics. I'd like the automatic adding/removing of these to go to quick fix instead of loc list. I don't know anything about vimscripting so I can't find where I might do that.
+1, I used to have this functionality in ALE and it is very useful. I could simply type :lw and all the diagnostics would be populated in the location list
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
still valid request.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
still a valid request
Here is my solution:
" NOTE: I rely on $PWD being the project root. Works automatically in my case since I open vim with Unity
" NOTE: This is just done to filter out some stuff. I use Unity and omnisharp shows a bunch of hints about unnecessary using directives
let s:project_file_uris = map(systemlist("find $PWD/Assets/ -name '*.cs'"), {_, val -> lsp#utils#path_to_uri(val)})
let s:qflist = []
function! Updateqf(timer)
let l:result = []
for l:uri in s:project_file_uris
let l:diag = lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri)
" TODO: custom solution just for Unity & Omnisharp. Make it work for everything
" NOTE: While the server is starting up there are no diagnostics responses yet. Hence l:diag['omnisharp_mono'] returns an error
if !has_key(l:diag, 'omnisharp_mono')
return
endif
let l:result += lsp#ui#vim#utils#diagnostics_to_loc_list({ 'response': l:diag['omnisharp_mono'] })
endfor
" Don't change the qf list if there is no change (otherwise qf list jumps back to the first entry everytime this function is called)
if l:result == s:qflist
return
endif
" Don't change the quickfix list while I'm editing. I don't like stuff changing on my screen while I type
if mode() == 'i'
return
endif
" Update current qf list
let s:qflist = l:result
if empty(l:result)
cclose
else
" Open quickfix list without focusing
let l:bufname=bufname('%')
call setqflist(l:result, 'r')
botright copen 8
exec bufwinnr(l:bufname) . 'wincmd w'
endif
endfunction
" Call the function every second
let g:lspqftimer = timer_start(1000, 'Updateqf', {'repeat': -1})
It's customized for Unity/C# editing but hopefully you can adapt it for your purposes.
I added some comments because I wrote shitty code to quickly get to work.
I use a timer to run the function every second. There is an autocommand from vim-lsp that is triggered every time there is a diagnostic change but that happened too often for my taste (and also isn't asynchronous). Same for the vim autocommand when the text changed.
The diagnostics list being loaded in the location list is not inconsistent. The location list is local to a buffer, and LspDocumentDiagnostics only loads the diagnostics for the current buffer. I just happen to like having a global quickfix list that shows me all the problems in my code base.
Final word of caution: I also know next to nothing about vimscript, this is probably not the best way to do this.
Thanks @pkrack ! Here's what I added to the bottom of lsp.vim for my use case:
let s:qflist = []
function! Updateqf(timer)
let l:options = get(a:000, 0, {})
let l:server = get(l:options, 'server', '')
let l:bufnr = bufnr('%')
let l:result = []
if !lsp#internal#diagnostics#state#_is_enabled_for_buffer(l:bufnr)
return {}
endif
let l:uri = lsp#utils#get_buffer_uri(l:bufnr)
let l:diag = lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri)
if !has_key(l:diag, 'clangd')
return
endif
let l:result += lsp#ui#vim#utils#diagnostics_to_loc_list({ 'response': l:diag['clangd'] })
if l:result == s:qflist
return
endif
" Don't change the quickfix list while I'm editing. I don't like stuff changing on my screen while I type
if mode() == 'i'
return
endif
" Update current qf list
let s:qflist = l:result
if empty(l:result)
cclose
else
call setqflist(l:result, 'r')
endif
endfunction
" Call the function every second
let g:lspqftimer = timer_start(1000, 'Updateqf', {'repeat': -1})