mirror of
https://github.com/neovim/neovim.git
synced 2025-10-17 15:21:47 +00:00
job: Replace by a better process abstraction layer
- New libuv/pty process abstraction with simplified API and no globals. - Remove nvim/os/job*. Jobs are now a concept that apply only to programs spawned by vimscript job* functions. - Refactor shell.c/channel.c to use the new module, which brings a number of advantages: - Simplified API, less code - No slots in the user job table are used - Not possible to acidentally receive data from vimscript - Implement job table in eval.c, which is now a hash table with unilimited job slots and unique job ids.
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
#include "nvim/lib/kvec.h"
|
||||
#include "nvim/log.h"
|
||||
#include "nvim/event/loop.h"
|
||||
#include "nvim/os/job.h"
|
||||
#include "nvim/event/uv_process.h"
|
||||
#include "nvim/event/rstream.h"
|
||||
#include "nvim/os/shell.h"
|
||||
#include "nvim/os/signal.h"
|
||||
@@ -204,17 +204,15 @@ static int do_os_system(char **argv,
|
||||
char prog[MAXPATHL];
|
||||
xstrlcpy(prog, argv[0], MAXPATHL);
|
||||
|
||||
int status;
|
||||
JobOptions opts = JOB_OPTIONS_INIT;
|
||||
opts.argv = argv;
|
||||
opts.data = &buf;
|
||||
opts.writable = input != NULL;
|
||||
opts.stdout_cb = data_cb;
|
||||
opts.stderr_cb = data_cb;
|
||||
opts.exit_cb = NULL;
|
||||
Job *job = job_start(opts, &status);
|
||||
|
||||
if (status <= 0) {
|
||||
Stream in, out, err;
|
||||
UvProcess uvproc = uv_process_init(&buf);
|
||||
Process *proc = &uvproc.process;
|
||||
proc->argv = argv;
|
||||
proc->in = input != NULL ? &in : NULL;
|
||||
proc->out = &out;
|
||||
proc->err = &err;
|
||||
if (!process_spawn(&loop, proc)) {
|
||||
loop_poll_events(&loop, 0);
|
||||
// Failed, probably due to `sh` not being executable
|
||||
if (!silent) {
|
||||
MSG_PUTS(_("\nCannot execute "));
|
||||
@@ -224,28 +222,32 @@ static int do_os_system(char **argv,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (input != NULL) {
|
||||
wstream_init(proc->in, 0);
|
||||
}
|
||||
rstream_init(proc->out, 0);
|
||||
rstream_start(proc->out, data_cb);
|
||||
rstream_init(proc->err, 0);
|
||||
rstream_start(proc->err, data_cb);
|
||||
|
||||
// write the input, if any
|
||||
if (input) {
|
||||
WBuffer *input_buffer = wstream_new_buffer((char *) input, len, 1, NULL);
|
||||
|
||||
if (!job_write(job, input_buffer)) {
|
||||
// couldn't write, stop the job and tell the user about it
|
||||
job_stop(job);
|
||||
if (!wstream_write(&in, input_buffer)) {
|
||||
// couldn't write, stop the process and tell the user about it
|
||||
process_stop(proc);
|
||||
return -1;
|
||||
}
|
||||
// close the input stream after everything is written
|
||||
job_write_cb(job, shell_write_cb);
|
||||
} else {
|
||||
// close the input stream, let the process know that no more input is
|
||||
// coming
|
||||
job_close_in(job);
|
||||
wstream_set_write_cb(&in, shell_write_cb);
|
||||
}
|
||||
|
||||
// invoke busy_start here so event_poll_until wont change the busy state for
|
||||
// the UI
|
||||
ui_busy_start();
|
||||
ui_flush();
|
||||
status = job_wait(job, -1);
|
||||
int status = process_wait(proc, -1);
|
||||
ui_busy_stop();
|
||||
|
||||
// prepare the out parameters if requested
|
||||
@@ -285,8 +287,7 @@ static void dynamic_buffer_ensure(DynamicBuffer *buf, size_t desired)
|
||||
|
||||
static void system_data_cb(Stream *stream, RBuffer *buf, void *data, bool eof)
|
||||
{
|
||||
Job *job = data;
|
||||
DynamicBuffer *dbuf = job_data(job);
|
||||
DynamicBuffer *dbuf = data;
|
||||
|
||||
size_t nread = buf->size;
|
||||
dynamic_buffer_ensure(dbuf, dbuf->len + nread + 1);
|
||||
@@ -472,6 +473,5 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer,
|
||||
|
||||
static void shell_write_cb(Stream *stream, void *data, int status)
|
||||
{
|
||||
Job *job = data;
|
||||
job_close_in(job);
|
||||
stream_close(stream, NULL);
|
||||
}
|
||||
|
Reference in New Issue
Block a user