perf(picker): small optims for abort

This commit is contained in:
Folke Lemaitre 2025-01-21 12:16:14 +01:00
parent d283d9e182
commit 317a2093ea
No known key found for this signature in database
GPG key ID: 41F8B1FBACAE2040
7 changed files with 30 additions and 13 deletions

View file

@ -5,7 +5,6 @@ local Async = require("snacks.picker.util.async")
---@field task snacks.picker.Async ---@field task snacks.picker.Async
---@field items snacks.picker.finder.Item[] ---@field items snacks.picker.finder.Item[]
---@field filter? snacks.picker.Filter ---@field filter? snacks.picker.Filter
---@field has_scores? boolean
local M = {} local M = {}
M.__index = M M.__index = M
@ -46,7 +45,6 @@ function M:run(picker)
local default_score = require("snacks.picker.core.matcher").DEFAULT_SCORE local default_score = require("snacks.picker.core.matcher").DEFAULT_SCORE
self.task:abort() self.task:abort()
self.items = {} self.items = {}
self.has_scores = false
local yield ---@type fun() local yield ---@type fun()
self.filter = picker.input.filter:clone({ trim = true }) self.filter = picker.input.filter:clone({ trim = true })
local finder = self._find(picker.opts, self.filter) local finder = self._find(picker.opts, self.filter)
@ -56,7 +54,6 @@ function M:run(picker)
local function add(item) local function add(item)
item.idx, item.score = #self.items + 1, default_score item.idx, item.score = #self.items + 1, default_score
self.items[item.idx] = item self.items[item.idx] = item
self.has_scores = self.has_scores or item.score_add ~= nil
end end
-- PERF: if finder is a table, we can skip the async part -- PERF: if finder is a table, we can skip the async part
@ -89,8 +86,10 @@ function M:run(picker)
end, async) end, async)
end):on("done", function() end):on("done", function()
collectgarbage("restart") collectgarbage("restart")
picker.matcher.task:resume() if not self.task:aborted() then
picker:update() picker.matcher.task:resume()
picker:update()
end
end) end)
end end

View file

@ -470,10 +470,11 @@ function M:close()
end end
self.layout:close() self.layout:close()
self.updater:stop() self.updater:stop()
self.finder:abort()
self.matcher:abort()
M._active[self] = nil M._active[self] = nil
vim.schedule(function() vim.schedule(function()
self.matcher:abort() -- order matters!
self.finder:abort()
self.input:close() self.input:close()
self.preview:close() self.preview:close()
end) end)

View file

@ -108,7 +108,7 @@ function M.files(opts, filter)
return require("snacks.picker.source.proc").proc(vim.tbl_deep_extend("force", { return require("snacks.picker.source.proc").proc(vim.tbl_deep_extend("force", {
cmd = cmd, cmd = cmd,
args = args, args = args,
notify = false, notify = not opts.live,
---@param item snacks.picker.finder.Item ---@param item snacks.picker.finder.Item
transform = function(item) transform = function(item)
item.cwd = cwd item.cwd = cwd

View file

@ -108,7 +108,7 @@ function M.grep(opts, filter)
local cwd = not absolute and vim.fs.normalize(opts and opts.cwd or uv.cwd() or ".") or nil local cwd = not absolute and vim.fs.normalize(opts and opts.cwd or uv.cwd() or ".") or nil
local cmd, args = get_cmd(opts, filter) local cmd, args = get_cmd(opts, filter)
return require("snacks.picker.source.proc").proc(vim.tbl_deep_extend("force", { return require("snacks.picker.source.proc").proc(vim.tbl_deep_extend("force", {
notify = false, notify = not opts.live,
cmd = cmd, cmd = cmd,
args = args, args = args,
---@param item snacks.picker.finder.Item ---@param item snacks.picker.finder.Item

View file

@ -31,6 +31,7 @@ function M.proc(opts)
end end
end end
end end
local aborted = false local aborted = false
local stdout = assert(uv.new_pipe()) local stdout = assert(uv.new_pipe())
opts = vim.tbl_deep_extend("force", {}, opts or {}, { opts = vim.tbl_deep_extend("force", {}, opts or {}, {
@ -44,7 +45,7 @@ function M.proc(opts)
if not aborted and code ~= 0 and opts.notify ~= false then if not aborted and code ~= 0 and opts.notify ~= false then
local full = { opts.cmd or "" } local full = { opts.cmd or "" }
vim.list_extend(full, opts.args or {}) vim.list_extend(full, opts.args or {})
return Snacks.notify.error(("Command failed:\n- cmd: `%s`"):format(table.concat(full, " "))) Snacks.notify.error(("Command failed:\n- cmd: `%s`"):format(table.concat(full, " ")))
end end
stdout:close() stdout:close()
handle:close() handle:close()
@ -55,9 +56,12 @@ function M.proc(opts)
end end
local prev ---@type string? local prev ---@type string?
local queue = require("snacks.picker.util.queue").new()
self:on("abort", function() self:on("abort", function()
aborted = true aborted = true
queue:clear()
cb = function() end
if not handle:is_closing() then if not handle:is_closing() then
handle:kill("sigterm") handle:kill("sigterm")
vim.defer_fn(function() vim.defer_fn(function()
@ -97,9 +101,10 @@ function M.proc(opts)
end end
end end
local queue = require("snacks.picker.util.queue").new()
stdout:read_start(function(err, data) stdout:read_start(function(err, data)
if aborted then
return
end
assert(not err, err) assert(not err, err)
if M.USE_QUEUE then if M.USE_QUEUE then
queue:push(data) queue:push(data)

View file

@ -58,9 +58,17 @@ function Async:init(fn)
return M.add(self) return M.add(self)
end end
function Async:aborted()
return self._aborted
end
function Async:_done() function Async:_done()
if self._co == nil then
return
end
self:_emit("done") self:_emit("done")
self._fn = nil self._fn = nil
M._threads[self._co] = nil
self._co = nil self._co = nil
self._on = {} self._on = {}
end end

View file

@ -9,7 +9,7 @@ M.__index = M
function M.new() function M.new()
local self = setmetatable({}, M) local self = setmetatable({}, M)
self.first, self.last, self.queue = 0, -1, {} self:clear()
return self return self
end end
@ -26,6 +26,10 @@ function M:empty()
return self:size() == 0 return self:size() == 0
end end
function M:clear()
self.first, self.last, self.queue = 0, -1, {}
end
function M:pop() function M:pop()
if self:empty() then if self:empty() then
return return