Show errors on vim.system failure (#8552)

Problem: `vim.system` throws an error when `uv.spawn` fails, in
particular when `cmd` or `cwd` does not exist. This kills the coroutine,
which makes the corresponding async call hang.

Solution: Wrap `vim.system` in a function that catches any error and
returns it as `stderr` in a `SystemObj`.

Co-authored-by: Christian Clason <c.clason@uni-graz.at>
This commit is contained in:
Luca Papagni
2026-03-14 19:06:38 +01:00
committed by GitHub
parent eb1f8e80cb
commit 88a217f570

View File

@@ -97,7 +97,31 @@ end
local function system(cmd, opts)
local cwd = opts and opts.cwd or uv.cwd()
log.trace('running job: (cwd=%s) %s', cwd, table.concat(cmd, ' '))
local r = a.await(3, vim.system, cmd, opts) --[[@as vim.SystemCompleted]]
---vim.system throws an error when uv.spawn fails, in particular if cmd or cwd
---does not exist. This kills the coroutine, so the async'ed call simply hangs.
---Instead, we pass a wrapper that catches errors and propagates them as a proper
---`SystemObj`.
---TODO(clason): remove when https://github.com/neovim/neovim/issues/38257 is resolved.
---@param _cmd string[]
---@param _opts vim.SystemOpts
---@param on_exit fun(result: vim.SystemCompleted)
---@return vim.SystemObj?
local function system_wrap(_cmd, _opts, on_exit)
local ok, ret = pcall(vim.system, _cmd, _opts, on_exit)
if not ok then
on_exit({
code = 125,
signal = 0,
stdout = '',
stderr = ret --[[@as string]],
})
return nil
end
return ret --[[@as vim.SystemObj]]
end
local r = a.await(3, system_wrap, cmd, opts) --[[@as vim.SystemCompleted]]
a.schedule()
if r.stdout and r.stdout ~= '' then
log.trace('stdout -> %s', r.stdout)