Skip to content

fix(#2954): more efficient LSP updates, increase diagnostics.debounce_delay from 50ms to 500ms #3007

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions doc/nvim-tree-lua.txt
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ Following is the default configuration. See |nvim-tree-opts| for details. >lua
enable = false,
show_on_dirs = false,
show_on_open_dirs = true,
debounce_delay = 50,
debounce_delay = 500,
severity = {
min = vim.diagnostic.severity.HINT,
max = vim.diagnostic.severity.ERROR,
Expand Down Expand Up @@ -1272,7 +1272,7 @@ Enable/disable the feature.

*nvim-tree.diagnostics.debounce_delay*
Idle milliseconds between diagnostic event and update.
Type: `number`, Default: `50` (ms)
Type: `number`, Default: `500` (ms)

*nvim-tree.diagnostics.show_on_dirs*
Show diagnostic icons on parent directories.
Expand Down
8 changes: 4 additions & 4 deletions lua/nvim-tree.lua
Original file line number Diff line number Diff line change
Expand Up @@ -208,16 +208,16 @@ local function setup_autocommands(opts)

if opts.diagnostics.enable then
create_nvim_tree_autocmd("DiagnosticChanged", {
callback = function()
callback = function(ev)
log.line("diagnostics", "DiagnosticChanged")
require("nvim-tree.diagnostics").update()
require("nvim-tree.diagnostics").update_lsp(ev)
end,
})
create_nvim_tree_autocmd("User", {
pattern = "CocDiagnosticChange",
callback = function()
log.line("diagnostics", "CocDiagnosticChange")
require("nvim-tree.diagnostics").update()
require("nvim-tree.diagnostics").update_coc()
end,
})
end
Expand Down Expand Up @@ -386,7 +386,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
enable = false,
show_on_dirs = false,
show_on_open_dirs = true,
debounce_delay = 50,
debounce_delay = 500,
severity = {
min = vim.diagnostic.severity.HINT,
max = vim.diagnostic.severity.ERROR,
Expand Down
99 changes: 57 additions & 42 deletions lua/nvim-tree/diagnostics.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ local COC_SEVERITY_LEVELS = {
}

---Absolute Node path to LSP severity level
---@alias NodeSeverities table<string, lsp.DiagnosticSeverity>
---@alias NodeSeverities table<string, vim.diagnostic.Severity>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lsp.DiagnosticSeverity and vim.diagnostic.Severity are effectively the same. It's not clear which is preferred, so I went with the one from vim.Diagnostic


---@class DiagStatus
---@field value lsp.DiagnosticSeverity|nil
Expand All @@ -37,33 +37,6 @@ local function uniformize_path(path)
return utils.canonical_path(path:gsub("\\", "/"))
end

---Marshal severities from LSP. Does nothing when LSP disabled.
---@return NodeSeverities
local function from_nvim_lsp()
local buffer_severity = {}

-- is_enabled is not present in all 0.10 builds/releases, see #2781
local is_enabled = false
if vim.fn.has("nvim-0.10") == 1 and type(vim.diagnostic.is_enabled) == "function" then
is_enabled = vim.diagnostic.is_enabled()
elseif type(vim.diagnostic.is_disabled) == "function" then ---@diagnostic disable-line: deprecated
is_enabled = not vim.diagnostic.is_disabled() ---@diagnostic disable-line: deprecated
end

if is_enabled then
for _, diagnostic in ipairs(vim.diagnostic.get(nil, { severity = M.severity })) do
if diagnostic.severity and diagnostic.bufnr and vim.api.nvim_buf_is_valid(diagnostic.bufnr) then
local bufname = uniformize_path(vim.api.nvim_buf_get_name(diagnostic.bufnr))
if not buffer_severity[bufname] or diagnostic.severity < buffer_severity[bufname] then
buffer_severity[bufname] = diagnostic.severity
end
end
end
end

return buffer_severity
end

---Severity is within diagnostics.severity.min, diagnostics.severity.max
---@param severity lsp.DiagnosticSeverity
---@param config table
Expand Down Expand Up @@ -135,35 +108,77 @@ local function from_cache(node)
for bufname, severity in pairs(NODE_SEVERITIES) do
local node_contains_buf = vim.startswith(bufname, nodepath .. "/")
if node_contains_buf then
if severity == M.severity.max then
if not max_severity or severity < max_severity then
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This became a warning hence it was simplified.

max_severity = severity
break
else
max_severity = math.min(max_severity or severity, severity)
end
end
end
end
return { value = max_severity, cache_version = NODE_SEVERITIES_VERSION }
end

---Fired on DiagnosticChanged and CocDiagnosticChanged events:
---Fired on DiagnosticChanged for a single buffer.
---This will be called on set and reset of diagnostics.
---On disabling LSP, a reset event will be sent for all buffers.
---@param ev table standard event with data.diagnostics populated
function M.update_lsp(ev)
if not M.enable or not ev or not ev.data or not ev.data.diagnostics then
return
end

local profile_event = log.profile_start("DiagnosticChanged event")

---@type vim.Diagnostic[]
local diagnostics = ev.data.diagnostics

-- use the buffer from the event, as ev.data.diagnostics will be empty on resolved diagnostics
local bufname = uniformize_path(vim.api.nvim_buf_get_name(ev.buf))

---@type vim.diagnostic.Severity?
local new_severity = nil

-- most severe (lowest) severity in user range
for _, diagnostic in ipairs(diagnostics) do
if diagnostic.severity >= M.severity.max and diagnostic.severity <= M.severity.min then
if not new_severity or diagnostic.severity < new_severity then
new_severity = diagnostic.severity
end
end
end

-- record delta and schedule a redraw
if new_severity ~= NODE_SEVERITIES[bufname] then
NODE_SEVERITIES[bufname] = new_severity
NODE_SEVERITIES_VERSION = NODE_SEVERITIES_VERSION + 1

utils.debounce("DiagnosticChanged redraw", M.debounce_delay, function()
local profile_redraw = log.profile_start("DiagnosticChanged redraw")

local explorer = core.get_explorer()
if explorer then
explorer.renderer:draw()
end

log.profile_end(profile_redraw)
end)
end

log.profile_end(profile_event)
end

---Fired on CocDiagnosticChanged events:
---debounced retrieval, cache update, version increment and draw
function M.update()
function M.update_coc()
if not M.enable then
return
end
utils.debounce("diagnostics", M.debounce_delay, function()
local profile = log.profile_start("diagnostics update")
if is_using_coc() then
NODE_SEVERITIES = from_coc()
else
NODE_SEVERITIES = from_nvim_lsp()
end
utils.debounce("CocDiagnosticChanged update", M.debounce_delay, function()
local profile = log.profile_start("CocDiagnosticChanged update")
NODE_SEVERITIES = from_coc()
NODE_SEVERITIES_VERSION = NODE_SEVERITIES_VERSION + 1
if log.enabled("diagnostics") then
for bufname, severity in pairs(NODE_SEVERITIES) do
log.line("diagnostics", "Indexing bufname '%s' with severity %d", bufname, severity)
log.line("diagnostics", "COC Indexing bufname '%s' with severity %d", bufname, severity)
end
end
log.profile_end(profile)
Expand Down
Loading