Skip to content

Commit 1f3ffd6

Browse files
authored
fix(#2954): more efficient LSP updates, increase diagnostics.debounce_delay from 50ms to 500ms (#3007)
* fix(#2954): use LSP diagnostic data deltas from events instead of a full query * fix(#2954): use LSP diagnostic data deltas from events instead of a full query
1 parent f7c65e1 commit 1f3ffd6

File tree

3 files changed

+63
-48
lines changed

3 files changed

+63
-48
lines changed

Diff for: doc/nvim-tree-lua.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ Following is the default configuration. See |nvim-tree-opts| for details. >lua
527527
enable = false,
528528
show_on_dirs = false,
529529
show_on_open_dirs = true,
530-
debounce_delay = 50,
530+
debounce_delay = 500,
531531
severity = {
532532
min = vim.diagnostic.severity.HINT,
533533
max = vim.diagnostic.severity.ERROR,
@@ -1272,7 +1272,7 @@ Enable/disable the feature.
12721272

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

12771277
*nvim-tree.diagnostics.show_on_dirs*
12781278
Show diagnostic icons on parent directories.

Diff for: lua/nvim-tree.lua

+4-4
Original file line numberDiff line numberDiff line change
@@ -208,16 +208,16 @@ local function setup_autocommands(opts)
208208

209209
if opts.diagnostics.enable then
210210
create_nvim_tree_autocmd("DiagnosticChanged", {
211-
callback = function()
211+
callback = function(ev)
212212
log.line("diagnostics", "DiagnosticChanged")
213-
require("nvim-tree.diagnostics").update()
213+
require("nvim-tree.diagnostics").update_lsp(ev)
214214
end,
215215
})
216216
create_nvim_tree_autocmd("User", {
217217
pattern = "CocDiagnosticChange",
218218
callback = function()
219219
log.line("diagnostics", "CocDiagnosticChange")
220-
require("nvim-tree.diagnostics").update()
220+
require("nvim-tree.diagnostics").update_coc()
221221
end,
222222
})
223223
end
@@ -386,7 +386,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
386386
enable = false,
387387
show_on_dirs = false,
388388
show_on_open_dirs = true,
389-
debounce_delay = 50,
389+
debounce_delay = 500,
390390
severity = {
391391
min = vim.diagnostic.severity.HINT,
392392
max = vim.diagnostic.severity.ERROR,

Diff for: lua/nvim-tree/diagnostics.lua

+57-42
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ local COC_SEVERITY_LEVELS = {
1717
}
1818

1919
---Absolute Node path to LSP severity level
20-
---@alias NodeSeverities table<string, lsp.DiagnosticSeverity>
20+
---@alias NodeSeverities table<string, vim.diagnostic.Severity>
2121

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

40-
---Marshal severities from LSP. Does nothing when LSP disabled.
41-
---@return NodeSeverities
42-
local function from_nvim_lsp()
43-
local buffer_severity = {}
44-
45-
-- is_enabled is not present in all 0.10 builds/releases, see #2781
46-
local is_enabled = false
47-
if vim.fn.has("nvim-0.10") == 1 and type(vim.diagnostic.is_enabled) == "function" then
48-
is_enabled = vim.diagnostic.is_enabled()
49-
elseif type(vim.diagnostic.is_disabled) == "function" then ---@diagnostic disable-line: deprecated
50-
is_enabled = not vim.diagnostic.is_disabled() ---@diagnostic disable-line: deprecated
51-
end
52-
53-
if is_enabled then
54-
for _, diagnostic in ipairs(vim.diagnostic.get(nil, { severity = M.severity })) do
55-
if diagnostic.severity and diagnostic.bufnr and vim.api.nvim_buf_is_valid(diagnostic.bufnr) then
56-
local bufname = uniformize_path(vim.api.nvim_buf_get_name(diagnostic.bufnr))
57-
if not buffer_severity[bufname] or diagnostic.severity < buffer_severity[bufname] then
58-
buffer_severity[bufname] = diagnostic.severity
59-
end
60-
end
61-
end
62-
end
63-
64-
return buffer_severity
65-
end
66-
6740
---Severity is within diagnostics.severity.min, diagnostics.severity.max
6841
---@param severity lsp.DiagnosticSeverity
6942
---@param config table
@@ -135,35 +108,77 @@ local function from_cache(node)
135108
for bufname, severity in pairs(NODE_SEVERITIES) do
136109
local node_contains_buf = vim.startswith(bufname, nodepath .. "/")
137110
if node_contains_buf then
138-
if severity == M.severity.max then
111+
if not max_severity or severity < max_severity then
139112
max_severity = severity
140-
break
141-
else
142-
max_severity = math.min(max_severity or severity, severity)
143113
end
144114
end
145115
end
146116
end
147117
return { value = max_severity, cache_version = NODE_SEVERITIES_VERSION }
148118
end
149119

150-
---Fired on DiagnosticChanged and CocDiagnosticChanged events:
120+
---Fired on DiagnosticChanged for a single buffer.
121+
---This will be called on set and reset of diagnostics.
122+
---On disabling LSP, a reset event will be sent for all buffers.
123+
---@param ev table standard event with data.diagnostics populated
124+
function M.update_lsp(ev)
125+
if not M.enable or not ev or not ev.data or not ev.data.diagnostics then
126+
return
127+
end
128+
129+
local profile_event = log.profile_start("DiagnosticChanged event")
130+
131+
---@type vim.Diagnostic[]
132+
local diagnostics = ev.data.diagnostics
133+
134+
-- use the buffer from the event, as ev.data.diagnostics will be empty on resolved diagnostics
135+
local bufname = uniformize_path(vim.api.nvim_buf_get_name(ev.buf))
136+
137+
---@type vim.diagnostic.Severity?
138+
local new_severity = nil
139+
140+
-- most severe (lowest) severity in user range
141+
for _, diagnostic in ipairs(diagnostics) do
142+
if diagnostic.severity >= M.severity.max and diagnostic.severity <= M.severity.min then
143+
if not new_severity or diagnostic.severity < new_severity then
144+
new_severity = diagnostic.severity
145+
end
146+
end
147+
end
148+
149+
-- record delta and schedule a redraw
150+
if new_severity ~= NODE_SEVERITIES[bufname] then
151+
NODE_SEVERITIES[bufname] = new_severity
152+
NODE_SEVERITIES_VERSION = NODE_SEVERITIES_VERSION + 1
153+
154+
utils.debounce("DiagnosticChanged redraw", M.debounce_delay, function()
155+
local profile_redraw = log.profile_start("DiagnosticChanged redraw")
156+
157+
local explorer = core.get_explorer()
158+
if explorer then
159+
explorer.renderer:draw()
160+
end
161+
162+
log.profile_end(profile_redraw)
163+
end)
164+
end
165+
166+
log.profile_end(profile_event)
167+
end
168+
169+
---Fired on CocDiagnosticChanged events:
151170
---debounced retrieval, cache update, version increment and draw
152-
function M.update()
171+
function M.update_coc()
153172
if not M.enable then
154173
return
155174
end
156-
utils.debounce("diagnostics", M.debounce_delay, function()
157-
local profile = log.profile_start("diagnostics update")
158-
if is_using_coc() then
159-
NODE_SEVERITIES = from_coc()
160-
else
161-
NODE_SEVERITIES = from_nvim_lsp()
162-
end
175+
utils.debounce("CocDiagnosticChanged update", M.debounce_delay, function()
176+
local profile = log.profile_start("CocDiagnosticChanged update")
177+
NODE_SEVERITIES = from_coc()
163178
NODE_SEVERITIES_VERSION = NODE_SEVERITIES_VERSION + 1
164179
if log.enabled("diagnostics") then
165180
for bufname, severity in pairs(NODE_SEVERITIES) do
166-
log.line("diagnostics", "Indexing bufname '%s' with severity %d", bufname, severity)
181+
log.line("diagnostics", "COC Indexing bufname '%s' with severity %d", bufname, severity)
167182
end
168183
end
169184
log.profile_end(profile)

0 commit comments

Comments
 (0)