mirror of
https://github.com/neovim/neovim.git
synced 2024-12-23 20:55:18 -07:00
job control: add 'detach' option to jobstart
This commit is contained in:
parent
ee0e214427
commit
d0d5d17b69
@ -4194,6 +4194,10 @@ jobstart({cmd}[, {opts}]) {Nvim} *jobstart()*
|
||||
- width: Width of the terminal screen(only if pty is set)
|
||||
- height: Height of the terminal screen(only if pty is set)
|
||||
- TERM: $TERM environment variable(only if pty is set)
|
||||
- detach: Detach the job process from the nvim process. The
|
||||
process won't get killed when nvim exists. If the process
|
||||
dies before nvim exits, on_exit will still be invoked.
|
||||
This option is only allowed for non-pty jobs.
|
||||
Either funcrefs or function names can be passed as event
|
||||
handlers. The {opts} object is also used as the "self"
|
||||
argument for the callback, so the caller may pass arbitrary
|
||||
|
@ -11771,8 +11771,9 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv)
|
||||
}
|
||||
|
||||
bool pty = job_opts && get_dict_number(job_opts, (uint8_t *)"pty") != 0;
|
||||
bool detach = job_opts && get_dict_number(job_opts, (uint8_t *)"detach") != 0;
|
||||
TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit,
|
||||
job_opts, pty);
|
||||
job_opts, pty, detach);
|
||||
Process *proc = (Process *)&data->proc;
|
||||
|
||||
if (pty) {
|
||||
@ -16776,7 +16777,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
|
||||
}
|
||||
|
||||
TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit,
|
||||
job_opts, true);
|
||||
job_opts, true, false);
|
||||
data->proc.pty.width = curwin->w_width;
|
||||
data->proc.pty.height = curwin->w_height;
|
||||
data->proc.pty.term_name = xstrdup("xterm-256color");
|
||||
@ -21782,8 +21783,13 @@ char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, char_u *flags)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline TerminalJobData *common_job_init(char **argv, ufunc_T *on_stdout,
|
||||
ufunc_T *on_stderr, ufunc_T *on_exit, dict_T *self, bool pty)
|
||||
static inline TerminalJobData *common_job_init(char **argv,
|
||||
ufunc_T *on_stdout,
|
||||
ufunc_T *on_stderr,
|
||||
ufunc_T *on_exit,
|
||||
dict_T *self,
|
||||
bool pty,
|
||||
bool detach)
|
||||
{
|
||||
TerminalJobData *data = xcalloc(1, sizeof(TerminalJobData));
|
||||
data->stopped = false;
|
||||
@ -21806,6 +21812,7 @@ static inline TerminalJobData *common_job_init(char **argv, ufunc_T *on_stdout,
|
||||
}
|
||||
proc->cb = on_process_exit;
|
||||
proc->events = data->events;
|
||||
proc->detach = detach;
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -21833,8 +21840,13 @@ static inline bool common_job_callbacks(dict_T *vopts, ufunc_T **on_stdout,
|
||||
|
||||
static inline bool common_job_start(TerminalJobData *data, typval_T *rettv)
|
||||
{
|
||||
data->refcount++;
|
||||
Process *proc = (Process *)&data->proc;
|
||||
if (proc->type == kProcessTypePty && proc->detach) {
|
||||
EMSG2(_(e_invarg2), "terminal/pty job cannot be detached");
|
||||
return false;
|
||||
}
|
||||
|
||||
data->refcount++;
|
||||
char *cmd = xstrdup(proc->argv[0]);
|
||||
if (!process_spawn(proc)) {
|
||||
EMSG2(_(e_jobspawn), cmd);
|
||||
|
@ -21,6 +21,9 @@ bool libuv_process_spawn(LibuvProcess *uvproc)
|
||||
uvproc->uvopts.args = proc->argv;
|
||||
uvproc->uvopts.flags = UV_PROCESS_WINDOWS_HIDE
|
||||
| UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
|
||||
if (proc->detach) {
|
||||
uvproc->uvopts.flags |= UV_PROCESS_DETACHED;
|
||||
}
|
||||
uvproc->uvopts.exit_cb = exit_cb;
|
||||
uvproc->uvopts.cwd = NULL;
|
||||
uvproc->uvopts.env = NULL;
|
||||
|
@ -29,6 +29,7 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static bool process_is_tearing_down = false;
|
||||
|
||||
bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
@ -112,11 +113,17 @@ bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
|
||||
|
||||
void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
process_is_tearing_down = true;
|
||||
kl_iter(WatcherPtr, loop->children, current) {
|
||||
Process *proc = (*current)->data;
|
||||
uv_kill(proc->pid, SIGTERM);
|
||||
proc->term_sent = true;
|
||||
process_stop(proc);
|
||||
if (proc->detach) {
|
||||
// Close handles to process without killing it.
|
||||
CREATE_EVENT(loop->events, process_close_handles, 1, proc);
|
||||
} else {
|
||||
uv_kill(proc->pid, SIGTERM);
|
||||
proc->term_sent = true;
|
||||
process_stop(proc);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait until all children exit
|
||||
@ -303,6 +310,10 @@ static void decref(Process *proc)
|
||||
static void process_close(Process *proc)
|
||||
FUNC_ATTR_NONNULL_ARG(1)
|
||||
{
|
||||
if (process_is_tearing_down && proc->detach && proc->closed) {
|
||||
// If a detached process dies while tearing down it might get closed twice.
|
||||
return;
|
||||
}
|
||||
assert(!proc->closed);
|
||||
proc->closed = true;
|
||||
switch (proc->type) {
|
||||
@ -333,6 +344,7 @@ static void on_process_exit(Process *proc)
|
||||
DLOG("Stopping process kill timer");
|
||||
uv_timer_stop(&loop->children_kill_timer);
|
||||
}
|
||||
|
||||
// Process handles are closed in the next event loop tick. This is done to
|
||||
// give libuv more time to read data from the OS after the process exits(If
|
||||
// process_close_streams is called with data still in the OS buffer, we lose
|
||||
|
@ -25,7 +25,7 @@ struct process {
|
||||
Stream *in, *out, *err;
|
||||
process_exit_cb cb;
|
||||
internal_process_cb internal_exit_cb, internal_close_cb;
|
||||
bool closed, term_sent;
|
||||
bool closed, term_sent, detach;
|
||||
Queue *events;
|
||||
};
|
||||
|
||||
@ -48,7 +48,8 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data)
|
||||
.closed = false,
|
||||
.term_sent = false,
|
||||
.internal_close_cb = NULL,
|
||||
.internal_exit_cb = NULL
|
||||
.internal_exit_cb = NULL,
|
||||
.detach = false
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user