diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/nvim/eval.c | 1 | ||||
| -rw-r--r-- | src/nvim/msgpack_rpc/channel.c | 1 | ||||
| -rw-r--r-- | src/nvim/os/job.c | 88 | ||||
| -rw-r--r-- | src/nvim/os/shell.c | 40 | 
4 files changed, 85 insertions, 45 deletions
| diff --git a/src/nvim/eval.c b/src/nvim/eval.c index d0af4b8249..6b6f008a44 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -10675,6 +10675,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv)    job_start(argv,              xstrdup((char *)argvars[0].vval.v_string), +            true,              on_job_stdout,              on_job_stderr,              on_job_exit, diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 43bed54b2c..8d74921562 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -119,6 +119,7 @@ uint64_t channel_from_job(char **argv)    int status;    channel->data.job = job_start(argv,                                  channel, +                                true,                                  job_out,                                  job_err,                                  job_exit, diff --git a/src/nvim/os/job.c b/src/nvim/os/job.c index bbf8006ab6..4fa442fe76 100644 --- a/src/nvim/os/job.c +++ b/src/nvim/os/job.c @@ -136,10 +136,12 @@ void job_teardown(void)  /// @param argv Argument vector for the process. The first item is the  ///        executable to run.  /// @param data Caller data that will be associated with the job +/// @param writable If true the job stdin will be available for writing with +///                 job_write, otherwise it will be redirected to /dev/null  /// @param stdout_cb Callback that will be invoked when data is available -///        on stdout +///        on stdout. If NULL stdout will be redirected to /dev/null.  /// @param stderr_cb Callback that will be invoked when data is available -///        on stderr +///        on stderr. If NULL stderr will be redirected to /dev/null.  /// @param job_exit_cb Callback that will be invoked when the job exits  /// @param maxmem Maximum amount of memory used by the job WStream  /// @param[out] status The job id if the job started successfully, 0 if the job @@ -147,6 +149,7 @@ void job_teardown(void)  /// @return The job pointer if the job started successfully, NULL otherwise  Job *job_start(char **argv,                 void *data, +               bool writable,                 rstream_cb stdout_cb,                 rstream_cb stderr_cb,                 job_exit_cb job_exit_cb, @@ -174,7 +177,7 @@ Job *job_start(char **argv,    job->id = i + 1;    *status = job->id;    job->status = -1; -  job->refcount = 4; +  job->refcount = 1;    job->data = data;    job->stdout_cb = stdout_cb;    job->stderr_cb = stderr_cb; @@ -193,45 +196,76 @@ Job *job_start(char **argv,    job->proc_stdin.data = NULL;    job->proc_stdout.data = NULL;    job->proc_stderr.data = NULL; +  job->in = NULL; +  job->out = NULL; +  job->err = NULL;    // Initialize the job std{in,out,err} -  uv_pipe_init(uv_default_loop(), &job->proc_stdin, 0); -  job->stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; -  job->stdio[0].data.stream = (uv_stream_t *)&job->proc_stdin; +  job->stdio[0].flags = UV_IGNORE; +  job->stdio[1].flags = UV_IGNORE; +  job->stdio[2].flags = UV_IGNORE; + +  if (writable) { +    uv_pipe_init(uv_default_loop(), &job->proc_stdin, 0); +    job->stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; +    job->stdio[0].data.stream = (uv_stream_t *)&job->proc_stdin; +    handle_set_job((uv_handle_t *)&job->proc_stdin, job); +    job->refcount++; +  } -  uv_pipe_init(uv_default_loop(), &job->proc_stdout, 0); -  job->stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; -  job->stdio[1].data.stream = (uv_stream_t *)&job->proc_stdout; +  if (stdout_cb) { +    uv_pipe_init(uv_default_loop(), &job->proc_stdout, 0); +    job->stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; +    job->stdio[1].data.stream = (uv_stream_t *)&job->proc_stdout; +    handle_set_job((uv_handle_t *)&job->proc_stdout, job); +    job->refcount++; +  } -  uv_pipe_init(uv_default_loop(), &job->proc_stderr, 0); -  job->stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; -  job->stdio[2].data.stream = (uv_stream_t *)&job->proc_stderr; +  if (stderr_cb) { +    uv_pipe_init(uv_default_loop(), &job->proc_stderr, 0); +    job->stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; +    job->stdio[2].data.stream = (uv_stream_t *)&job->proc_stderr; +    handle_set_job((uv_handle_t *)&job->proc_stderr, job); +    job->refcount++; +  } -  // Give all handles a reference to the job    handle_set_job((uv_handle_t *)&job->proc, job); -  handle_set_job((uv_handle_t *)&job->proc_stdin, job); -  handle_set_job((uv_handle_t *)&job->proc_stdout, job); -  handle_set_job((uv_handle_t *)&job->proc_stderr, job);    // Spawn the job    if (uv_spawn(uv_default_loop(), &job->proc, &job->proc_opts) != 0) { -    uv_close((uv_handle_t *)&job->proc_stdin, NULL); -    uv_close((uv_handle_t *)&job->proc_stdout, NULL); -    uv_close((uv_handle_t *)&job->proc_stderr, NULL); +    if (writable) { +      uv_close((uv_handle_t *)&job->proc_stdin, close_cb); +    } +    if (stdout_cb) { +      uv_close((uv_handle_t *)&job->proc_stdout, close_cb); +    } +    if (stderr_cb) { +      uv_close((uv_handle_t *)&job->proc_stderr, close_cb); +    } +    uv_close((uv_handle_t *)&job->proc, close_cb);      event_poll(0); +    // Manually invoke the close_cb to free the job resources      *status = -1;      return NULL;    } -  job->in = wstream_new(maxmem); -  wstream_set_stream(job->in, (uv_stream_t *)&job->proc_stdin); +  if (writable) { +    job->in = wstream_new(maxmem); +    wstream_set_stream(job->in, (uv_stream_t *)&job->proc_stdin); +  } +    // Start the readable streams -  job->out = rstream_new(read_cb, rbuffer_new(JOB_BUFFER_SIZE), job); -  job->err = rstream_new(read_cb, rbuffer_new(JOB_BUFFER_SIZE), job); -  rstream_set_stream(job->out, (uv_stream_t *)&job->proc_stdout); -  rstream_set_stream(job->err, (uv_stream_t *)&job->proc_stderr); -  rstream_start(job->out); -  rstream_start(job->err); +  if (stdout_cb) { +    job->out = rstream_new(read_cb, rbuffer_new(JOB_BUFFER_SIZE), job); +    rstream_set_stream(job->out, (uv_stream_t *)&job->proc_stdout); +    rstream_start(job->out); +  } + +  if (stderr_cb) { +    job->err = rstream_new(read_cb, rbuffer_new(JOB_BUFFER_SIZE), job); +    rstream_set_stream(job->err, (uv_stream_t *)&job->proc_stderr); +    rstream_start(job->err); +  }    // Save the job to the table    table[i] = job; diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index d5464f7975..ef95946b68 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -258,8 +258,8 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg)  /// @param len The length of the input buffer (not used if `input` == NULL)  /// @param[out] output A pointer to to a location where the output will be  ///                    allocated and stored. Will point to NULL if the shell -///                    command did not output anything. NOTE: it's not -///                    allowed to pass NULL yet +///                    command did not output anything. If NULL is passed, +///                    the shell output will be ignored.  /// @param[out] nread the number of bytes in the returned buffer (if the  ///             returned buffer is not NULL)  /// @return the return code of the process, -1 if the process couldn't be @@ -268,7 +268,7 @@ int os_system(const char *cmd,                const char *input,                size_t len,                char **output, -              size_t *nread) FUNC_ATTR_NONNULL_ARG(1, 4) +              size_t *nread) FUNC_ATTR_NONNULL_ARG(1)  {    // the output buffer    dyn_buffer_t buf; @@ -279,8 +279,9 @@ int os_system(const char *cmd,    int i;    Job *job = job_start(argv,                         &buf, -                       system_data_cb, -                       system_data_cb, +                       input != NULL, +                       output ? system_data_cb : NULL, +                       output ? system_data_cb : NULL,                         NULL,                         0,                         &i); @@ -300,25 +301,28 @@ int os_system(const char *cmd,        job_stop(job);        return -1;      } +    // close the input stream, let the process know that no more input is +    // coming +    job_close_in(job);    } -  // close the input stream, let the process know that no more input is coming -  job_close_in(job);    int status = job_wait(job, -1);    // prepare the out parameters if requested -  if (buf.len == 0) { -    // no data received from the process, return NULL -    *output = NULL; -    free(buf.data); -  } else { -    // NUL-terminate to make the output directly usable as a C string -    buf.data[buf.len] = NUL; -    *output = buf.data; -  } +  if (output) { +    if (buf.len == 0) { +      // no data received from the process, return NULL +      *output = NULL; +      free(buf.data); +    } else { +      // NUL-terminate to make the output directly usable as a C string +      buf.data[buf.len] = NUL; +      *output = buf.data; +    } -  if (nread) { -    *nread = buf.len; +    if (nread) { +      *nread = buf.len; +    }    }    return status; | 
