For all I know there’s a builtin/better way to do this, but here’s what I’ve got. The idea is to first save off the value of vim.diagnostic._set_signs
, and then have a wrapper on top of it that ensures that there is only a single entry in the sign column for language server diagnostics (the highest of any on that line).
local lspctl = {}
local module = { orig_set_signs = vim.diagnostic._set_signs }
lspctl.set_signs = function(namespace, bufnr, diagnostics, opts)
opts.priority = 10
-- First find the highest-level diagnostic for each line that currently exists
local existing = {}
for _, diagnostic in ipairs(vim.diagnostic.get(bufnr)) do
if not existing[diagnostic.lnum] then
existing[diagnostic.lnum] = diagnostic
elseif diagnostic.severity < existing[diagnostic.lnum].severity then
existing[diagnostic.lnum] = diagnostic
end
end
-- Now iterate over all diagnostics that are to be added, and only keep them
-- if they are higher than the current diagnostic
local add = {}
for _, diagnostic in ipairs(diagnostics) do
if not existing[diagnostic.lnum] then
existing[diagnostic.lnum] = diagnostic
add[diagnostic.lnum] = diagnostic
elseif existing[diagnostic.lnum] and diagnostic.severity <= existing[diagnostic.lnum].severity then
existing[diagnostic.lnum] = diagnostic
add[diagnostic.lnum] = diagnostic
end
end
local filtered = vim.tbl_values(add)
if #filtered == 0 then
-- Skip adding signs if there would be no net change (all lower than existing)
return
end
module.orig_set_signs(namespace, bufnr, filtered, opts)
end
return lspctl
My main concern is that while it seems to be working fine, I am not 100% sure with how diagnostic signs are removed, and if I need to be handling removing them here as well. It would seem not, but either way any feedback would be appreciated (cough @mjlbach )