aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/channel.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/channel.c')
-rw-r--r--src/nvim/channel.c55
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);