mirror of
https://github.com/folke/snacks.nvim
synced 2025-08-05 03:08:13 +00:00
perf(picker): fixed some issues with closed pickers not always being garbage collected
This commit is contained in:
parent
b59f4ff477
commit
eebf44a34e
7 changed files with 82 additions and 24 deletions
|
@ -382,18 +382,23 @@ function M:close(opts)
|
|||
for w, win in pairs(self.wins) do
|
||||
if opts.wins == false then
|
||||
win.opts = self.win_opts[w]
|
||||
elseif win:valid() then
|
||||
win:close()
|
||||
else
|
||||
win:destroy()
|
||||
end
|
||||
end
|
||||
for _, win in pairs(self.box_wins) do
|
||||
win:close()
|
||||
win:destroy()
|
||||
end
|
||||
self.opts = nil
|
||||
self.root = nil
|
||||
self.wins = nil
|
||||
self.box_wins = nil
|
||||
self.win_opts = nil
|
||||
end
|
||||
|
||||
--- Check if layout is valid (visible)
|
||||
function M:valid()
|
||||
return self.root:valid()
|
||||
return not self.closed and self.root:valid()
|
||||
end
|
||||
|
||||
--- Check if the window has been used in the layout
|
||||
|
@ -402,6 +407,28 @@ function M:is_enabled(w)
|
|||
return not self:is_hidden(w) and self.wins[w].enabled
|
||||
end
|
||||
|
||||
function M:hide()
|
||||
for _, win in ipairs(self:get_wins()) do
|
||||
if win:valid() then
|
||||
vim.api.nvim_win_set_config(win.win, { hide = true })
|
||||
if win.backdrop and win.backdrop:valid() then
|
||||
vim.api.nvim_win_set_config(win.backdrop.win, { hide = true })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M:unhide()
|
||||
for _, win in ipairs(self:get_wins()) do
|
||||
if win:valid() then
|
||||
vim.api.nvim_win_set_config(win.win, { hide = false })
|
||||
if win.backdrop and win.backdrop:valid() then
|
||||
vim.api.nvim_win_set_config(win.backdrop.win, { hide = false })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Show the layout
|
||||
function M:show()
|
||||
if self:valid() then
|
||||
|
|
|
@ -13,7 +13,7 @@ local islist = vim.islist or vim.tbl_islist
|
|||
|
||||
---@param picker snacks.Picker
|
||||
function M.get(picker)
|
||||
local ref = Snacks.util.ref(picker)
|
||||
local ref = picker:ref()
|
||||
---@type table<string, snacks.win.Action>
|
||||
local ret = {}
|
||||
setmetatable(ret, {
|
||||
|
@ -23,11 +23,7 @@ function M.get(picker)
|
|||
if type(k) ~= "string" then
|
||||
return
|
||||
end
|
||||
local p = ref()
|
||||
if not p then
|
||||
return
|
||||
end
|
||||
t[k] = M.wrap(k, p, k) or false
|
||||
t[k] = M.wrap(k, ref, k) or false
|
||||
return rawget(t, k)
|
||||
end,
|
||||
})
|
||||
|
@ -35,16 +31,24 @@ function M.get(picker)
|
|||
end
|
||||
|
||||
---@param action snacks.picker.Action.spec
|
||||
---@param picker snacks.Picker
|
||||
---@param ref snacks.Picker.ref
|
||||
---@param name? string
|
||||
---@return snacks.win.Action?
|
||||
function M.wrap(action, picker, name)
|
||||
function M.wrap(action, ref, name)
|
||||
local picker = ref()
|
||||
if not picker then
|
||||
return
|
||||
end
|
||||
action = M.resolve(action, picker, name)
|
||||
action.name = name
|
||||
return {
|
||||
name = name,
|
||||
action = function()
|
||||
return action.action(picker, picker:current(), action)
|
||||
local p = ref()
|
||||
if not p then
|
||||
return
|
||||
end
|
||||
return action.action(p, p:current(), action)
|
||||
end,
|
||||
desc = action.desc,
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
---@field win snacks.win
|
||||
---@field totals string
|
||||
---@field picker snacks.Picker
|
||||
---@field _statuscolumn string
|
||||
---@field filter snacks.picker.Filter
|
||||
local M = {}
|
||||
M.__index = M
|
||||
|
@ -41,10 +40,12 @@ function M.new(picker)
|
|||
},
|
||||
}))
|
||||
|
||||
local ref = picker:ref()
|
||||
self.win:on(
|
||||
{ "TextChangedI", "TextChanged" },
|
||||
Snacks.util.throttle(function()
|
||||
if not self.win:valid() then
|
||||
local p = ref()
|
||||
if not p or not self.win:valid() then
|
||||
return
|
||||
end
|
||||
-- only one line
|
||||
|
@ -56,18 +57,23 @@ function M.new(picker)
|
|||
end
|
||||
vim.bo[self.win.buf].modified = false
|
||||
local pattern = self:get()
|
||||
if self.picker.opts.live then
|
||||
if p.opts.live then
|
||||
self.filter.search = pattern
|
||||
else
|
||||
self.filter.pattern = pattern
|
||||
end
|
||||
picker:match()
|
||||
p:match()
|
||||
end, { ms = picker.opts.live and 100 or 30 }),
|
||||
{ buf = true }
|
||||
)
|
||||
return self
|
||||
end
|
||||
|
||||
function M:close()
|
||||
self.win:destroy()
|
||||
self.picker = nil -- needed for garbage collection of the picker
|
||||
end
|
||||
|
||||
function M:statuscolumn()
|
||||
local parts = {} ---@type string[]
|
||||
local function add(str, hl)
|
||||
|
|
|
@ -132,9 +132,8 @@ function M:count()
|
|||
end
|
||||
|
||||
function M:close()
|
||||
self.win:close()
|
||||
self.items = {}
|
||||
self.topk:clear()
|
||||
-- nothing todo. Keep all items so actions can be performed on them,
|
||||
-- even when the picker closed
|
||||
end
|
||||
|
||||
function M:scrolloff()
|
||||
|
|
|
@ -4,6 +4,8 @@ local Finder = require("snacks.picker.core.finder")
|
|||
local uv = vim.uv or vim.loop
|
||||
Async.BUDGET = 10
|
||||
|
||||
---@alias snacks.Picker.ref (fun():snacks.Picker?)|{value?: snacks.Picker}
|
||||
|
||||
---@class snacks.Picker
|
||||
---@field opts snacks.picker.Config
|
||||
---@field finder snacks.picker.Finder
|
||||
|
@ -134,8 +136,12 @@ function M.new(opts)
|
|||
end)
|
||||
end)
|
||||
|
||||
local ref = self:ref()
|
||||
self._throttled_preview = Snacks.util.throttle(function()
|
||||
self._show_preview(self)
|
||||
local this = ref()
|
||||
if this then
|
||||
this:_show_preview()
|
||||
end
|
||||
end, { ms = 60, name = "preview" })
|
||||
|
||||
self:find()
|
||||
|
@ -412,6 +418,11 @@ function M:empty()
|
|||
return self:count() == 0
|
||||
end
|
||||
|
||||
---@return snacks.Picker.ref
|
||||
function M:ref()
|
||||
return Snacks.util.ref(self)
|
||||
end
|
||||
|
||||
--- Close the picker
|
||||
function M:close()
|
||||
vim.cmd.stopinsert()
|
||||
|
@ -428,15 +439,14 @@ function M:close()
|
|||
if is_picker_win and vim.api.nvim_win_is_valid(self.main) then
|
||||
vim.api.nvim_set_current_win(self.main)
|
||||
end
|
||||
self.preview.win:close()
|
||||
self.layout:close()
|
||||
self.updater:stop()
|
||||
M._active[self] = nil
|
||||
vim.schedule(function()
|
||||
self.list:clear()
|
||||
self.finder.items = {}
|
||||
self.matcher:abort()
|
||||
self.finder:abort()
|
||||
self.input:close()
|
||||
self.preview:close()
|
||||
end)
|
||||
end
|
||||
|
||||
|
|
|
@ -80,6 +80,13 @@ function M.new(opts, main)
|
|||
return self
|
||||
end
|
||||
|
||||
function M:close()
|
||||
self.win:destroy()
|
||||
self.item = nil
|
||||
self.win_opts = { main = {}, layout = {}, win = {} }
|
||||
self.state = {}
|
||||
end
|
||||
|
||||
---@param main? number
|
||||
function M:update(main)
|
||||
self.main = main
|
||||
|
|
|
@ -486,6 +486,11 @@ function M:scroll(up)
|
|||
end)
|
||||
end
|
||||
|
||||
function M:destroy()
|
||||
self:close()
|
||||
self.events = {}
|
||||
end
|
||||
|
||||
---@param opts? { buf: boolean }
|
||||
function M:close(opts)
|
||||
opts = opts or {}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue