From 5355cee77d7b3b62917036281406726832b6d7dc Mon Sep 17 00:00:00 2001 From: erw7 Date: Sat, 9 Nov 2019 15:46:12 +0900 Subject: Change to use ConPTY, if available --- src/nvim/os/os_win_conpty.c | 181 ++++++++++++++++++++++++++++++++++++++++++ src/nvim/os/os_win_conpty.h | 22 +++++ src/nvim/os/pty_process_win.c | 146 ++++++++++++++++++++++------------ src/nvim/os/pty_process_win.h | 15 +++- 4 files changed, 313 insertions(+), 51 deletions(-) create mode 100644 src/nvim/os/os_win_conpty.c create mode 100644 src/nvim/os/os_win_conpty.h (limited to 'src/nvim/os') diff --git a/src/nvim/os/os_win_conpty.c b/src/nvim/os/os_win_conpty.c new file mode 100644 index 0000000000..9c6b7ad40f --- /dev/null +++ b/src/nvim/os/os_win_conpty.c @@ -0,0 +1,181 @@ +#include + +#include "nvim/vim.h" +#include "nvim/os/os.h" +#include "nvim/os/os_win_conpty.h" + +#ifndef EXTENDED_STARTUPINFO_PRESENT +# define EXTENDED_STARTUPINFO_PRESENT 0x00080000 +#endif +#ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE +# define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x00020016 +#endif + +static bool conpty_working = false; + +HRESULT (WINAPI *pCreatePseudoConsole)(COORD, HANDLE, HANDLE, DWORD, HPCON *); +HRESULT (WINAPI *pResizePseudoConsole)(HPCON, COORD); +HRESULT (WINAPI *pClosePseudoConsole)(HPCON); + +bool os_has_conpty_working(void) +{ + return conpty_working; +} + +void os_dyn_conpty_init(void) +{ + uv_lib_t kernel; + if (uv_dlopen("kernel32.dll", &kernel)) { + uv_dlclose(&kernel); + return; + } + 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; + } + } + conpty_working = true; +} + +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_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/os_win_conpty.h b/src/nvim/os/os_win_conpty.h new file mode 100644 index 0000000000..8e34d394a5 --- /dev/null +++ b/src/nvim/os/os_win_conpty.h @@ -0,0 +1,22 @@ +#ifndef NVIM_OS_OS_WIN_CONPTY_H +#define NVIM_OS_OS_WIN_CONPTY_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 HRESULT (WINAPI *pClosePseudoConsole)(HPCON); + +typedef struct conpty { + HPCON pty; + STARTUPINFOEXW si_ex; +} conpty_t; + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "os/os_win_conpty.h.generated.h" +#endif + +#endif // NVIM_OS_OS_WIN_CONPTY_H diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c index 183219bd3e..f48fef76d3 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/os_win_conpty.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 == PTY_TYPE_CONPTY + && ptyproc->pty_object.conpty_object != NULL) { + os_conpty_free(ptyproc->pty_object.conpty_object); + ptyproc->pty_object.conpty_object = 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,40 @@ 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; + int pty_type = *p_twt; + if (pty_type == 'c' && os_has_conpty_working()) { + if ((conpty_object = + os_conpty_init(&in_name, &out_name, + ptyproc->width, ptyproc->height)) != NULL) { + ptyproc->type = PTY_TYPE_CONPTY; + } } - 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 == PTY_TYPE_WINPTY) { + 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 +125,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 == PTY_TYPE_CONPTY) { + 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 +183,14 @@ int pty_process_spawn(PtyProcess *ptyproc) uv_run(&proc->loop->uv, UV_RUN_ONCE); } - ptyproc->winpty_object = winpty_object; + if (ptyproc->type == PTY_TYPE_CONPTY) { + ptyproc->pty_object.conpty_object = conpty_object; + } else { + ptyproc->pty_object.winpty_object = winpty_object; + } ptyproc->process_handle = process_handle; winpty_object = NULL; + conpty_object = NULL; process_handle = NULL; cleanup: @@ -171,6 +207,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 +229,18 @@ 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 == PTY_TYPE_CONPTY + && ptyproc->pty_object.conpty_object != NULL) { + assert(width <= SHRT_MAX); + assert(height <= SHRT_MAX); + COORD size = { (int16_t)width, (int16_t)height }; + if (pResizePseudoConsole( + ptyproc->pty_object.conpty_object->pty, size) != S_OK) { + ELOG("ResizePseudoConsoel failed: error code: %d", + os_translate_sys_error((int)GetLastError())); + } + } else if (ptyproc->pty_object.winpty_object != NULL) { + winpty_set_size(ptyproc->pty_object.winpty_object, width, height, NULL); } } @@ -212,9 +259,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 == PTY_TYPE_WINPTY + && ptyproc->pty_object.winpty_object != NULL) { + winpty_free(ptyproc->pty_object.winpty_object); + ptyproc->pty_object.winpty_object = NULL; } } diff --git a/src/nvim/os/pty_process_win.h b/src/nvim/os/pty_process_win.h index 1a4019e654..49a0d420ad 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/os_win_conpty.h" + +typedef enum { + PTY_TYPE_WINPTY, + PTY_TYPE_CONPTY +} pty_type_t; typedef struct pty_process { Process process; char *term_name; uint16_t width, height; - winpty_t *winpty_object; + union { + winpty_t *winpty_object; + conpty_t *conpty_object; + } pty_object; + pty_type_t 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.pty_object.winpty_object = NULL; + rv.type = PTY_TYPE_WINPTY; rv.finish_wait = NULL; rv.process_handle = NULL; return rv; -- cgit From ed37d1081c8adbd33832b4140ba5368fa876bdb8 Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 15 Nov 2019 12:51:41 +0900 Subject: Change union name from pty_object to object Co-Authored-By: Justin M. Keyes --- src/nvim/os/pty_process_win.c | 24 ++++++++++++------------ src/nvim/os/pty_process_win.h | 8 ++++---- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'src/nvim/os') diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c index f48fef76d3..0fbe3e5fad 100644 --- a/src/nvim/os/pty_process_win.c +++ b/src/nvim/os/pty_process_win.c @@ -25,9 +25,9 @@ static void CALLBACK pty_process_finish1(void *context, BOOLEAN unused) Process *proc = (Process *)ptyproc; if (ptyproc->type == PTY_TYPE_CONPTY - && ptyproc->pty_object.conpty_object != NULL) { - os_conpty_free(ptyproc->pty_object.conpty_object); - ptyproc->pty_object.conpty_object = NULL; + && 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; @@ -184,9 +184,9 @@ int pty_process_spawn(PtyProcess *ptyproc) } if (ptyproc->type == PTY_TYPE_CONPTY) { - ptyproc->pty_object.conpty_object = conpty_object; + ptyproc->object.conpty = conpty_object; } else { - ptyproc->pty_object.winpty_object = winpty_object; + ptyproc->object.winpty = winpty_object; } ptyproc->process_handle = process_handle; winpty_object = NULL; @@ -230,17 +230,17 @@ void pty_process_resize(PtyProcess *ptyproc, uint16_t width, FUNC_ATTR_NONNULL_ALL { if (ptyproc->type == PTY_TYPE_CONPTY - && ptyproc->pty_object.conpty_object != NULL) { + && ptyproc->object.conpty != NULL) { assert(width <= SHRT_MAX); assert(height <= SHRT_MAX); COORD size = { (int16_t)width, (int16_t)height }; if (pResizePseudoConsole( - ptyproc->pty_object.conpty_object->pty, size) != S_OK) { + ptyproc->object.conpty->pty, size) != S_OK) { ELOG("ResizePseudoConsoel failed: error code: %d", os_translate_sys_error((int)GetLastError())); } - } else if (ptyproc->pty_object.winpty_object != NULL) { - winpty_set_size(ptyproc->pty_object.winpty_object, width, height, NULL); + } else if (ptyproc->object.winpty != NULL) { + winpty_set_size(ptyproc->object.winpty, width, height, NULL); } } @@ -260,9 +260,9 @@ void pty_process_close_master(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL { if (ptyproc->type == PTY_TYPE_WINPTY - && ptyproc->pty_object.winpty_object != NULL) { - winpty_free(ptyproc->pty_object.winpty_object); - ptyproc->pty_object.winpty_object = NULL; + && 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 49a0d420ad..c7eaa23b1b 100644 --- a/src/nvim/os/pty_process_win.h +++ b/src/nvim/os/pty_process_win.h @@ -18,9 +18,9 @@ typedef struct pty_process { char *term_name; uint16_t width, height; union { - winpty_t *winpty_object; - conpty_t *conpty_object; - } pty_object; + winpty_t *winpty; + conpty_t *conpty; + } object; pty_type_t type; HANDLE finish_wait; HANDLE process_handle; @@ -40,7 +40,7 @@ static inline PtyProcess pty_process_init(Loop *loop, void *data) rv.term_name = NULL; rv.width = 80; rv.height = 24; - rv.pty_object.winpty_object = NULL; + rv.object.winpty = NULL; rv.type = PTY_TYPE_WINPTY; rv.finish_wait = NULL; rv.process_handle = NULL; -- cgit From 7aff0340e1f0550ff1c04dc17474d7cb6e57a89b Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 15 Nov 2019 13:03:25 +0900 Subject: Move ConPTY resize to os_win_conpty.c --- src/nvim/os/os_win_conpty.c | 14 +++++++++++++- src/nvim/os/pty_process_win.c | 9 +-------- 2 files changed, 14 insertions(+), 9 deletions(-) (limited to 'src/nvim/os') diff --git a/src/nvim/os/os_win_conpty.c b/src/nvim/os/os_win_conpty.c index 9c6b7ad40f..bf6ec62818 100644 --- a/src/nvim/os/os_win_conpty.c +++ b/src/nvim/os/os_win_conpty.c @@ -166,7 +166,19 @@ bool os_conpty_spawn(conpty_t *conpty_object, HANDLE *process_handle, return true; } -void os_conpty_free(conpty_t * conpty_object) +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) { diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c index 0fbe3e5fad..ffdececf94 100644 --- a/src/nvim/os/pty_process_win.c +++ b/src/nvim/os/pty_process_win.c @@ -231,14 +231,7 @@ void pty_process_resize(PtyProcess *ptyproc, uint16_t width, { if (ptyproc->type == PTY_TYPE_CONPTY && ptyproc->object.conpty != NULL) { - assert(width <= SHRT_MAX); - assert(height <= SHRT_MAX); - COORD size = { (int16_t)width, (int16_t)height }; - if (pResizePseudoConsole( - ptyproc->object.conpty->pty, size) != S_OK) { - ELOG("ResizePseudoConsoel failed: error code: %d", - os_translate_sys_error((int)GetLastError())); - } + os_conpty_set_size(ptyproc->object.conpty, width, height); } else if (ptyproc->object.winpty != NULL) { winpty_set_size(ptyproc->object.winpty, width, height, NULL); } -- cgit From b4ff583277ce16584f20868cef6697f52bebc7d4 Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 15 Nov 2019 13:12:48 +0900 Subject: Minor changes in reviewer's point --- src/nvim/os/os_win_conpty.c | 3 +++ src/nvim/os/pty_process_win.c | 8 +++----- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src/nvim/os') diff --git a/src/nvim/os/os_win_conpty.c b/src/nvim/os/os_win_conpty.c index bf6ec62818..887286b59f 100644 --- a/src/nvim/os/os_win_conpty.c +++ b/src/nvim/os/os_win_conpty.c @@ -1,3 +1,6 @@ +// 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 #include "nvim/vim.h" diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c index ffdececf94..0cd730401a 100644 --- a/src/nvim/os/pty_process_win.c +++ b/src/nvim/os/pty_process_win.c @@ -183,11 +183,9 @@ int pty_process_spawn(PtyProcess *ptyproc) uv_run(&proc->loop->uv, UV_RUN_ONCE); } - if (ptyproc->type == PTY_TYPE_CONPTY) { - ptyproc->object.conpty = conpty_object; - } else { - ptyproc->object.winpty = winpty_object; - } + (ptyproc->type == PTY_TYPE_CONPTY) ? + (void *)(ptyproc->object.conpty = conpty_object) : + (void *)(ptyproc->object.winpty = winpty_object); ptyproc->process_handle = process_handle; winpty_object = NULL; conpty_object = NULL; -- cgit From b25e42f7989aa0a071e3132ce992ab9a6251594e Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 15 Nov 2019 14:42:49 +0900 Subject: Fix function prototype --- src/nvim/os/os_win_conpty.c | 2 +- src/nvim/os/os_win_conpty.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/os') diff --git a/src/nvim/os/os_win_conpty.c b/src/nvim/os/os_win_conpty.c index 887286b59f..a73b1b65a0 100644 --- a/src/nvim/os/os_win_conpty.c +++ b/src/nvim/os/os_win_conpty.c @@ -18,7 +18,7 @@ static bool conpty_working = false; HRESULT (WINAPI *pCreatePseudoConsole)(COORD, HANDLE, HANDLE, DWORD, HPCON *); HRESULT (WINAPI *pResizePseudoConsole)(HPCON, COORD); -HRESULT (WINAPI *pClosePseudoConsole)(HPCON); +void (WINAPI *pClosePseudoConsole)(HPCON); bool os_has_conpty_working(void) { diff --git a/src/nvim/os/os_win_conpty.h b/src/nvim/os/os_win_conpty.h index 8e34d394a5..8a5f45e2cd 100644 --- a/src/nvim/os/os_win_conpty.h +++ b/src/nvim/os/os_win_conpty.h @@ -8,7 +8,7 @@ extern HRESULT (WINAPI *pCreatePseudoConsole) // NOLINT(whitespace/parens) (COORD, HANDLE, HANDLE, DWORD, HPCON *); extern HRESULT (WINAPI *pResizePseudoConsole)(HPCON, COORD); -extern HRESULT (WINAPI *pClosePseudoConsole)(HPCON); +extern void (WINAPI *pClosePseudoConsole)(HPCON); typedef struct conpty { HPCON pty; -- cgit From 59ae38a9196d596e2fe511eeb216e314bfc3dac7 Mon Sep 17 00:00:00 2001 From: erw7 Date: Sat, 16 Nov 2019 12:59:07 +0900 Subject: Change to use TriState instead of bool Co-Authored-By: Justin M. Keyes --- src/nvim/os/os_win_conpty.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'src/nvim/os') diff --git a/src/nvim/os/os_win_conpty.c b/src/nvim/os/os_win_conpty.c index a73b1b65a0..3d5ba83523 100644 --- a/src/nvim/os/os_win_conpty.c +++ b/src/nvim/os/os_win_conpty.c @@ -14,23 +14,26 @@ # define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x00020016 #endif -static bool conpty_working = false; - HRESULT (WINAPI *pCreatePseudoConsole)(COORD, HANDLE, HANDLE, DWORD, HPCON *); HRESULT (WINAPI *pResizePseudoConsole)(HPCON, COORD); void (WINAPI *pClosePseudoConsole)(HPCON); bool os_has_conpty_working(void) { - return conpty_working; + static TriState has_conpty = kNone; + if (has_conpty == kNone) { + has_conpty = os_dyn_conpty_init(); + } + + return has_conpty == kTrue; } -void os_dyn_conpty_init(void) +TriState os_dyn_conpty_init(void) { uv_lib_t kernel; if (uv_dlopen("kernel32.dll", &kernel)) { uv_dlclose(&kernel); - return; + return kFalse; } static struct { char *name; @@ -45,10 +48,10 @@ void os_dyn_conpty_init(void) 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; + return kFalse; } } - conpty_working = true; + return kTrue; } conpty_t *os_conpty_init(char **in_name, char **out_name, -- cgit From 60c7eabb2feeb95f405deca6680bdd59113edcaa Mon Sep 17 00:00:00 2001 From: erw7 Date: Sat, 16 Nov 2019 13:16:52 +0900 Subject: Change enum to a name that follows naming convention --- src/nvim/os/pty_process_win.c | 14 +++++++------- src/nvim/os/pty_process_win.h | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src/nvim/os') diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c index 0cd730401a..7108d9c049 100644 --- a/src/nvim/os/pty_process_win.c +++ b/src/nvim/os/pty_process_win.c @@ -24,7 +24,7 @@ static void CALLBACK pty_process_finish1(void *context, BOOLEAN unused) PtyProcess *ptyproc = (PtyProcess *)context; Process *proc = (Process *)ptyproc; - if (ptyproc->type == PTY_TYPE_CONPTY + if (ptyproc->type == kConpty && ptyproc->object.conpty != NULL) { os_conpty_free(ptyproc->object.conpty); ptyproc->object.conpty = NULL; @@ -61,11 +61,11 @@ int pty_process_spawn(PtyProcess *ptyproc) if ((conpty_object = os_conpty_init(&in_name, &out_name, ptyproc->width, ptyproc->height)) != NULL) { - ptyproc->type = PTY_TYPE_CONPTY; + ptyproc->type = kConpty; } } - if (ptyproc->type == PTY_TYPE_WINPTY) { + if (ptyproc->type == kWinpty) { cfg = winpty_config_new(WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION, &err); if (cfg == NULL) { emsg = "winpty_config_new failed"; @@ -125,7 +125,7 @@ int pty_process_spawn(PtyProcess *ptyproc) goto cleanup; } - if (ptyproc->type == PTY_TYPE_CONPTY) { + if (ptyproc->type == kConpty) { if (!os_conpty_spawn(conpty_object, &process_handle, NULL, @@ -183,7 +183,7 @@ int pty_process_spawn(PtyProcess *ptyproc) uv_run(&proc->loop->uv, UV_RUN_ONCE); } - (ptyproc->type == PTY_TYPE_CONPTY) ? + (ptyproc->type == kConpty) ? (void *)(ptyproc->object.conpty = conpty_object) : (void *)(ptyproc->object.winpty = winpty_object); ptyproc->process_handle = process_handle; @@ -227,7 +227,7 @@ void pty_process_resize(PtyProcess *ptyproc, uint16_t width, uint16_t height) FUNC_ATTR_NONNULL_ALL { - if (ptyproc->type == PTY_TYPE_CONPTY + if (ptyproc->type == kConpty && ptyproc->object.conpty != NULL) { os_conpty_set_size(ptyproc->object.conpty, width, height); } else if (ptyproc->object.winpty != NULL) { @@ -250,7 +250,7 @@ void pty_process_close(PtyProcess *ptyproc) void pty_process_close_master(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL { - if (ptyproc->type == PTY_TYPE_WINPTY + 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 c7eaa23b1b..04c8439c6c 100644 --- a/src/nvim/os/pty_process_win.h +++ b/src/nvim/os/pty_process_win.h @@ -9,9 +9,9 @@ #include "nvim/os/os_win_conpty.h" typedef enum { - PTY_TYPE_WINPTY, - PTY_TYPE_CONPTY -} pty_type_t; + kWinpty, + kConpty +} PtyType; typedef struct pty_process { Process process; @@ -21,7 +21,7 @@ typedef struct pty_process { winpty_t *winpty; conpty_t *conpty; } object; - pty_type_t type; + PtyType type; HANDLE finish_wait; HANDLE process_handle; uv_timer_t wait_eof_timer; @@ -41,7 +41,7 @@ static inline PtyProcess pty_process_init(Loop *loop, void *data) rv.width = 80; rv.height = 24; rv.object.winpty = NULL; - rv.type = PTY_TYPE_WINPTY; + rv.type = kWinpty; rv.finish_wait = NULL; rv.process_handle = NULL; return rv; -- cgit From 2c8016c7048051da9afd809b580cf8f2d2c69614 Mon Sep 17 00:00:00 2001 From: erw7 Date: Sat, 16 Nov 2019 13:45:37 +0900 Subject: Add stdin, stdout replacement functions --- src/nvim/os/os_win_console.c | 38 ++++++++++++++++++++++++++++++++++++++ src/nvim/os/os_win_console.h | 8 ++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/nvim/os/os_win_console.c create mode 100644 src/nvim/os/os_win_console.h (limited to 'src/nvim/os') diff --git a/src/nvim/os/os_win_console.c b/src/nvim/os/os_win_console.c new file mode 100644 index 0000000000..50127248a4 --- /dev/null +++ b/src/nvim/os/os_win_console.c @@ -0,0 +1,38 @@ +// 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" + +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_to_conout(void) +{ + close(STDOUT_FILENO); + 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); + const int conout_fd = _open_osfhandle((intptr_t)conout_handle, 0); + assert(conout_fd == STDOUT_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 -- cgit From 8f91d709b0006e3fcfa4cb59abd9b77938096d76 Mon Sep 17 00:00:00 2001 From: erw7 Date: Sat, 16 Nov 2019 13:50:52 +0900 Subject: Rename from os_win_conpty.{c,h} to pty_conpty_win.{c,h} --- src/nvim/os/os_win_conpty.c | 199 ------------------------------------------ src/nvim/os/os_win_conpty.h | 22 ----- src/nvim/os/pty_conpty_win.c | 199 ++++++++++++++++++++++++++++++++++++++++++ src/nvim/os/pty_conpty_win.h | 22 +++++ src/nvim/os/pty_process_win.c | 2 +- src/nvim/os/pty_process_win.h | 2 +- 6 files changed, 223 insertions(+), 223 deletions(-) delete mode 100644 src/nvim/os/os_win_conpty.c delete mode 100644 src/nvim/os/os_win_conpty.h create mode 100644 src/nvim/os/pty_conpty_win.c create mode 100644 src/nvim/os/pty_conpty_win.h (limited to 'src/nvim/os') diff --git a/src/nvim/os/os_win_conpty.c b/src/nvim/os/os_win_conpty.c deleted file mode 100644 index 3d5ba83523..0000000000 --- a/src/nvim/os/os_win_conpty.c +++ /dev/null @@ -1,199 +0,0 @@ -// 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 - -#include "nvim/vim.h" -#include "nvim/os/os.h" -#include "nvim/os/os_win_conpty.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/os_win_conpty.h b/src/nvim/os/os_win_conpty.h deleted file mode 100644 index 8a5f45e2cd..0000000000 --- a/src/nvim/os/os_win_conpty.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef NVIM_OS_OS_WIN_CONPTY_H -#define NVIM_OS_OS_WIN_CONPTY_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/os_win_conpty.h.generated.h" -#endif - -#endif // NVIM_OS_OS_WIN_CONPTY_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 + +#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 7108d9c049..64d4408ece 100644 --- a/src/nvim/os/pty_process_win.c +++ b/src/nvim/os/pty_process_win.c @@ -12,7 +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/os_win_conpty.h" +#include "nvim/os/pty_conpty_win.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/pty_process_win.c.generated.h" diff --git a/src/nvim/os/pty_process_win.h b/src/nvim/os/pty_process_win.h index 04c8439c6c..8ad5ba7286 100644 --- a/src/nvim/os/pty_process_win.h +++ b/src/nvim/os/pty_process_win.h @@ -6,7 +6,7 @@ #include "nvim/event/process.h" #include "nvim/lib/queue.h" -#include "nvim/os/os_win_conpty.h" +#include "nvim/os/pty_conpty_win.h" typedef enum { kWinpty, -- cgit From a5a3d7160d7cb70ef2477f243d7a537fc4fa20e8 Mon Sep 17 00:00:00 2001 From: erw7 Date: Sat, 16 Nov 2019 13:55:27 +0900 Subject: Change option name from termwintype to termtype --- src/nvim/os/pty_process_win.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/os') diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c index 64d4408ece..93f1656029 100644 --- a/src/nvim/os/pty_process_win.c +++ b/src/nvim/os/pty_process_win.c @@ -56,8 +56,8 @@ int pty_process_spawn(PtyProcess *ptyproc) assert(proc->err.closed); - int pty_type = *p_twt; - if (pty_type == 'c' && os_has_conpty_working()) { + int pty_type = *p_tmt; + if (pty_type != 'w' && os_has_conpty_working()) { if ((conpty_object = os_conpty_init(&in_name, &out_name, ptyproc->width, ptyproc->height)) != NULL) { -- cgit From 4e06594c53645c9b3dc6c57850f712a810d071d3 Mon Sep 17 00:00:00 2001 From: erw7 Date: Sun, 17 Nov 2019 12:20:24 +0900 Subject: Add missing include file --- src/nvim/os/os_win_console.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/os') diff --git a/src/nvim/os/os_win_console.c b/src/nvim/os/os_win_console.c index 50127248a4..6cabeb2c9a 100644 --- a/src/nvim/os/os_win_console.c +++ b/src/nvim/os/os_win_console.c @@ -2,6 +2,7 @@ // 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) { -- cgit From c86d5fa981b0651167f789aaff685b42cad7aaca Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 22 Nov 2019 13:51:14 +0900 Subject: Change to replace stderr with conout --- src/nvim/os/os_win_console.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/nvim/os') diff --git a/src/nvim/os/os_win_console.c b/src/nvim/os/os_win_console.c index 6cabeb2c9a..8a0aa2f5ae 100644 --- a/src/nvim/os/os_win_console.c +++ b/src/nvim/os/os_win_console.c @@ -24,9 +24,8 @@ void os_replace_stdin_to_conin(void) assert(conin_fd == STDIN_FILENO); } -void os_replace_stdout_to_conout(void) +void os_replace_stdout_and_stderr_to_conout(void) { - close(STDOUT_FILENO); const HANDLE conout_handle = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, @@ -34,6 +33,10 @@ void os_replace_stdout_to_conout(void) (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); } -- cgit From 1e4f29069146cbab0be0559d87e399aefa433a29 Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 22 Nov 2019 14:01:12 +0900 Subject: Remove termtype option --- src/nvim/os/pty_process_win.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/nvim/os') diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c index 93f1656029..6f7100e846 100644 --- a/src/nvim/os/pty_process_win.c +++ b/src/nvim/os/pty_process_win.c @@ -56,8 +56,7 @@ int pty_process_spawn(PtyProcess *ptyproc) assert(proc->err.closed); - int pty_type = *p_tmt; - if (pty_type != 'w' && os_has_conpty_working()) { + if (os_has_conpty_working()) { if ((conpty_object = os_conpty_init(&in_name, &out_name, ptyproc->width, ptyproc->height)) != NULL) { -- cgit