mirror of
https://github.com/folke/snacks.nvim
synced 2025-08-04 10:49:08 +00:00
perf(explorer): use cache when possible for opening/closing directories. Closes #869
This commit is contained in:
parent
d897ead2b7
commit
cef4fc9181
1 changed files with 47 additions and 16 deletions
|
@ -145,6 +145,7 @@ local git_tree_status = {} ---@type table<string, string>
|
|||
---@field on_find? fun()?
|
||||
---@field git_status {file: string, status: string, sort?:string}[]
|
||||
---@field expanded table<string, boolean>
|
||||
---@field cache table<string, snacks.picker.explorer.Item[]>
|
||||
local State = {}
|
||||
State.__index = State
|
||||
---@param picker snacks.Picker
|
||||
|
@ -158,6 +159,7 @@ function State.new(picker)
|
|||
self.tick = 0
|
||||
self.git_status = {}
|
||||
self.expanded = {}
|
||||
self.cache = {}
|
||||
local buf = vim.api.nvim_win_get_buf(picker.main)
|
||||
local buf_file = vim.fs.normalize(vim.api.nvim_buf_get_name(buf))
|
||||
if uv.fs_stat(buf_file) then
|
||||
|
@ -171,11 +173,11 @@ function State.new(picker)
|
|||
end)
|
||||
end)
|
||||
picker.list.win:on("TermClose", function()
|
||||
self:update()
|
||||
self:update({ force = true })
|
||||
end, { pattern = "*lazygit" })
|
||||
picker.list.win:on("BufWritePost", function(_, ev)
|
||||
if self:is_visible(ev.file) then
|
||||
self:update()
|
||||
self:update({ force = true })
|
||||
end
|
||||
end)
|
||||
picker.list.win:on("DirChanged", function(_, ev)
|
||||
|
@ -357,9 +359,12 @@ function State:setup(opts, ctx)
|
|||
return opts
|
||||
end
|
||||
|
||||
---@param opts? {target?: boolean, on_done?: fun()}
|
||||
---@param opts? {target?: boolean, on_done?: fun(), force?: boolean}
|
||||
function State:update(opts)
|
||||
opts = opts or {}
|
||||
if opts.force then
|
||||
self.cache = {}
|
||||
end
|
||||
local picker = self:picker()
|
||||
if picker then
|
||||
if opts.target ~= false then
|
||||
|
@ -420,7 +425,7 @@ end
|
|||
---@type table<string, snacks.picker.Action.spec>
|
||||
M.actions = {
|
||||
explorer_update = function(picker)
|
||||
M.get_state(picker):update()
|
||||
M.get_state(picker):update({ force = true })
|
||||
end,
|
||||
explorer_up = function(picker)
|
||||
M.get_state(picker):up()
|
||||
|
@ -571,7 +576,7 @@ M.actions = {
|
|||
return
|
||||
end
|
||||
local what = #paths == 1 and vim.fn.fnamemodify(paths[1], ":p:~:.") or #paths .. " files"
|
||||
M.confirm("Delete " .. what .. "?", function(_, idx)
|
||||
M.confirm("Delete " .. what .. "?", function()
|
||||
for _, path in ipairs(paths) do
|
||||
local ok, err = pcall(vim.fn.delete, path, "rf")
|
||||
if not ok then
|
||||
|
@ -637,21 +642,25 @@ function M.explorer(opts, ctx)
|
|||
local tick = state.tick
|
||||
opts.notify = false
|
||||
local expanded = {} ---@type table<string, boolean>
|
||||
local use_cache = not state.all
|
||||
for _, dir in ipairs(opts.dirs or {}) do
|
||||
expanded[dir] = true
|
||||
use_cache = use_cache and state.cache[dir] ~= nil
|
||||
end
|
||||
|
||||
if not use_cache then
|
||||
state.cache = {}
|
||||
end
|
||||
-- vim.notify(table.concat(opts.dirs or {}, "\n"), "info")
|
||||
|
||||
---@param path string
|
||||
local function is_open(path)
|
||||
return state.all or expanded[path]
|
||||
end
|
||||
|
||||
local files = require("snacks.picker.source.files").files(opts, ctx)
|
||||
local git = Git.status(opts, ctx)
|
||||
|
||||
local dirs = {} ---@type table<string, snacks.picker.explorer.Item>
|
||||
local last = {} ---@type table<snacks.picker.finder.Item, snacks.picker.finder.Item>
|
||||
---@param item snacks.picker.explorer.Item
|
||||
local function add_git_status(item)
|
||||
item.status = (opts.git_status_open or not item.open) and git_tree_status[item.file or ""] or nil
|
||||
end
|
||||
|
||||
---@type snacks.picker.explorer.Item
|
||||
local root = {
|
||||
|
@ -662,15 +671,33 @@ function M.explorer(opts, ctx)
|
|||
sort = "",
|
||||
internal = true,
|
||||
}
|
||||
|
||||
if use_cache then
|
||||
local ret = { root } ---@type snacks.picker.explorer.Item[]
|
||||
for _, dir in ipairs(opts.dirs or {}) do
|
||||
for _, item in ipairs(state.cache[dir]) do
|
||||
item.open = is_open(item.file)
|
||||
add_git_status(item)
|
||||
table.insert(ret, item)
|
||||
end
|
||||
end
|
||||
if state.on_find then
|
||||
state.on_find()
|
||||
state.on_find = nil
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
local files = require("snacks.picker.source.files").files(opts, ctx)
|
||||
local git = Git.status(opts, ctx)
|
||||
|
||||
local dirs = {} ---@type table<string, snacks.picker.explorer.Item>
|
||||
local last = {} ---@type table<snacks.picker.finder.Item, snacks.picker.finder.Item>
|
||||
|
||||
local cwd = state.cwd
|
||||
dirs[cwd] = root
|
||||
state.git_status = {}
|
||||
|
||||
---@param item snacks.picker.explorer.Item
|
||||
local function add_git_status(item)
|
||||
item.status = (opts.git_status_open or not item.open) and git_tree_status[item.file or ""] or nil
|
||||
end
|
||||
|
||||
---@async
|
||||
return function(cb)
|
||||
if state.on_find then
|
||||
|
@ -685,6 +712,9 @@ function M.explorer(opts, ctx)
|
|||
dirname, basename = dirname or "", basename or item.file
|
||||
local parent = dirs[dirname] ~= item and dirs[dirname] or root
|
||||
|
||||
state.cache[dirname] = state.cache[dirname] or {}
|
||||
table.insert(state.cache[dirname], item)
|
||||
|
||||
-- hierarchical sorting
|
||||
if item.dir then
|
||||
item.sort = parent.sort .. "!" .. basename .. " "
|
||||
|
@ -707,6 +737,7 @@ function M.explorer(opts, ctx)
|
|||
-- add to picker
|
||||
cb(item)
|
||||
end
|
||||
-- ctx.async:sleep(1000)
|
||||
|
||||
-- get files and directories
|
||||
files(function(item)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue