diff options
-rw-r--r-- | src/nvim/CMakeLists.txt | 8 | ||||
-rw-r--r-- | src/nvim/channel.c | 20 | ||||
-rw-r--r-- | src/nvim/main.c | 11 | ||||
-rw-r--r-- | src/nvim/option.c | 3 | ||||
-rw-r--r-- | src/nvim/os/os_win_console.c | 42 | ||||
-rw-r--r-- | src/nvim/os/os_win_console.h | 8 | ||||
-rw-r--r-- | src/nvim/os/pty_conpty_win.c | 199 | ||||
-rw-r--r-- | src/nvim/os/pty_conpty_win.h | 22 | ||||
-rw-r--r-- | src/nvim/os/pty_process_win.c | 136 | ||||
-rw-r--r-- | src/nvim/os/pty_process_win.h | 15 | ||||
-rw-r--r-- | src/nvim/tui/input.c | 11 |
11 files changed, 408 insertions, 67 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index bc8e64dd41..089dd537e9 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -134,6 +134,12 @@ foreach(sfile ${NVIM_SOURCES}) if(NOT WIN32 AND ${f} MATCHES "^(pty_process_win.c)$") list(APPEND to_remove ${sfile}) endif() + if(NOT WIN32 AND ${f} MATCHES "^(pty_conpty_win.c)$") + list(APPEND to_remove ${sfile}) + endif() + if(NOT WIN32 AND ${f} MATCHES "^(os_win_console.c)$") + list(APPEND to_remove ${sfile}) + endif() endforeach() list(REMOVE_ITEM NVIM_SOURCES ${to_remove}) @@ -637,6 +643,8 @@ endfunction() set(NO_SINGLE_CHECK_HEADERS os/win_defs.h os/pty_process_win.h + os/pty_conpty_win.h + os/os_win_console.h ) foreach(hfile ${NVIM_HEADERS}) get_test_target(test-includes "${hfile}" relative_path texe) diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 2bb568f025..c66a0682e3 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -11,6 +11,10 @@ #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" @@ -469,8 +473,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); diff --git a/src/nvim/main.c b/src/nvim/main.c index c7011f4f4e..be279b449a 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -64,6 +64,9 @@ #include "nvim/os/os.h" #include "nvim/os/time.h" #include "nvim/os/fileio.h" +#ifdef WIN32 +# include "nvim/os/os_win_console.h" +#endif #include "nvim/event/loop.h" #include "nvim/os/signal.h" #include "nvim/event/process.h" @@ -1120,13 +1123,7 @@ scripterror: const int stdin_dup_fd = os_dup(STDIN_FILENO); #ifdef WIN32 // Replace the original stdin with the console input handle. - close(STDIN_FILENO); - const HANDLE conin_handle = - CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)NULL, - OPEN_EXISTING, 0, (HANDLE)NULL); - const int conin_fd = _open_osfhandle(conin_handle, _O_RDONLY); - assert(conin_fd == STDIN_FILENO); + os_replace_stdin_to_conin(); #endif FileDescriptor *const stdin_dup = file_open_fd_new( &error, stdin_dup_fd, kFileReadOnly|kFileNonBlocking); diff --git a/src/nvim/option.c b/src/nvim/option.c index 9d3e02949e..0c87a422dc 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -76,6 +76,9 @@ #include "nvim/undo.h" #include "nvim/window.h" #include "nvim/os/os.h" +#ifdef WIN32 +# include "nvim/os/pty_conpty_win.h" +#endif #include "nvim/api/private/helpers.h" #include "nvim/os/input.h" #include "nvim/os/lang.h" diff --git a/src/nvim/os/os_win_console.c b/src/nvim/os/os_win_console.c new file mode 100644 index 0000000000..8a0aa2f5ae --- /dev/null +++ b/src/nvim/os/os_win_console.c @@ -0,0 +1,42 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + +#include "nvim/vim.h" +#include "nvim/os/os_win_console.h" + +int os_get_conin_fd(void) +{ + const HANDLE conin_handle = CreateFile("CONIN$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + (LPSECURITY_ATTRIBUTES)NULL, + OPEN_EXISTING, 0, (HANDLE)NULL); + assert(conin_handle != INVALID_HANDLE_VALUE); + int conin_fd = _open_osfhandle((intptr_t)conin_handle, _O_RDONLY); + assert(conin_fd != -1); + return conin_fd; +} + +void os_replace_stdin_to_conin(void) +{ + close(STDIN_FILENO); + const int conin_fd = os_get_conin_fd(); + assert(conin_fd == STDIN_FILENO); +} + +void os_replace_stdout_and_stderr_to_conout(void) +{ + const HANDLE conout_handle = + CreateFile("CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + (LPSECURITY_ATTRIBUTES)NULL, + OPEN_EXISTING, 0, (HANDLE)NULL); + assert(conout_handle != INVALID_HANDLE_VALUE); + close(STDOUT_FILENO); + const int conout_fd = _open_osfhandle((intptr_t)conout_handle, 0); + assert(conout_fd == STDOUT_FILENO); + close(STDERR_FILENO); + const int conerr_fd = _open_osfhandle((intptr_t)conout_handle, 0); + assert(conerr_fd == STDERR_FILENO); +} diff --git a/src/nvim/os/os_win_console.h b/src/nvim/os/os_win_console.h new file mode 100644 index 0000000000..154ec83d8a --- /dev/null +++ b/src/nvim/os/os_win_console.h @@ -0,0 +1,8 @@ +#ifndef NVIM_OS_OS_WIN_CONSOLE_H +#define NVIM_OS_OS_WIN_CONSOLE_H + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "os/os_win_console.h.generated.h" +#endif + +#endif // NVIM_OS_OS_WIN_CONSOLE_H diff --git a/src/nvim/os/pty_conpty_win.c b/src/nvim/os/pty_conpty_win.c new file mode 100644 index 0000000000..5bcadd6490 --- /dev/null +++ b/src/nvim/os/pty_conpty_win.c @@ -0,0 +1,199 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + +#include <uv.h> + +#include "nvim/vim.h" +#include "nvim/os/os.h" +#include "nvim/os/pty_conpty_win.h" + +#ifndef EXTENDED_STARTUPINFO_PRESENT +# define EXTENDED_STARTUPINFO_PRESENT 0x00080000 +#endif +#ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE +# define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x00020016 +#endif + +HRESULT (WINAPI *pCreatePseudoConsole)(COORD, HANDLE, HANDLE, DWORD, HPCON *); +HRESULT (WINAPI *pResizePseudoConsole)(HPCON, COORD); +void (WINAPI *pClosePseudoConsole)(HPCON); + +bool os_has_conpty_working(void) +{ + static TriState has_conpty = kNone; + if (has_conpty == kNone) { + has_conpty = os_dyn_conpty_init(); + } + + return has_conpty == kTrue; +} + +TriState os_dyn_conpty_init(void) +{ + uv_lib_t kernel; + if (uv_dlopen("kernel32.dll", &kernel)) { + uv_dlclose(&kernel); + return kFalse; + } + static struct { + char *name; + FARPROC *ptr; + } conpty_entry[] = { + { "CreatePseudoConsole", (FARPROC *)&pCreatePseudoConsole }, + { "ResizePseudoConsole", (FARPROC *)&pResizePseudoConsole }, + { "ClosePseudoConsole", (FARPROC *)&pClosePseudoConsole }, + { NULL, NULL } + }; + for (int i = 0; + conpty_entry[i].name != NULL && conpty_entry[i].ptr != NULL; i++) { + if (uv_dlsym(&kernel, conpty_entry[i].name, (void **)conpty_entry[i].ptr)) { + uv_dlclose(&kernel); + return kFalse; + } + } + return kTrue; +} + +conpty_t *os_conpty_init(char **in_name, char **out_name, + uint16_t width, uint16_t height) +{ + static int count = 0; + conpty_t *conpty_object = xcalloc(1, sizeof(*conpty_object)); + const char *emsg = NULL; + HANDLE in_read = INVALID_HANDLE_VALUE; + HANDLE out_write = INVALID_HANDLE_VALUE; + char buf[MAXPATHL]; + SECURITY_ATTRIBUTES sa = { 0 }; + const DWORD mode = PIPE_ACCESS_INBOUND + | PIPE_ACCESS_OUTBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE; + + sa.nLength = sizeof(sa); + snprintf(buf, sizeof(buf), "\\\\.\\pipe\\nvim-term-in-%d-%d", + os_get_pid(), count); + *in_name = xstrdup(buf); + if ((in_read = CreateNamedPipeA( + *in_name, + mode, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + 1, + 0, + 0, + 30000, + &sa)) == INVALID_HANDLE_VALUE) { + emsg = "create input pipe failed"; + goto failed; + } + snprintf(buf, sizeof(buf), "\\\\.\\pipe\\nvim-term-out-%d-%d", + os_get_pid(), count); + *out_name = xstrdup(buf); + if ((out_write = CreateNamedPipeA( + *out_name, + mode, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + 1, + 0, + 0, + 30000, + &sa)) == INVALID_HANDLE_VALUE) { + emsg = "create output pipe failed"; + goto failed; + } + assert(width <= SHRT_MAX); + assert(height <= SHRT_MAX); + COORD size = { (int16_t)width, (int16_t)height }; + HRESULT hr; + hr = pCreatePseudoConsole(size, in_read, out_write, 0, &conpty_object->pty); + if (FAILED(hr)) { + emsg = "create psudo console failed"; + goto failed; + } + + conpty_object->si_ex.StartupInfo.cb = sizeof(conpty_object->si_ex); + size_t bytes_required; + InitializeProcThreadAttributeList(NULL, 1, 0, & bytes_required); + conpty_object->si_ex.lpAttributeList = + (PPROC_THREAD_ATTRIBUTE_LIST)xmalloc(bytes_required); + if (!InitializeProcThreadAttributeList( + conpty_object->si_ex.lpAttributeList, + 1, + 0, + &bytes_required)) { + emsg = "InitializeProcThreadAttributeList failed"; + goto failed; + } + if (!UpdateProcThreadAttribute( + conpty_object->si_ex.lpAttributeList, + 0, + PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, + conpty_object->pty, + sizeof(conpty_object->pty), + NULL, + NULL)) { + emsg = "UpdateProcThreadAttribute failed"; + goto failed; + } + count++; + goto finished; + +failed: + ELOG("os_conpty_init:%s : error code: %d", + emsg, os_translate_sys_error((int)GetLastError())); + os_conpty_free(conpty_object); + conpty_object = NULL; +finished: + if (in_read != INVALID_HANDLE_VALUE) { + CloseHandle(in_read); + } + if (out_write != INVALID_HANDLE_VALUE) { + CloseHandle(out_write); + } + return conpty_object; +} + +bool os_conpty_spawn(conpty_t *conpty_object, HANDLE *process_handle, + wchar_t *name, wchar_t *cmd_line, wchar_t *cwd, + wchar_t *env) +{ + PROCESS_INFORMATION pi = { 0 }; + if (!CreateProcessW( + name, + cmd_line, + NULL, + NULL, + false, + EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, + env, + cwd, + &conpty_object->si_ex.StartupInfo, + &pi)) { + return false; + } + *process_handle = pi.hProcess; + return true; +} + +void os_conpty_set_size(conpty_t *conpty_object, + uint16_t width, uint16_t height) +{ + assert(width <= SHRT_MAX); + assert(height <= SHRT_MAX); + COORD size = { (int16_t)width, (int16_t)height }; + if (pResizePseudoConsole(conpty_object->pty, size) != S_OK) { + ELOG("ResizePseudoConsoel failed: error code: %d", + os_translate_sys_error((int)GetLastError())); + } +} + +void os_conpty_free(conpty_t *conpty_object) +{ + if (conpty_object != NULL) { + if (conpty_object->si_ex.lpAttributeList != NULL) { + DeleteProcThreadAttributeList(conpty_object->si_ex.lpAttributeList); + xfree(conpty_object->si_ex.lpAttributeList); + } + if (conpty_object->pty != NULL) { + pClosePseudoConsole(conpty_object->pty); + } + } + xfree(conpty_object); +} diff --git a/src/nvim/os/pty_conpty_win.h b/src/nvim/os/pty_conpty_win.h new file mode 100644 index 0000000000..c243db4fa5 --- /dev/null +++ b/src/nvim/os/pty_conpty_win.h @@ -0,0 +1,22 @@ +#ifndef NVIM_OS_PTY_CONPTY_WIN_H +#define NVIM_OS_PTY_CONPTY_WIN_H + +#ifndef HPCON +# define HPCON VOID * +#endif + +extern HRESULT (WINAPI *pCreatePseudoConsole) // NOLINT(whitespace/parens) + (COORD, HANDLE, HANDLE, DWORD, HPCON *); +extern HRESULT (WINAPI *pResizePseudoConsole)(HPCON, COORD); +extern void (WINAPI *pClosePseudoConsole)(HPCON); + +typedef struct conpty { + HPCON pty; + STARTUPINFOEXW si_ex; +} conpty_t; + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "os/pty_conpty_win.h.generated.h" +#endif + +#endif // NVIM_OS_PTY_CONPTY_WIN_H diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c index 183219bd3e..6f7100e846 100644 --- a/src/nvim/os/pty_process_win.c +++ b/src/nvim/os/pty_process_win.c @@ -12,6 +12,7 @@ #include "nvim/memory.h" #include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8 #include "nvim/os/pty_process_win.h" +#include "nvim/os/pty_conpty_win.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/pty_process_win.c.generated.h" @@ -23,6 +24,11 @@ static void CALLBACK pty_process_finish1(void *context, BOOLEAN unused) PtyProcess *ptyproc = (PtyProcess *)context; Process *proc = (Process *)ptyproc; + if (ptyproc->type == kConpty + && ptyproc->object.conpty != NULL) { + os_conpty_free(ptyproc->object.conpty); + ptyproc->object.conpty = NULL; + } uv_timer_init(&proc->loop->uv, &ptyproc->wait_eof_timer); ptyproc->wait_eof_timer.data = (void *)ptyproc; uv_timer_start(&ptyproc->wait_eof_timer, wait_eof_timer_cb, 200, 200); @@ -38,6 +44,7 @@ int pty_process_spawn(PtyProcess *ptyproc) winpty_config_t *cfg = NULL; winpty_spawn_config_t *spawncfg = NULL; winpty_t *winpty_object = NULL; + conpty_t *conpty_object = NULL; char *in_name = NULL; char *out_name = NULL; HANDLE process_handle = NULL; @@ -49,29 +56,39 @@ int pty_process_spawn(PtyProcess *ptyproc) assert(proc->err.closed); - cfg = winpty_config_new(WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION, &err); - if (cfg == NULL) { - emsg = "winpty_config_new failed"; - goto cleanup; + if (os_has_conpty_working()) { + if ((conpty_object = + os_conpty_init(&in_name, &out_name, + ptyproc->width, ptyproc->height)) != NULL) { + ptyproc->type = kConpty; + } } - winpty_config_set_initial_size(cfg, ptyproc->width, ptyproc->height); - winpty_object = winpty_open(cfg, &err); - if (winpty_object == NULL) { - emsg = "winpty_open failed"; - goto cleanup; - } + if (ptyproc->type == kWinpty) { + cfg = winpty_config_new(WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION, &err); + if (cfg == NULL) { + emsg = "winpty_config_new failed"; + goto cleanup; + } - status = utf16_to_utf8(winpty_conin_name(winpty_object), -1, &in_name); - if (status != 0) { - emsg = "utf16_to_utf8(winpty_conin_name) failed"; - goto cleanup; - } + winpty_config_set_initial_size(cfg, ptyproc->width, ptyproc->height); + winpty_object = winpty_open(cfg, &err); + if (winpty_object == NULL) { + emsg = "winpty_open failed"; + goto cleanup; + } - status = utf16_to_utf8(winpty_conout_name(winpty_object), -1, &out_name); - if (status != 0) { - emsg = "utf16_to_utf8(winpty_conout_name) failed"; - goto cleanup; + status = utf16_to_utf8(winpty_conin_name(winpty_object), -1, &in_name); + if (status != 0) { + emsg = "utf16_to_utf8(winpty_conin_name) failed"; + goto cleanup; + } + + status = utf16_to_utf8(winpty_conout_name(winpty_object), -1, &out_name); + if (status != 0) { + emsg = "utf16_to_utf8(winpty_conout_name) failed"; + goto cleanup; + } } if (!proc->in.closed) { @@ -107,32 +124,45 @@ int pty_process_spawn(PtyProcess *ptyproc) goto cleanup; } - spawncfg = winpty_spawn_config_new( - WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN, - NULL, // Optional application name - cmd_line, - cwd, - NULL, // Optional environment variables - &err); - if (spawncfg == NULL) { - emsg = "winpty_spawn_config_new failed"; - goto cleanup; - } + if (ptyproc->type == kConpty) { + if (!os_conpty_spawn(conpty_object, + &process_handle, + NULL, + cmd_line, + cwd, + NULL)) { + emsg = "os_conpty_spawn failed"; + status = (int)GetLastError(); + goto cleanup; + } + } else { + spawncfg = winpty_spawn_config_new( + WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN, + NULL, // Optional application name + cmd_line, + cwd, + NULL, // Optional environment variables + &err); + if (spawncfg == NULL) { + emsg = "winpty_spawn_config_new failed"; + goto cleanup; + } - DWORD win_err = 0; - if (!winpty_spawn(winpty_object, - spawncfg, - &process_handle, - NULL, // Optional thread handle - &win_err, - &err)) { - if (win_err) { - status = (int)win_err; - emsg = "failed to spawn process"; - } else { - emsg = "winpty_spawn failed"; + DWORD win_err = 0; + if (!winpty_spawn(winpty_object, + spawncfg, + &process_handle, + NULL, // Optional thread handle + &win_err, + &err)) { + if (win_err) { + status = (int)win_err; + emsg = "failed to spawn process"; + } else { + emsg = "winpty_spawn failed"; + } + goto cleanup; } - goto cleanup; } proc->pid = (int)GetProcessId(process_handle); @@ -152,9 +182,12 @@ int pty_process_spawn(PtyProcess *ptyproc) uv_run(&proc->loop->uv, UV_RUN_ONCE); } - ptyproc->winpty_object = winpty_object; + (ptyproc->type == kConpty) ? + (void *)(ptyproc->object.conpty = conpty_object) : + (void *)(ptyproc->object.winpty = winpty_object); ptyproc->process_handle = process_handle; winpty_object = NULL; + conpty_object = NULL; process_handle = NULL; cleanup: @@ -171,6 +204,7 @@ cleanup: winpty_config_free(cfg); winpty_spawn_config_free(spawncfg); winpty_free(winpty_object); + os_conpty_free(conpty_object); xfree(in_name); xfree(out_name); if (process_handle != NULL) { @@ -192,8 +226,11 @@ void pty_process_resize(PtyProcess *ptyproc, uint16_t width, uint16_t height) FUNC_ATTR_NONNULL_ALL { - if (ptyproc->winpty_object != NULL) { - winpty_set_size(ptyproc->winpty_object, width, height, NULL); + if (ptyproc->type == kConpty + && ptyproc->object.conpty != NULL) { + os_conpty_set_size(ptyproc->object.conpty, width, height); + } else if (ptyproc->object.winpty != NULL) { + winpty_set_size(ptyproc->object.winpty, width, height, NULL); } } @@ -212,9 +249,10 @@ void pty_process_close(PtyProcess *ptyproc) void pty_process_close_master(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL { - if (ptyproc->winpty_object != NULL) { - winpty_free(ptyproc->winpty_object); - ptyproc->winpty_object = NULL; + if (ptyproc->type == kWinpty + && ptyproc->object.winpty != NULL) { + winpty_free(ptyproc->object.winpty); + ptyproc->object.winpty = NULL; } } diff --git a/src/nvim/os/pty_process_win.h b/src/nvim/os/pty_process_win.h index 1a4019e654..8ad5ba7286 100644 --- a/src/nvim/os/pty_process_win.h +++ b/src/nvim/os/pty_process_win.h @@ -6,12 +6,22 @@ #include "nvim/event/process.h" #include "nvim/lib/queue.h" +#include "nvim/os/pty_conpty_win.h" + +typedef enum { + kWinpty, + kConpty +} PtyType; typedef struct pty_process { Process process; char *term_name; uint16_t width, height; - winpty_t *winpty_object; + union { + winpty_t *winpty; + conpty_t *conpty; + } object; + PtyType type; HANDLE finish_wait; HANDLE process_handle; uv_timer_t wait_eof_timer; @@ -30,7 +40,8 @@ static inline PtyProcess pty_process_init(Loop *loop, void *data) rv.term_name = NULL; rv.width = 80; rv.height = 24; - rv.winpty_object = NULL; + rv.object.winpty = NULL; + rv.type = kWinpty; rv.finish_wait = NULL; rv.process_handle = NULL; return rv; diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index c71378463f..951cb50c3c 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -14,6 +14,9 @@ #include "nvim/option.h" #include "nvim/os/os.h" #include "nvim/os/input.h" +#ifdef WIN32 +# include "nvim/os/os_win_console.h" +#endif #include "nvim/event/rstream.h" #define KEY_BUFFER_SIZE 0xfff @@ -37,13 +40,7 @@ void tinput_init(TermInput *input, Loop *loop) // ls *.md | xargs nvim #ifdef WIN32 if (!os_isatty(input->in_fd)) { - const HANDLE conin_handle = CreateFile("CONIN$", - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - (LPSECURITY_ATTRIBUTES)NULL, - OPEN_EXISTING, 0, (HANDLE)NULL); - input->in_fd = _open_osfhandle(conin_handle, _O_RDONLY); - assert(input->in_fd != -1); + input->in_fd = os_get_conin_fd(); } #else if (!os_isatty(input->in_fd) && os_isatty(STDERR_FILENO)) { |