fix(async): make asyncs abortable

This commit is contained in:
Folke Lemaitre 2024-06-30 13:35:11 +02:00
parent c882227f1f
commit 1fad61712b
No known key found for this signature in database
GPG Key ID: 41F8B1FBACAE2040
7 changed files with 29 additions and 8 deletions

View File

@ -79,7 +79,7 @@ end
function Async:suspend(yield) function Async:suspend(yield)
self._suspended = true self._suspended = true
if coroutine.running() == self._co and yield ~= false then if coroutine.running() == self._co and yield ~= false then
coroutine.yield() M.yield()
end end
end end
@ -132,12 +132,25 @@ function Async:step()
return self:running() return self:running()
end end
function M.abort()
for _, async in ipairs(M._active) do
coroutine.resume(async._co, "abort")
end
end
function M.yield()
if coroutine.yield() == "abort" then
error("aborted", 2)
end
end
function M.step() function M.step()
local start = vim.uv.hrtime() local start = vim.uv.hrtime()
for _ = 1, #M._active do for _ = 1, #M._active do
if vim.uv.hrtime() - start > M.BUDGET * 1e6 then if Util.exiting() or vim.uv.hrtime() - start > M.BUDGET * 1e6 then
break break
end end
local state = table.remove(M._active, 1) local state = table.remove(M._active, 1)
if state:step() then if state:step() then
if state._suspended then if state._suspended then
@ -153,7 +166,7 @@ function M.step()
end end
-- M.debug() -- M.debug()
if #M._active == 0 then if #M._active == 0 or Util.exiting() then
return M._executor:stop() return M._executor:stop()
end end
end end
@ -183,7 +196,7 @@ function M.add(async)
end end
function M._run() function M._run()
if not M._executor:is_active() then if not Util.exiting() and not M._executor:is_active() then
M._executor:start(vim.schedule_wrap(M.step)) M._executor:start(vim.schedule_wrap(M.step))
end end
end end

View File

@ -29,6 +29,10 @@ function M.track(data, time)
end end
end end
function M.exiting()
return vim.v.exiting ~= vim.NIL
end
---@generic T ---@generic T
---@param list T[] ---@param list T[]
---@param fn fun(v: T):boolean? ---@param fn fun(v: T):boolean?

View File

@ -93,7 +93,7 @@ function Process:_run()
end) end)
self:suspend() self:suspend()
while not (self.handle:is_closing() and stdout:is_closing() and stderr:is_closing()) do while not (self.handle:is_closing() and stdout:is_closing() and stderr:is_closing()) do
coroutine.yield() Async.yield()
end end
else else
self.data = "Failed to spawn process " .. self.cmd .. " " .. vim.inspect(self.opts) self.data = "Failed to spawn process " .. self.cmd .. " " .. vim.inspect(self.opts)

View File

@ -252,7 +252,7 @@ end
---@param fn fun(self?) ---@param fn fun(self?)
---@param desc? string ---@param desc? string
---@param mode? string[] ---@param mode? string[]
function M:on_key(key, fn, desc,mode) function M:on_key(key, fn, desc, mode)
vim.keymap.set(mode or "n", key, function() vim.keymap.set(mode or "n", key, function()
fn(self) fn(self)
end, { end, {
@ -295,6 +295,7 @@ function M:close(opts)
vim.diagnostic.reset(Config.ns, buf) vim.diagnostic.reset(Config.ns, buf)
vim.api.nvim_buf_delete(buf, { force = true }) vim.api.nvim_buf_delete(buf, { force = true })
end end
vim.cmd.redraw()
end) end)
end end

View File

@ -83,6 +83,7 @@ function M.create()
vim.keymap.set("n", ViewConfig.keys.abort, function() vim.keymap.set("n", ViewConfig.keys.abort, function()
require("lazy.manage.process").abort() require("lazy.manage.process").abort()
require("lazy.async").abort()
return ViewConfig.keys.abort return ViewConfig.keys.abort
end, { silent = true, buffer = self.buf, expr = true }) end, { silent = true, buffer = self.buf, expr = true })

View File

@ -1,3 +1,4 @@
local Async = require("lazy.async")
local Runner = require("lazy.manage.runner") local Runner = require("lazy.manage.runner")
describe("runner", function() describe("runner", function()
@ -33,7 +34,7 @@ describe("runner", function()
---@async ---@async
---@param task LazyTask ---@param task LazyTask
run = function(task) run = function(task)
coroutine.yield() Async.yield()
table.insert(runs, { plugin = task.plugin.name, task = task.name }) table.insert(runs, { plugin = task.plugin.name, task = task.name })
end, end,
} }

View File

@ -1,4 +1,5 @@
--# selene:allow(incorrect_standard_library_use) --# selene:allow(incorrect_standard_library_use)
local Async = require("lazy.async")
local Task = require("lazy.manage.task") local Task = require("lazy.manage.task")
describe("task", function() describe("task", function()
@ -42,7 +43,7 @@ describe("task", function()
local running = true local running = true
---@async ---@async
local task = Task.new(plugin, "test", function() local task = Task.new(plugin, "test", function()
coroutine.yield() Async.yield()
running = false running = false
end, opts) end, opts)
assert(task:running()) assert(task:running())