diff options
Diffstat (limited to 'src/nvim/channel.c')
-rw-r--r-- | src/nvim/channel.c | 55 |
1 files changed, 50 insertions, 5 deletions
diff --git a/src/nvim/channel.c b/src/nvim/channel.c index f9102fa0e2..37cbfb968b 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -11,11 +11,14 @@ #include "nvim/msgpack_rpc/channel.h" #include "nvim/msgpack_rpc/server.h" #include "nvim/os/shell.h" +#ifdef WIN32 +# include "nvim/os/pty_conpty_win.h" +# include "nvim/os/os_win_console.h" +#endif #include "nvim/path.h" #include "nvim/ascii.h" static bool did_stdio = false; -PMap(uint64_t) *channels = NULL; /// next free id for a job or rpc channel /// 1 is reserved for stdio channel @@ -272,11 +275,36 @@ static void close_cb(Stream *stream, void *data) channel_decref(data); } + +/// Starts a job and returns the associated channel +/// +/// @param[in] argv Arguments vector specifying the command to run, +/// NULL-terminated +/// @param[in] on_stdout Callback to read the job's stdout +/// @param[in] on_stderr Callback to read the job's stderr +/// @param[in] on_exit Callback to receive the job's exit status +/// @param[in] pty True if the job should run attached to a pty +/// @param[in] rpc True to communicate with the job using msgpack-rpc, +/// `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] 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 +/// @param[in] pty_height Height of the pty, ignored if `pty` is false +/// @param[in] term_name `$TERM` for the pty +/// @param[in] env Nvim's configured environment is used if this is NULL, +/// otherwise defines all environment variables +/// @param[out] status_out 0 for invalid arguments, > 0 for the channel id, +/// < 0 if the job can't start +/// +/// @returns [allocated] channel Channel *channel_job_start(char **argv, CallbackReader on_stdout, CallbackReader on_stderr, Callback on_exit, - bool pty, bool rpc, bool detach, const char *cwd, + bool pty, bool rpc, bool overlapped, bool detach, + const char *cwd, uint16_t pty_width, uint16_t pty_height, - char *term_name, varnumber_T *status_out) + char *term_name, char **env, varnumber_T *status_out) { assert(cwd == NULL || os_isdir_executable(cwd)); @@ -314,6 +342,8 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout, proc->events = chan->events; proc->detach = detach; proc->cwd = cwd; + proc->env = env; + proc->overlapped = overlapped; char *cmd = xstrdup(proc->argv[0]); bool has_out, has_err; @@ -328,6 +358,7 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout, if (status) { EMSG3(_(e_jobspawn), os_strerror(status), cmd); xfree(cmd); + os_free_fullenv(proc->env); if (proc->type == kProcessTypePty) { xfree(chan->stream.pty.term_name); } @@ -336,6 +367,8 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout, return NULL; } xfree(cmd); + os_free_fullenv(proc->env); + wstream_init(&proc->in, 0); if (has_out) { @@ -441,8 +474,20 @@ uint64_t channel_from_stdio(bool rpc, CallbackReader on_output, Channel *channel = channel_alloc(kChannelStreamStdio); - rstream_init_fd(&main_loop, &channel->stream.stdio.in, 0, 0); - wstream_init_fd(&main_loop, &channel->stream.stdio.out, 1, 0); + int stdin_dup_fd = STDIN_FILENO; + int stdout_dup_fd = STDOUT_FILENO; +#ifdef WIN32 + // Strangely, ConPTY doesn't work if stdin and stdout are pipes. So replace + // stdin and stdout with CONIN$ and CONOUT$, respectively. + if (embedded_mode && os_has_conpty_working()) { + stdin_dup_fd = os_dup(STDIN_FILENO); + os_replace_stdin_to_conin(); + stdout_dup_fd = os_dup(STDOUT_FILENO); + os_replace_stdout_and_stderr_to_conout(); + } +#endif + rstream_init_fd(&main_loop, &channel->stream.stdio.in, stdin_dup_fd, 0); + wstream_init_fd(&main_loop, &channel->stream.stdio.out, stdout_dup_fd, 0); if (rpc) { rpc_start(channel); |