diff --git a/lua/lazy/async.lua b/lua/lazy/async.lua index 9f39a5c..6ad2d6a 100644 --- a/lua/lazy/async.lua +++ b/lua/lazy/async.lua @@ -1,78 +1,122 @@ ----@class AsyncOpts ----@field on_done? fun() ----@field on_error? fun(err:string) ----@field on_yield? fun(res:any) - local M = {} ---@type Async[] M._queue = {} M._executor = assert(vim.loop.new_check()) M._running = false ----@type Async -M.current = nil + +---@type table +M._threads = setmetatable({}, { __mode = "k" }) + +---@alias AsyncEvent "done" | "error" | "yield" | "ok" ---@class Async ----@field co thread ----@field opts AsyncOpts ----@field sleeping? boolean +---@field _co thread +---@field _fn fun() +---@field _suspended? boolean +---@field _on table local Async = {} ---@param fn async fun() ----@param opts? AsyncOpts ---@return Async -function Async.new(fn, opts) +function Async.new(fn) local self = setmetatable({}, { __index = Async }) - self.co = coroutine.create(fn) - self.opts = opts or {} + return self:init(fn) +end + +---@param fn async fun() +---@return Async +function Async:init(fn) + self._fn = fn + self._on = {} + self._co = coroutine.create(function() + local ok, err = pcall(self._fn) + if not ok then + self:_emit("error", err) + end + self:_emit("done") + end) + M._threads[self._co] = self + return M.add(self) +end + +function Async:restart() + assert(not self:running(), "Cannot restart a running async") + self:init(self._fn) +end + +---@param event AsyncEvent +---@param cb async fun(res:any, async:Async) +function Async:on(event, cb) + self._on[event] = self._on[event] or {} + table.insert(self._on[event], cb) return self end -function Async:running() - return coroutine.status(self.co) ~= "dead" +---@private +---@param event AsyncEvent +---@param res any +function Async:_emit(event, res) + for _, cb in ipairs(self._on[event] or {}) do + cb(res, self) + end end +function Async:running() + return coroutine.status(self._co) ~= "dead" +end + +---@async function Async:sleep(ms) - self.sleeping = true + self._suspended = true vim.defer_fn(function() - self.sleeping = false + self._suspended = false end, ms) coroutine.yield() end +---@async function Async:suspend() - self.sleeping = true + self._suspended = true + if coroutine.running() == self._co then + coroutine.yield() + end end function Async:resume() - self.sleeping = false + self._suspended = false +end + +function Async:wait() + local async = M.running() + if coroutine.running() == self._co then + error("Cannot wait on self") + end + + while self:running() do + if async then + coroutine.yield() + else + vim.wait(10) + end + end + return self end function Async:step() - if self.sleeping then + if self._suspended then return true end - local status = coroutine.status(self.co) + local status = coroutine.status(self._co) if status == "suspended" then - M.current = self - local ok, res = coroutine.resume(self.co) - M.current = nil + local ok, res = coroutine.resume(self._co) if not ok then - if self.opts.on_error then - self.opts.on_error(tostring(res)) - end + error(res) elseif res then - if self.opts.on_yield then - self.opts.on_yield(res) - end + self:_emit("yield", res) end end - if self:running() then - return true - end - if self.opts.on_done then - self.opts.on_done() - end + return self:running() end function M.step() @@ -107,32 +151,24 @@ function M.add(async) return async end ----@param fn async fun() ----@param opts? AsyncOpts -function M.run(fn, opts) - return M.add(Async.new(fn, opts)) -end - ----@generic T: async fun() ----@param fn T ----@param opts? AsyncOpts ----@return T -function M.wrap(fn, opts) - return function(...) - local args = { ... } - ---@async - local wrapped = function() - return fn(unpack(args)) - end - return M.run(wrapped, opts) +function M.running() + local co = coroutine.running() + if co then + local async = M._threads[co] + assert(async, "In coroutine without async context") + return async end end ---@async ---@param ms number function M.sleep(ms) - assert(M.current, "Not in an async context") - M.current:sleep(ms) + local async = M.running() + assert(async, "Not in an async context") + async:sleep(ms) end +M.Async = Async +M.new = Async.new + return M diff --git a/lua/lazy/manage/init.lua b/lua/lazy/manage/init.lua index 55c5076..ac9ba14 100644 --- a/lua/lazy/manage/init.lua +++ b/lua/lazy/manage/init.lua @@ -236,7 +236,7 @@ function M.clear(plugins) if plugin._.tasks then ---@param task LazyTask plugin._.tasks = vim.tbl_filter(function(task) - return task:is_running() or task:has_errors() + return task:running() or task:has_errors() end, plugin._.tasks) end end diff --git a/lua/lazy/manage/process.lua b/lua/lazy/manage/process.lua index 03becf2..f29d978 100644 --- a/lua/lazy/manage/process.lua +++ b/lua/lazy/manage/process.lua @@ -1,67 +1,133 @@ +local Async = require("lazy.async") local Config = require("lazy.core.config") -local M = {} - ----@type table -M.running = {} - -M.signals = { - "HUP", - "INT", - "QUIT", - "ILL", - "TRAP", - "ABRT", - "BUS", - "FPE", - "KILL", - "USR1", - "SEGV", - "USR2", - "PIPE", - "ALRM", - "TERM", - "CHLD", - "CONT", - "STOP", - "TSTP", - "TTIN", - "TTOU", - "URG", - "XCPU", - "XFSZ", - "VTALRM", - "PROF", - "WINCH", - "IO", - "PWR", - "EMT", - "SYS", - "INFO", -} - ---@diagnostic disable-next-line: no-unknown local uv = vim.uv ---@class ProcessOpts ---@field args string[] ---@field cwd? string ----@field on_line? fun(string) +---@field on_line? fun(line:string) ---@field on_exit? fun(ok:boolean, output:string) ----@field on_data? fun(string) +---@field on_data? fun(data:string, is_stderr?:boolean) ---@field timeout? number ---@field env? table ----@param opts? ProcessOpts ----@param cmd string -function M.spawn(cmd, opts) - opts = opts or {} - opts.timeout = opts.timeout or (Config.options.git and Config.options.git.timeout * 1000) +local M = {} +---@type table +M.running = setmetatable({}, { __mode = "k" }) + +---@class LazyProcess: Async +---@field handle? uv_process_t +---@field pid? number +---@field cmd string +---@field opts ProcessOpts +---@field timeout? uv_timer_t +---@field timedout? boolean +---@field data string +---@field check? uv_check_t +---@field code? number +---@field signal? number +local Process = setmetatable({}, { __index = Async.Async }) + +---@param cmd string|string[] +---@param opts? ProcessOpts +function Process.new(cmd, opts) + local self = setmetatable({}, { __index = Process }) + ---@async + Process.init(self, function() + self:_run() + end) + opts = opts or {} + opts.args = opts.args or {} + if type(cmd) == "table" then + self.cmd = table.remove(cmd, 1) + vim.list_extend(opts.args, cmd) + else + self.cmd = cmd + end + opts.timeout = opts.timeout or (Config.options.git and Config.options.git.timeout * 1000) + -- make sure the cwd is valid + if not opts.cwd and type(uv.cwd()) ~= "string" then + opts.cwd = uv.os_homedir() + end + opts.on_line = opts.on_line and vim.schedule_wrap(opts.on_line) or nil + opts.on_data = opts.on_data and vim.schedule_wrap(opts.on_data) or nil + self.data = "" + self.opts = opts + self.code = 1 + self.signal = 0 + return self +end + +---@async +function Process:_run() + self:guard() + local stdout = assert(uv.new_pipe()) + local stderr = assert(uv.new_pipe()) + self.handle = uv.spawn(self.cmd, { + stdio = { nil, stdout, stderr }, + args = self.opts.args, + cwd = self.opts.cwd, + env = self:env(), + }, function(code, signal) + self.code = code + self.signal = signal + if self.timeout then + self.timeout:stop() + end + self.handle:close() + stdout:close() + stderr:close() + self:resume() + end) + + if self.handle then + M.running[self.handle] = self + stdout:read_start(function(err, data) + self:on_data(err, data) + end) + stderr:read_start(function(err, data) + self:on_data(err, data, true) + end) + self:suspend() + while not (self.handle:is_closing() and stdout:is_closing() and stderr:is_closing()) do + coroutine.yield() + end + else + self.data = "Failed to spawn process " .. self.cmd .. " " .. vim.inspect(self.opts) + end + self:on_exit() +end + +function Process:on_exit() + self.data = self.data:gsub("[^\r\n]+\r", "") + if self.timedout then + self.data = self.data .. "\n" .. "Process was killed because it reached the timeout" + elseif self.signal ~= 0 then + self.data = self.data .. "\n" .. "Process was killed with SIG" .. M.signals[self.signal]:upper() + end + if self.opts.on_exit then + self.opts.on_exit(self.code == 0 and self.signal == 0, self.data) + end +end + +function Process:guard() + if self.opts.timeout then + self.timeout = assert(uv.new_timer()) + self.timeout:start(self.opts.timeout, 0, function() + self.timedout = true + self:kill() + end) + end +end + +function Process:env() ---@type table local env = vim.tbl_extend("force", { GIT_SSH_COMMAND = "ssh -oBatchMode=yes", - }, uv.os_environ(), opts.env or {}) + }, uv.os_environ(), self.opts.env or {}) env.GIT_DIR = nil env.GIT_WORK_TREE = nil env.GIT_TERMINAL_PROMPT = "0" @@ -72,147 +138,105 @@ function M.spawn(cmd, opts) for k, v in pairs(env) do env_flat[#env_flat + 1] = k .. "=" .. v end - - local stdout = assert(uv.new_pipe()) - local stderr = assert(uv.new_pipe()) - - local output = "" - ---@type uv_process_t? - local handle = nil - - ---@type uv_timer_t - local timeout - local killed = false - if opts.timeout then - timeout = assert(uv.new_timer()) - timeout:start(opts.timeout, 0, function() - if M.kill(handle) then - killed = true - end - end) - end - - -- make sure the cwd is valid - if not opts.cwd and type(uv.cwd()) ~= "string" then - opts.cwd = uv.os_homedir() - end - - handle = uv.spawn(cmd, { - stdio = { nil, stdout, stderr }, - args = opts.args, - cwd = opts.cwd, - env = env_flat, - }, function(exit_code, signal) - ---@cast handle uv_process_t - M.running[handle] = nil - if timeout then - timeout:stop() - timeout:close() - end - handle:close() - stdout:close() - stderr:close() - local check = assert(uv.new_check()) - check:start(function() - if not stdout:is_closing() or not stderr:is_closing() then - return - end - check:stop() - if opts.on_exit then - output = output:gsub("[^\r\n]+\r", "") - if killed then - output = output .. "\n" .. "Process was killed because it reached the timeout" - elseif signal ~= 0 then - output = output .. "\n" .. "Process was killed with SIG" .. M.signals[signal] - end - - vim.schedule(function() - opts.on_exit(exit_code == 0 and signal == 0, output) - end) - end - end) - end) - - if not handle then - if opts.on_exit then - opts.on_exit(false, "Failed to spawn process " .. cmd .. " " .. vim.inspect(opts)) - end - return - end - M.running[handle] = true - - ---@param data? string - local function on_output(err, data) - assert(not err, err) - - if data then - if opts.on_data then - vim.schedule(function() - opts.on_data(data) - end) - end - output = output .. data:gsub("\r\n", "\n") - local lines = vim.split(vim.trim(output:gsub("\r$", "")):gsub("[^\n\r]+\r", ""), "\n") - - if opts.on_line then - vim.schedule(function() - opts.on_line(lines[#lines]) - end) - end - end - end - - uv.read_start(stdout, on_output) - uv.read_start(stderr, on_output) - - return handle + return env_flat end -function M.kill(handle) - if handle and not handle:is_closing() then - M.running[handle] = nil - uv.process_kill(handle, "sigint") - return true +---@param signals uv.aliases.signals|uv.aliases.signals[]|nil +function Process:kill(signals) + if not self.handle or self.handle:is_closing() then + return end + signals = signals or { "sigterm", "sigkill" } + signals = type(signals) == "table" and signals or { signals } + ---@cast signals uv.aliases.signals[] + local timer = assert(uv.new_timer()) + timer:start(0, 1000, function() + if self.handle and not self.handle:is_closing() and #signals > 0 then + self.handle:kill(table.remove(signals, 1)) + else + timer:stop() + end + end) +end + +---@param err? string +---@param data? string +---@param is_stderr? boolean +function Process:on_data(err, data, is_stderr) + assert(not err, err) + if not data then + return + end + + if self.opts.on_data then + self.opts.on_data(data, is_stderr) + end + self.data = self.data .. data:gsub("\r\n", "\n") + local lines = vim.split(vim.trim(self.data:gsub("\r$", "")):gsub("[^\n\r]+\r", ""), "\n") + + if self.opts.on_line then + self.opts.on_line(lines[#lines]) + end +end + +M.signals = { + "hup", + "int", + "quit", + "ill", + "trap", + "abrt", + "bus", + "fpe", + "kill", + "usr1", + "segv", + "usr2", + "pipe", + "alrm", + "term", + "chld", + "cont", + "stop", + "tstp", + "ttin", + "ttou", + "urg", + "xcpu", + "xfsz", + "vtalrm", + "prof", + "winch", + "io", + "pwr", + "emt", + "sys", + "info", +} + +---@param cmd string|string[] +---@param opts? ProcessOpts +function M.spawn(cmd, opts) + return Process.new(cmd, opts) end function M.abort() - for handle in pairs(M.running) do - M.kill(handle) + for _, proc in pairs(M.running) do + proc:kill() end end ----@param cmd string[] ----@param opts? {cwd:string, env:table} +---@async +---@param cmd string|string[] +---@param opts? ProcessOpts function M.exec(cmd, opts) opts = opts or {} - ---@type string[] - local lines - local job = vim.fn.jobstart(cmd, { - cwd = opts.cwd, - pty = false, - env = opts.env, - stdout_buffered = true, - on_stdout = function(_, _lines) - lines = _lines - end, - }) - - if job <= 0 then - error("Failed to start job: " .. vim.inspect(cmd)) + local proc = M.spawn(cmd, opts) + proc:wait() + if proc.code ~= 0 then + error("Process failed with code " .. proc.code) end - - local Async = require("lazy.async") - local async = Async.current - if async then - while vim.fn.jobwait({ job }, 0)[1] == -1 do - async:sleep(10) - end - else - vim.fn.jobwait({ job }) - end - - return lines + return vim.split(proc.data, "\n") end return M diff --git a/lua/lazy/manage/runner.lua b/lua/lazy/manage/runner.lua index 74d6254..c5f5c75 100644 --- a/lua/lazy/manage/runner.lua +++ b/lua/lazy/manage/runner.lua @@ -16,7 +16,6 @@ local Task = require("lazy.manage.task") ---@class Runner ---@field _plugins table ---@field _pipeline PipelineStep[] ----@field _on_done fun()[] ---@field _opts RunnerOpts ---@field _running? Async local Runner = {} @@ -38,7 +37,6 @@ function Runner.new(opts) for _, plugin in ipairs(pp) do self._plugins[plugin.name] = plugin end - self._on_done = {} ---@param step string|(TaskOptions|{[1]:string}) self._pipeline = vim.tbl_map(function(step) @@ -61,15 +59,9 @@ end function Runner:start() ---@async - self._running = Async.run(function() + self._running = Async.new(function() self:_start() - end, { - on_done = function() - for _, cb in ipairs(self._on_done) do - cb() - end - end, - }) + end) end ---@async @@ -97,7 +89,7 @@ function Runner:_start() for _, name in ipairs(names) do state[name] = state[name] or { step = 0 } local s = state[name] - local is_running = s.task and s.task:is_running() + local is_running = s.task and s.task:running() local step = self._pipeline[s.step] if is_running then @@ -185,14 +177,10 @@ function Runner:wait(cb) end return self end - if cb then - table.insert(self._on_done, cb) + self._running:on("done", cb) else - -- sync wait - while self:is_running() do - vim.wait(10) - end + self._running:wait() end return self end diff --git a/lua/lazy/manage/task/init.lua b/lua/lazy/manage/task/init.lua index 989f362..1470379 100644 --- a/lua/lazy/manage/task/init.lua +++ b/lua/lazy/manage/task/init.lua @@ -15,16 +15,15 @@ local colors = Config.options.headless.colors ---@field msg string ---@field level? number ----@class LazyTask +---@class LazyTask: Async ---@field plugin LazyPlugin ---@field name string ---@field private _log LazyMsg[] ----@field private _started? number +---@field private _started number ---@field private _ended? number ---@field private _opts TaskOptions ----@field private _running Async ---@field private _level number -local Task = {} +local Task = setmetatable({}, { __index = Async.Async }) ---@class TaskOptions: {[string]:any} ---@field on_done? fun(task:LazyTask) @@ -35,17 +34,21 @@ local Task = {} ---@param task LazyTaskFn function Task.new(plugin, name, task, opts) local self = setmetatable({}, { __index = Task }) + ---@async + Task.init(self, function() + self:_run(task) + end) + self:set_level() self._opts = opts or {} self._log = {} - self:set_level() self.plugin = plugin self.name = name + self._started = vim.uv.hrtime() ---@param other LazyTask plugin._.tasks = vim.tbl_filter(function(other) - return other.name ~= name or other:is_running() + return other.name ~= name or other:running() end, plugin._.tasks or {}) table.insert(plugin._.tasks, self) - self:_start(task) return self end @@ -75,10 +78,6 @@ function Task:status() return msg ~= "" and msg or nil end -function Task:is_running() - return self._ended == nil -end - function Task:has_errors() return self._level >= vim.log.levels.ERROR end @@ -92,31 +91,24 @@ function Task:set_level(level) self._level = level or vim.log.levels.TRACE end ----@private +---@async ---@param task LazyTaskFn -function Task:_start(task) - assert(not self._started, "task already started") - assert(not self._ended, "task already done") - +function Task:_run(task) if Config.headless() and Config.options.headless.task then self:log("Running task " .. self.name, vim.log.levels.INFO) end - self._started = vim.uv.hrtime() - ---@async - self._running = Async.run(function() - task(self, self._opts) - end, { - on_done = function() + self + :on("done", function() self:_done() - end, - on_error = function(err) + end) + :on("error", function(err) self:error(err) - end, - on_yield = function(res) - self:log(res) - end, - }) + end) + :on("yield", function(msg) + self:log(msg) + end) + task(self, self._opts) end ---@param msg string|string[] @@ -163,13 +155,6 @@ end ---@private function Task:_done() - assert(self._started, "task not started") - assert(not self._ended, "task already done") - - if self._running and self._running:running() then - return - end - if Config.headless() and Config.options.headless.task then local ms = math.floor(self:time() + 0.5) self:log("Finished task " .. self.name .. " in " .. ms .. "ms", vim.log.levels.INFO) @@ -186,13 +171,7 @@ function Task:_done() end function Task:time() - if not self._started then - return 0 - end - if not self._ended then - return (vim.uv.hrtime() - self._started) / 1e6 - end - return (self._ended - self._started) / 1e6 + return ((self._ended or vim.uv.hrtime()) - self._started) / 1e6 end ---@async @@ -201,7 +180,6 @@ end function Task:spawn(cmd, opts) opts = opts or {} local on_line = opts.on_line - local on_exit = opts.on_exit local headless = Config.headless() and Config.options.headless.process @@ -214,35 +192,28 @@ function Task:spawn(cmd, opts) end end - self._running:suspend() - - local running = true - local ret = { ok = true, output = "" } - ---@param output string - function opts.on_exit(ok, output) - if not headless then - self:log(vim.trim(output), ok and vim.log.levels.DEBUG or vim.log.levels.ERROR) - end - ret = { ok = ok, output = output } - running = false - self._running:resume() - end - if headless then opts.on_data = function(data) -- prefix with plugin name - local prefix = self:prefix() - io.write(Terminal.prefix(data, prefix)) + io.write(Terminal.prefix(data, self:prefix())) end end - Process.spawn(cmd, opts) - coroutine.yield() - assert(not running, "process still running?") - if on_exit then - pcall(on_exit, ret.ok, ret.output) + + local proc = Process.spawn(cmd, opts) + proc:wait() + + local ok = proc.code == 0 and proc.signal == 0 + if not headless then + local msg = vim.trim(proc.data) + if #msg > 0 then + self:log(vim.trim(proc.data), ok and vim.log.levels.DEBUG or vim.log.levels.ERROR) + end end - coroutine.yield() - return ret.ok + + if opts.on_exit then + pcall(opts.on_exit, ok, proc.data) + end + return ok end function Task:prefix() @@ -253,10 +224,4 @@ function Task:prefix() or plugin .. " " .. task .. " | " end -function Task:wait() - while self:is_running() do - vim.wait(10) - end -end - return Task diff --git a/lua/lazy/util.lua b/lua/lazy/util.lua index 1c3cee3..9f1088d 100644 --- a/lua/lazy/util.lua +++ b/lua/lazy/util.lua @@ -76,6 +76,13 @@ function M.throttle(ms, fn) local timer = vim.uv.new_timer() local pending = false + ---@type Async + local async + + local function running() + return async and async:running() + end + return function() if timer:is_active() then pending = true @@ -85,7 +92,10 @@ function M.throttle(ms, fn) 0, ms, vim.schedule_wrap(function() - fn() + if running() then + return + end + async = require("lazy.async").new(fn) if pending then pending = false else diff --git a/lua/lazy/view/render.lua b/lua/lazy/view/render.lua index 6d0e758..640e9b0 100644 --- a/lua/lazy/view/render.lua +++ b/lua/lazy/view/render.lua @@ -51,7 +51,7 @@ function M:update() if plugin._.tasks then for _, task in ipairs(plugin._.tasks) do self.progress.total = self.progress.total + 1 - if not task:is_running() then + if not task:running() then self.progress.done = self.progress.done + 1 end end @@ -356,7 +356,7 @@ end function M:diagnostics(plugin) local skip = false for _, task in ipairs(plugin._.tasks or {}) do - if task:is_running() then + if task:running() then self:diagnostic({ severity = vim.diagnostic.severity.WARN, message = task.name .. (task:status() and (": " .. task:status()) or ""), diff --git a/lua/lazy/view/sections.lua b/lua/lazy/view/sections.lua index c9fd9a7..c1681a8 100644 --- a/lua/lazy/view/sections.lua +++ b/lua/lazy/view/sections.lua @@ -28,7 +28,7 @@ return { return true end return has_task(plugin, function(task) - return task:is_running() + return task:running() end) end, title = "Working", diff --git a/tests/manage/process_spec.lua b/tests/manage/process_spec.lua new file mode 100644 index 0000000..0fbbe89 --- /dev/null +++ b/tests/manage/process_spec.lua @@ -0,0 +1,20 @@ +---@module 'luassert' +local Async = require("lazy.async") +local Process = require("lazy.manage.process") + +describe("process", function() + it("runs sync", function() + local lines = Process.exec({ "echo", "-n", "hello" }) + assert.are.same({ "hello" }, lines) + end) + + it("runs sync from async context", function() + local lines ---@type string[] + local async = Async.new(function() + lines = Process.exec({ "echo", "-n", "hello" }) + end) + async:wait() + + assert.are.same({ "hello" }, lines) + end) +end) diff --git a/tests/manage/task_spec.lua b/tests/manage/task_spec.lua index 7df638a..e161fa2 100644 --- a/tests/manage/task_spec.lua +++ b/tests/manage/task_spec.lua @@ -21,9 +21,9 @@ describe("task", function() it("simple function", function() local task = Task.new(plugin, "test", function() end, opts) - assert(task:is_running()) + assert(task:running()) task:wait() - assert(not task:is_running()) + assert(not task:running()) assert(task_result.done) end) @@ -31,9 +31,9 @@ describe("task", function() local task = Task.new(plugin, "test", function() error("test") end, opts) - assert(task:is_running()) + assert(task:running()) task:wait() - assert(not task:is_running()) + assert(not task:running()) assert(task_result.done) assert(task_result.error) assert(task:has_errors() and task:output(vim.log.levels.ERROR):find("test")) @@ -46,12 +46,12 @@ describe("task", function() coroutine.yield() running = false end, opts) - assert(task:is_running()) + assert(task:running()) assert(running) - assert(task:is_running()) + assert(task:running()) task:wait() assert(not running) - assert(not task:is_running()) + assert(not task:running()) assert(task_result.done) assert(not task:has_errors()) end) @@ -60,19 +60,19 @@ describe("task", function() local task = Task.new(plugin, "spawn_errors", function(task) task:spawn("foobar") end, opts) - assert(task:is_running()) + assert(task:running()) task:wait() - assert(not task:is_running()) + assert(not task:running()) assert(task_result.done) - assert(task:has_errors() and task:output(vim.log.levels.ERROR):find("Failed to spawn"), task.output) + assert(task:has_errors() and task:output(vim.log.levels.ERROR):find("Failed to spawn"), task:output()) end) it("spawn", function() local task = Task.new(plugin, "test", function(task) task:spawn("echo", { args = { "foo" } }) end, opts) - assert(task:is_running()) - assert(task:is_running()) + assert(task:running()) + assert(task:running()) task:wait() assert.same(task:output(), "foo") assert(task_result.done) @@ -84,8 +84,8 @@ describe("task", function() task:spawn("echo", { args = { "foo" } }) task:spawn("echo", { args = { "bar" } }) end, opts) - assert(task:is_running()) - assert(task:is_running()) + assert(task:running()) + assert(task:running()) task:wait() assert(task:output() == "foo\nbar" or task:output() == "bar\nfoo", task:output()) assert(task_result.done) diff --git a/tests/run b/tests/run index 7c8bb34..7872f5a 100755 --- a/tests/run +++ b/tests/run @@ -1,3 +1,3 @@ #!/bin/sh -nvim -l tests/busted.lua tests -o utfTerminal +nvim -l tests/busted.lua tests -o utfTerminal "$@" diff --git a/vim.toml b/vim.toml index 4206f6c..df7e67e 100644 --- a/vim.toml +++ b/vim.toml @@ -8,42 +8,14 @@ any = true [jit] any = true -[[describe.args]] -type = "string" -[[describe.args]] -type = "function" - -[[it.args]] -type = "string" -[[it.args]] -type = "function" - -[[before_each.args]] -type = "function" -[[after_each.args]] -type = "function" - -[assert.is_not] +[assert] any = true -[[assert.equals.args]] -type = "any" -[[assert.equals.args]] -type = "any" -[[assert.equals.args]] -type = "any" -required = false +[describe] +any = true -[[assert.same.args]] -type = "any" -[[assert.same.args]] -type = "any" +[it] +any = true -[[assert.truthy.args]] -type = "any" - -[[assert.spy.args]] -type = "any" - -[[assert.stub.args]] -type = "any" +[before_each.args] +any = true