Feedback on LSP diagnostics wrapper

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 :wink:)

1 Like

Isn’t this already covered in the example in :help diagnostic-handlers-example?

Also I am officially off the hook for diagnostics now that @gpanders factored it out of the LSP module :upside_down_face:

1 Like

I’m pretty sure all problems are @mjlbach problems :thinking:

The one in the docs looks close to this, obviously doing a better job too. Thanks for pointing me there.

2 Likes

On latest master you could also disable signs and create your custom handler. See :help diagnostic-handler.

Relying on private methods (_set_signs) is a bad idea as it can break any time.