perf(explorer): only update tree when diagnostics actually changed

This commit is contained in:
Folke Lemaitre 2025-02-20 09:26:04 +01:00
parent 06400568aa
commit 1142f46a27
No known key found for this signature in database
GPG key ID: 41F8B1FBACAE2040
3 changed files with 57 additions and 4 deletions

View file

@ -6,6 +6,8 @@ function M.update(cwd)
local Tree = require("snacks.explorer.tree")
local node = Tree:find(cwd)
local snapshot = Tree:snapshot(node, { "severity" })
Tree:walk(node, function(n)
n.severity = nil
end, { all = true })
@ -31,6 +33,8 @@ function M.update(cwd)
end
end
end
return Tree:changed(node, snapshot)
end
return M

View file

@ -21,6 +21,8 @@
---@field exclude? string[] globs to exclude
---@field include? string[] globs to exclude
---@alias snacks.picker.explorer.Snapshot {fields: string[], state:table<snacks.picker.explorer.Node, any[]>}
local uv = vim.uv or vim.loop
local function norm(path)
@ -331,4 +333,42 @@ function Tree:next(cwd, filter, opts)
return next or first
end
---@param node snacks.picker.explorer.Node
---@param snapshot snacks.picker.explorer.Snapshot
function Tree:changed(node, snapshot)
local old = snapshot.state
local current = self:snapshot(node, snapshot.fields).state
if vim.tbl_count(current) ~= vim.tbl_count(old) then
return true
end
for n, data in pairs(current) do
local prev = old[n]
if not prev then
return true
end
if not vim.deep_equal(prev, data) then
return true
end
end
return false
end
---@param node snacks.picker.explorer.Node
---@param fields string[]
function Tree:snapshot(node, fields)
---@type snacks.picker.explorer.Snapshot
local ret = {
state = {},
fields = fields,
}
Tree:walk(node, function(n)
local data = {} ---@type any[]
for f, field in ipairs(fields) do
data[f] = n[field]
end
ret.state[n] = data
end, { all = true })
return ret
end
return Tree.new()

View file

@ -72,12 +72,21 @@ function State.new(picker)
end)
if opts.diagnostics then
picker.list.win:on("DiagnosticChanged", function(_, ev)
local dirty = false
local diag_update = Snacks.util.debounce(function()
dirty = false
local p = ref()
if p then
require("snacks.explorer.diagnostics").update(p:cwd())
p.list:set_target()
p:find()
if require("snacks.explorer.diagnostics").update(p:cwd()) then
p.list:set_target()
p:find()
end
end
end, { ms = 200 })
picker.list.win:on({ "InsertLeave", "DiagnosticChanged" }, function(_, ev)
dirty = dirty or ev.event == "DiagnosticChanged"
if vim.fn.mode() == "n" and dirty then
diag_update()
end
end)
end