mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 03:05:11 -07:00
Merge pull request #14812 from gpanders/stdin_closed
feat(job): add parameter to close stdin
This commit is contained in:
commit
02bf251bb3
@ -5637,6 +5637,9 @@ jobstart({cmd}[, {opts}]) *jobstart()*
|
||||
before invoking `on_stderr`. |channel-buffered|
|
||||
stdout_buffered: (boolean) Collect data until EOF (stream
|
||||
closed) before invoking `on_stdout`. |channel-buffered|
|
||||
stdin: (string) Either "pipe" (default) to connect the
|
||||
job's stdin to a channel or "null" to disconnect
|
||||
stdin.
|
||||
width: (number) Width of the `pty` terminal.
|
||||
|
||||
{opts} is passed as |self| dictionary to the callback; the
|
||||
|
@ -289,6 +289,9 @@ static void close_cb(Stream *stream, void *data)
|
||||
/// `on_stdout` is ignored
|
||||
/// @param[in] detach True if the job should not be killed when nvim exits,
|
||||
/// ignored if `pty` is true
|
||||
/// @param[in] stdin_mode Stdin mode. Either kChannelStdinPipe to open a
|
||||
/// channel for stdin or kChannelStdinNull to leave
|
||||
/// stdin disconnected.
|
||||
/// @param[in] cwd Initial working directory for the job. Nvim's working
|
||||
/// directory if `cwd` is NULL
|
||||
/// @param[in] pty_width Width of the pty, ignored if `pty` is false
|
||||
@ -302,7 +305,7 @@ static void close_cb(Stream *stream, void *data)
|
||||
Channel *channel_job_start(char **argv, CallbackReader on_stdout,
|
||||
CallbackReader on_stderr, Callback on_exit,
|
||||
bool pty, bool rpc, bool overlapped, bool detach,
|
||||
const char *cwd,
|
||||
ChannelStdinMode stdin_mode, const char *cwd,
|
||||
uint16_t pty_width, uint16_t pty_height,
|
||||
dict_T *env, varnumber_T *status_out)
|
||||
{
|
||||
@ -345,7 +348,7 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout,
|
||||
proc->overlapped = overlapped;
|
||||
|
||||
char *cmd = xstrdup(proc->argv[0]);
|
||||
bool has_out, has_err;
|
||||
bool has_in, has_out, has_err;
|
||||
if (proc->type == kProcessTypePty) {
|
||||
has_out = true;
|
||||
has_err = false;
|
||||
@ -353,7 +356,17 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout,
|
||||
has_out = rpc || callback_reader_set(chan->on_data);
|
||||
has_err = callback_reader_set(chan->on_stderr);
|
||||
}
|
||||
int status = process_spawn(proc, true, has_out, has_err);
|
||||
|
||||
switch (stdin_mode) {
|
||||
case kChannelStdinPipe:
|
||||
has_in = true;
|
||||
break;
|
||||
case kChannelStdinNull:
|
||||
has_in = false;
|
||||
break;
|
||||
}
|
||||
|
||||
int status = process_spawn(proc, has_in, has_out, has_err);
|
||||
if (status) {
|
||||
EMSG3(_(e_jobspawn), os_strerror(status), cmd);
|
||||
xfree(cmd);
|
||||
@ -369,7 +382,9 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout,
|
||||
tv_dict_free(proc->env);
|
||||
}
|
||||
|
||||
if (has_in) {
|
||||
wstream_init(&proc->in, 0);
|
||||
}
|
||||
if (has_out) {
|
||||
rstream_init(&proc->out, 0);
|
||||
}
|
||||
|
@ -28,6 +28,10 @@ typedef enum {
|
||||
kChannelPartAll
|
||||
} ChannelPart;
|
||||
|
||||
typedef enum {
|
||||
kChannelStdinPipe,
|
||||
kChannelStdinNull,
|
||||
} ChannelStdinMode;
|
||||
|
||||
typedef struct {
|
||||
Stream in;
|
||||
|
@ -5182,6 +5182,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
bool pty = false;
|
||||
bool clear_env = false;
|
||||
bool overlapped = false;
|
||||
ChannelStdinMode stdin_mode = kChannelStdinPipe;
|
||||
CallbackReader on_stdout = CALLBACK_READER_INIT,
|
||||
on_stderr = CALLBACK_READER_INIT;
|
||||
Callback on_exit = CALLBACK_NONE;
|
||||
@ -5196,6 +5197,17 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
clear_env = tv_dict_get_number(job_opts, "clear_env") != 0;
|
||||
overlapped = tv_dict_get_number(job_opts, "overlapped") != 0;
|
||||
|
||||
char *s = tv_dict_get_string(job_opts, "stdin", false);
|
||||
if (s) {
|
||||
if (!strncmp(s, "null", NUMBUFLEN)) {
|
||||
stdin_mode = kChannelStdinNull;
|
||||
} else if (!strncmp(s, "pipe", NUMBUFLEN)) {
|
||||
// Nothing to do, default value
|
||||
} else {
|
||||
EMSG3(_(e_invargNval), "stdin", s);
|
||||
}
|
||||
}
|
||||
|
||||
if (pty && rpc) {
|
||||
EMSG2(_(e_invarg2), "job cannot have both 'pty' and 'rpc' options set");
|
||||
shell_free_argv(argv);
|
||||
@ -5252,8 +5264,8 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
env = create_environment(job_env, clear_env, pty, term_name);
|
||||
|
||||
Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit, pty,
|
||||
rpc, overlapped, detach, cwd, width, height,
|
||||
env, &rettv->vval.v_number);
|
||||
rpc, overlapped, detach, stdin_mode, cwd,
|
||||
width, height, env, &rettv->vval.v_number);
|
||||
if (chan) {
|
||||
channel_create_event(chan, NULL);
|
||||
}
|
||||
@ -7733,8 +7745,9 @@ static void f_rpcstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
|
||||
Channel *chan = channel_job_start(argv, CALLBACK_READER_INIT,
|
||||
CALLBACK_READER_INIT, CALLBACK_NONE,
|
||||
false, true, false, false, NULL, 0, 0,
|
||||
NULL, &rettv->vval.v_number);
|
||||
false, true, false, false,
|
||||
kChannelStdinPipe, NULL, 0, 0, NULL,
|
||||
&rettv->vval.v_number);
|
||||
if (chan) {
|
||||
channel_create_event(chan, NULL);
|
||||
}
|
||||
@ -10850,10 +10863,11 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
const bool rpc = false;
|
||||
const bool overlapped = false;
|
||||
const bool detach = false;
|
||||
ChannelStdinMode stdin_mode = kChannelStdinPipe;
|
||||
uint16_t term_width = MAX(0, curwin->w_width_inner - win_col_off(curwin));
|
||||
Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit,
|
||||
pty, rpc, overlapped, detach, cwd,
|
||||
term_width, curwin->w_height_inner,
|
||||
pty, rpc, overlapped, detach, stdin_mode,
|
||||
cwd, term_width, curwin->w_height_inner,
|
||||
env, &rettv->vval.v_number);
|
||||
if (rettv->vval.v_number <= 0) {
|
||||
return;
|
||||
|
@ -348,6 +348,12 @@ describe('jobs', function()
|
||||
eq(false, pcall(function()
|
||||
nvim('command', 'call jobsend(j, ["some data"])')
|
||||
end))
|
||||
|
||||
command("let g:job_opts.stdin = 'null'")
|
||||
nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
|
||||
eq(false, pcall(function()
|
||||
nvim('command', 'call jobsend(j, ["some data"])')
|
||||
end))
|
||||
end)
|
||||
|
||||
it('disallows jobsend on a non-existent job', function()
|
||||
|
Loading…
Reference in New Issue
Block a user