diff --git a/doc/nio.txt b/doc/nio.txt index afe2c60..3625f2d 100644 --- a/doc/nio.txt +++ b/doc/nio.txt @@ -81,7 +81,7 @@ result, with the same signature as the callback for `nio.run`. This is useful for APIs where users don't want to create async contexts but which are still used in async contexts internally. Parameters~ -{func} `(async fun(...))` +{func} `(async)` function {argc?} `(integer)` The number of arguments of func. Must be included if there are arguments. @@ -403,13 +403,15 @@ Fields~ {pid} `(integer)` ID of the invoked process {signal} `(fun(signal: integer|uv.aliases.signals))` Send a signal to the process -{result} `(async fun(): number)` Wait for the process to exit and return the -exit code +{result} `(async fun(close: boolean): number,(string|nil)[])` Wait for the +process to exit and return the exit code, optionally closing all streams. {stdin} `(nio.streams.OSStreamWriter)` Stream to write to the process stdin. {stdout} `(nio.streams.OSStreamReader)` Stream to read from the process stdout. {stderr} `(nio.streams.OSStreamReader)` Stream to read from the process stderr. +{close} `(async fun():(string|nil)[])` Close all streams, returning any errors +that occurred. *nio.process.run()* `run`({opts}) @@ -422,6 +424,8 @@ Run a process asynchronously. local output = second.stdout.read() print(output) + + process.close() < Processes can be chained together, passing output of one process as input to @@ -437,6 +441,9 @@ another. local output = second.stdout.read() print(output) + + first.close() + second.close() < The stdio fields can also be file objects. @@ -454,6 +461,8 @@ The stdio fields can also be file objects. local output = file.read(nil, 0) print(output) + + process.close() -- Closes the file < Parameters~ {opts} `(nio.process.RunOpts)` diff --git a/lua/nio/process.lua b/lua/nio/process.lua index 655e59f..f494e54 100644 --- a/lua/nio/process.lua +++ b/lua/nio/process.lua @@ -11,10 +11,11 @@ nio.process = {} ---@class nio.process.Process ---@field pid integer ID of the invoked process ---@field signal fun(signal: integer|uv.aliases.signals) Send a signal to the process ----@field result async fun(): number Wait for the process to exit and return the exit code +---@field result async fun(close: boolean): number,(string|nil)[] Wait for the process to exit and return the exit code, optionally closing all streams. ---@field stdin nio.streams.OSStreamWriter Stream to write to the process stdin. ---@field stdout nio.streams.OSStreamReader Stream to read from the process stdout. ---@field stderr nio.streams.OSStreamReader Stream to read from the process stderr. +---@field close async fun():(string|nil)[] Close all streams, returning any errors that occurred. --- Run a process asynchronously. --- ```lua @@ -24,6 +25,8 @@ nio.process = {} --- --- local output = second.stdout.read() --- print(output) +--- +--- process.close() --- ``` --- --- Processes can be chained together, passing output of one process as input to @@ -39,6 +42,9 @@ nio.process = {} --- --- local output = second.stdout.read() --- print(output) +--- +--- first.close() +--- second.close() --- ``` --- --- The stdio fields can also be file objects. @@ -56,6 +62,8 @@ nio.process = {} --- --- local output = file.read(nil, 0) --- print(output) +--- +--- process.close() -- Closes the file --- ``` ---@param opts nio.process.RunOpts ---@return nio.process.Process? Process object for the running process @@ -114,7 +122,8 @@ function nio.process.run(opts) end ---@type nio.process.Process - local process = { + local process + process = { pid = pid_or_error, signal = function(signal) vim.loop.process_kill(handle, signal) @@ -134,7 +143,17 @@ function nio.process.run(opts) fd = stderr_fd, close = stderr.close, }, - result = exit_code_future.wait, + result = function(close) + local result = exit_code_future.wait() + local errors = {} + if close then + errors = process.close() + end + return result, errors + end, + close = function() + return { stdin.close(), stdout.close(), stderr.close() } + end, } return process end diff --git a/tests/process_spec.lua b/tests/process_spec.lua index 1096792..aeaacf8 100644 --- a/tests/process_spec.lua +++ b/tests/process_spec.lua @@ -196,17 +196,36 @@ describe("process", function() end) a.it("returns exit code", function() - local pipe = assert(vim.loop.new_pipe()) - local process = assert(nio.process.run({ cmd = "bash", args = { "-c", "exit 1" }, - stdin = pipe, })) - process.signal(15) - local exit_code = process.result() - assert.equal(0, exit_code) + assert.equal(1, exit_code) + end) + + a.it("with returns exit code", function() + local process = assert(nio.process.run({ + cmd = "bash", + args = { "-c", "exit 1" }, + })) + + local exit_code = process.with(function() end) + + assert.equal(1, exit_code) + end) + + a.it("with closes streams", function() + local process = assert(nio.process.run({ + cmd = "echo", + args = { "test" }, + })) + + process.with(function() end) + + local stdout, stdout_err = process.stdout.read() + assert.equal("", stdout) + assert.Not.Nil(stdout_err) end) end)