Skip to content

Instantly share code, notes, and snippets.

@phelipetls
Last active December 9, 2022 18:21
Show Gist options
  • 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()]]
@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