Question: Is `shutdown` and `close` (use new_pipe with spawn) sync or async?
linrongbin16 opened this issue · comments
Hi,
I am writing a Neovim plugin with luv, spawn a command line and wait for all the output, then close the stdout/stderr pipe, here's the close code:
local function on_exit()
out_pipe:shutdown()
err_pipe:shutdown()
out_pipe:close()
err_pipe:close()
vim.loop.close() -- `vim.loop` is `uv`
end
This is because I read the docs - L28, there's a sample code:
local uv = require("luv") -- "luv" when stand-alone, "uv" in luvi apps
local server = uv.new_tcp()
server:bind("127.0.0.1", 1337)
server:listen(128, function (err)
assert(not err, err)
local client = uv.new_tcp()
server:accept(client)
client:read_start(function (err, chunk)
assert(not err, err)
if chunk then
client:write(chunk)
else
client:shutdown()
client:close()
end
end)
end)
print("TCP server listening at 127.0.0.1 port 1337")
uv.run() -- an explicit run call is necessary outside of luvit
It looks like these 2 APIs are sync, e.g., I first call shutdown
, then close
.
Somehow when I read the API signature of shutdown and close, I'm thinking I should write it like this:
local function on_exit()
out_pipe:shutdown(function()
out_pipe:close(function()
if out_pipe:is_closing() and err_pipe:is_closing() then
vim.loop.stop()
end
end)
end)
err_pipe:shutdown(function()
err_pipe:close(function()
if out_pipe:is_closing() and err_pipe:is_closing() then
vim.loop.stop()
end
end)
end)
end
In my practicing, both of them seems working correctly, (maybe it's related to how I consumed the output of the command line) there's no data loss from command line in the 1st way.
But would you please educate me, which one should I use? or is there a best-practice when I use spawn?
I think I find the correct way to use spawn
API in Neovim, here's a small sample:
local cmds = {'ls', '-lha', '~'}
local process_handler, process_id
local function on_exit(code, signal)
if process_handler and not process_handler:is_closing() then
process_handler:close(function(err)
vim.uv.stop() -- stop uv loop after close spawn process handler
end)
end
end
local function on_stdout(err, data)
-- process output here
end
local function on_stderr(err, data)
if err then
io.write(string.format("err:%s, data:%s\n", vim.inspect(err), vim.inspect(data)))
on_exit(1)
end
end
local out_pipe = vim.uv.new_pipe(false)
local err_pipe = vim.uv.new_pipe(false)
process_handler, process_id = vim.uv.spawn(cmds[1], {
args = vim.list_slice(cmds, 2),
stdio = { nil, out_pipe, err_pipe },
}, function(code, signal)
out_pipe:read_stop()
err_pipe:read_stop()
out_pipe:shutdown()
err_pipe:shutdown()
on_exit(code)
end)
out_pipe:read_start(on_stdout)
err_pipe:read_start(on_stderr)
vim.uv.run() -- start uv loop here, it will block the main thread until the command ends