Skip to content

Commit f30a8f6

Browse files
committed
Assign diagnostic version per node to reduce overhead
Signed-off-by: iusmac <[email protected]>
1 parent 2baf3da commit f30a8f6

File tree

5 files changed

+67
-29
lines changed

5 files changed

+67
-29
lines changed

lua/nvim-tree/actions/moves/item.lua

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ local view = require "nvim-tree.view"
33
local core = require "nvim-tree.core"
44
local lib = require "nvim-tree.lib"
55
local explorer_node = require "nvim-tree.explorer.node"
6+
local diagnostics = require "nvim-tree.diagnostics"
67

78
local M = {}
89

@@ -33,7 +34,8 @@ function M.fn(opts)
3334
local git_status = explorer_node.get_git_status(node)
3435
valid = git_status ~= nil and (not opts.skip_gitignored or git_status[1] ~= "!!")
3536
elseif opts.what == "diag" then
36-
valid = node.diag_status ~= nil
37+
local diag_status = diagnostics.get_diag_status(node)
38+
valid = diag_status ~= nil and diag_status.value ~= nil
3739
elseif opts.what == "opened" then
3840
valid = vim.fn.bufloaded(node.absolute_path) ~= 0
3941
end

lua/nvim-tree/diagnostics.lua

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,18 @@ local severity_levels = {
1111
Hint = 4,
1212
}
1313

14+
---@class DiagStatus
15+
---@field value integer|nil
16+
---@field cache_version integer
17+
1418
--- A dictionary tree containing buffer-severity mappings.
1519
---@type table
1620
local buffer_severity_dict = {}
1721

22+
--- The cache version number of the buffer-severity mappings.
23+
---@type integer
24+
local BUFFER_SEVERITY_VERSION = 0
25+
1826
---@param path string
1927
---@return string
2028
local function uniformize_path(path)
@@ -80,6 +88,31 @@ local function is_using_coc()
8088
return vim.g.coc_service_initialized == 1
8189
end
8290

91+
---@param node Node
92+
---@return DiagStatus
93+
local function from_cache(node)
94+
local nodepath = uniformize_path(node.absolute_path)
95+
local max_severity = nil
96+
if not node.nodes then
97+
-- direct cache hit for files
98+
max_severity = buffer_severity_dict[nodepath]
99+
else
100+
-- dirs should be searched in the list of cached buffer names by prefix
101+
for bufname, severity in pairs(buffer_severity_dict) do
102+
local node_contains_buf = vim.startswith(bufname, nodepath .. "/")
103+
if node_contains_buf then
104+
if severity == M.severity.max then
105+
max_severity = severity
106+
break
107+
else
108+
max_severity = math.min(max_severity or severity, severity)
109+
end
110+
end
111+
end
112+
end
113+
return { value = max_severity, cache_version = BUFFER_SEVERITY_VERSION }
114+
end
115+
83116
function M.update()
84117
if not M.enable then
85118
return
@@ -91,6 +124,7 @@ function M.update()
91124
else
92125
buffer_severity_dict = from_nvim_lsp()
93126
end
127+
BUFFER_SEVERITY_VERSION = BUFFER_SEVERITY_VERSION + 1
94128
log.node("diagnostics", buffer_severity_dict, "update")
95129
log.profile_end(profile)
96130
if view.is_buf_valid(view.get_bufnr()) then
@@ -100,33 +134,34 @@ function M.update()
100134
end
101135

102136
---@param node Node
103-
function M.update_node_severity_level(node)
137+
---@return DiagStatus|nil
138+
function M.get_diag_status(node)
104139
if not M.enable then
105-
return
140+
return nil
106141
end
107142

108-
local is_folder = node.nodes ~= nil
109-
local nodepath = uniformize_path(node.absolute_path)
143+
-- dir but we shouldn't show on dirs at all
144+
if node.nodes ~= nil and not M.show_on_dirs then
145+
return nil
146+
end
110147

111-
if is_folder then
112-
local max_severity = nil
113-
if M.show_on_dirs and (not node.open or M.show_on_open_dirs) then
114-
for bufname, severity in pairs(buffer_severity_dict) do
115-
local node_contains_buf = vim.startswith(bufname, nodepath .. "/")
116-
if node_contains_buf then
117-
if severity == M.severity.max then
118-
max_severity = severity
119-
break
120-
else
121-
max_severity = math.min(max_severity or severity, severity)
122-
end
123-
end
124-
end
125-
end
126-
node.diag_status = max_severity
127-
else
128-
node.diag_status = buffer_severity_dict[nodepath]
148+
-- here, we do a lazy update of the diagnostic status carried by the node.
149+
-- This is by design, as diagnostics and nodes live in completely separate
150+
-- worlds, and this module is the link between the two
151+
if not node.diag_status or node.diag_status.cache_version < BUFFER_SEVERITY_VERSION then
152+
node.diag_status = from_cache(node)
153+
end
154+
155+
-- file
156+
if not node.nodes then
157+
return node.diag_status
158+
end
159+
160+
-- dir is closed or we should show on open_dirs
161+
if not node.open or M.show_on_open_dirs then
162+
return node.diag_status
129163
end
164+
return nil
130165
end
131166

132167
function M.setup(opts)

lua/nvim-tree/node.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
---@field parent DirNode
1818
---@field type string
1919
---@field watcher function|nil
20-
---@field diag_status integer|nil
20+
---@field diag_status DiagStatus|nil
2121

2222
---@class DirNode: BaseNode
2323
---@field has_children boolean

lua/nvim-tree/renderer/builder.lua

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -413,8 +413,6 @@ end
413413
function Builder:_build_line(node, idx, num_children, unloaded_bufnr)
414414
local copy_paste = require "nvim-tree.actions.fs.copy-paste"
415415

416-
require("nvim-tree.diagnostics").update_node_severity_level(node)
417-
418416
-- various components
419417
local indent_markers = pad.get_indent_markers(self.depth, idx, num_children, node, self.markers)
420418
local arrows = pad.get_arrows(node)

lua/nvim-tree/renderer/components/diagnostics.lua

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
2+
local diagnostics = require "nvim-tree.diagnostics"
23

34
local M = {
45
HS_FILE = {},
@@ -17,10 +18,11 @@ function M.get_highlight(node)
1718
end
1819

1920
local group
21+
local diag_status = diagnostics.get_diag_status(node)
2022
if node.nodes then
21-
group = M.HS_FOLDER[node.diag_status]
23+
group = M.HS_FOLDER[diag_status and diag_status.value]
2224
else
23-
group = M.HS_FILE[node.diag_status]
25+
group = M.HS_FILE[diag_status and diag_status.value]
2426
end
2527

2628
if group then
@@ -35,7 +37,8 @@ end
3537
---@return HighlightedString|nil modified icon
3638
function M.get_icon(node)
3739
if node and M.config.diagnostics.enable and M.config.renderer.icons.show.diagnostics then
38-
return M.ICON[node.diag_status]
40+
local diag_status = diagnostics.get_diag_status(node)
41+
return M.ICON[diag_status and diag_status.value]
3942
end
4043
end
4144

0 commit comments

Comments
 (0)