Skip to content

Instantly share code, notes, and snippets.

@phelipetls
Last active December 9, 2022 18:21
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save phelipetls/0aeb9f4aca9af25d9f45ee56e0c5a340 to your computer and use it in GitHub Desktop.
Save phelipetls/0aeb9f4aca9af25d9f45ee56e0c5a340 to your computer and use it in GitHub Desktop.
Neovim built-in LSP diagnostics into location list
local severity_map = { "E", "W", "I", "H" }
local parse_diagnostics = function(diagnostics)
if not diagnostics then return end
local items = {}
for _, diagnostic in ipairs(diagnostics) do
local fname = vim.fn.bufname()
local position = diagnostic.range.start
local severity = diagnostic.severity
table.insert(items, {
filename = fname,
type = severity_map[severity],
lnum = position.line + 1,
col = position.character + 1,
text = diagnostic.message:gsub("\r", ""):gsub("\n", " ")
})
end
return items
end
-- redefine unwanted callbacks to be an empty function
-- notice that I keep `vim.lsp.util.buf_diagnostics_underline()`
vim.lsp.util.buf_diagnostics_signs = function() return end
vim.lsp.util.buf_diagnostics_virtual_text = function() return end
update_diagnostics_loclist = function()
bufnr = vim.fn.bufnr()
diagnostics = vim.lsp.util.diagnostics_by_buf[bufnr]
items = parse_diagnostics(diagnostics)
vim.lsp.util.set_loclist(items)
vim.api.nvim_command("doautocmd QuickFixCmdPost")
end
vim.api.nvim_command [[autocmd! User LspDiagnosticsChanged lua update_diagnostics_loclist()]]
@phelipetls
Copy link
Author

Later I preferred to put it into the location list so it wouldn't conflict with a quickfix list if there is one (for example, if I did some grep and then save the file, the grep qflist would be gone which is not what I want).

So, in this way, the LSP diagnostics will be put into the location list, which will be opened on save and closed when it's empty.

This is more appropriate because the location list really is meant to be used per window and the quickfix list is a more generic thing.

@svermeulen
Copy link

For people like me that want to both have the diagnostics in the location list, and keep the virtual text, I suggest the following approach instead:

  • Subscribe to the LspDiagnosticsChanged autocmd
  • Get the diagnostics for the current buffer by calling vim.lsp.util.diagnostics_by_buf
  • Add these to location list

@klw0
Copy link

klw0 commented May 1, 2020

@svermeulen Utilizing the LspDiagnosticsChanged autocmd and vim.lsp.util.diagnostics_by_buf is certainly the better approach, but it's worth mentioning that vim.lsp.util.diagnostics_by_buf did not exist until neovim/neovim@ef0398f, 14 days after the current revision of this gist (as of writing).

Additionally, if somebody did want to prevent the virtual text, it may be better to not override the textDocument/publishDiagnostics callback, and instead redefine vim.lsp.util.diagnostics_virtual_text to be an empty function. This is a hack since there's currently not a global option to disable virtual text (I suspect there will be one in the near future), but it's a lesser evil than redefining the entire diagnostics callback to prevent virtual text. By redefining the callback, you run the risk of falling out of sync with upstream.

@phelipetls
Copy link
Author

I have taken your advice into account and updated the gist. It's much cleaner now, thanks!

@phelipetls
Copy link
Author

I wonder though, is that function parse_diagnostics really necessary? vim.lsp.util.locations_to_items doesn't work for me... although by the source code it does seem to kinda do what I want, but it does it in a more complex/sophisticated way.

@andreit
Copy link

andreit commented Mar 31, 2021

Thanks for this! Using NVIM v0.5.0-dev+94cf7bb I had to change diagnostics = vim.lsp.util.diagnostics_by_buf[bufnr] to vim.lsp.diagnostic.get().

@phelipetls
Copy link
Author

This is pretty old already, I believe you can just use vim.lsp.diagnostic.set_loclist(). At least that's what I'm using and it works.

@andreit
Copy link

andreit commented Apr 1, 2021

Awesome, thanks! That seems to work for me too.

@pavannaganna
Copy link

From lsp documentation

vim.lsp.diagnostic.set_loclist()        Use vim.diagnostic.setloclist() instead

@hpaul
Copy link

hpaul commented Dec 9, 2022

Yes, it was added inside neovim api. One could write it as this snippet:

-- Populate loclist with the current buffer diagnostics
vim.api.nvim_create_autocmd('DiagnosticChanged', {
  callback = function(args)
    vim.diagnostic.setloclist({open = false})
  end,
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment