mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #11390 from erw7/feature-conpty
win/Terminal: Change to use ConPTY, if available
This commit is contained in:
commit
fd89ad7bfb
@ -134,6 +134,12 @@ foreach(sfile ${NVIM_SOURCES})
|
|||||||
if(NOT WIN32 AND ${f} MATCHES "^(pty_process_win.c)$")
|
if(NOT WIN32 AND ${f} MATCHES "^(pty_process_win.c)$")
|
||||||
list(APPEND to_remove ${sfile})
|
list(APPEND to_remove ${sfile})
|
||||||
endif()
|
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()
|
endforeach()
|
||||||
|
|
||||||
list(REMOVE_ITEM NVIM_SOURCES ${to_remove})
|
list(REMOVE_ITEM NVIM_SOURCES ${to_remove})
|
||||||
@ -637,6 +643,8 @@ endfunction()
|
|||||||
set(NO_SINGLE_CHECK_HEADERS
|
set(NO_SINGLE_CHECK_HEADERS
|
||||||
os/win_defs.h
|
os/win_defs.h
|
||||||
os/pty_process_win.h
|
os/pty_process_win.h
|
||||||
|
os/pty_conpty_win.h
|
||||||
|
os/os_win_console.h
|
||||||
)
|
)
|
||||||
foreach(hfile ${NVIM_HEADERS})
|
foreach(hfile ${NVIM_HEADERS})
|
||||||
get_test_target(test-includes "${hfile}" relative_path texe)
|
get_test_target(test-includes "${hfile}" relative_path texe)
|
||||||
|
@ -11,6 +11,10 @@
|
|||||||
#include "nvim/msgpack_rpc/channel.h"
|
#include "nvim/msgpack_rpc/channel.h"
|
||||||
#include "nvim/msgpack_rpc/server.h"
|
#include "nvim/msgpack_rpc/server.h"
|
||||||
#include "nvim/os/shell.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/path.h"
|
||||||
#include "nvim/ascii.h"
|
#include "nvim/ascii.h"
|
||||||
|
|
||||||
@ -469,8 +473,20 @@ uint64_t channel_from_stdio(bool rpc, CallbackReader on_output,
|
|||||||
|
|
||||||
Channel *channel = channel_alloc(kChannelStreamStdio);
|
Channel *channel = channel_alloc(kChannelStreamStdio);
|
||||||
|
|
||||||
rstream_init_fd(&main_loop, &channel->stream.stdio.in, 0, 0);
|
int stdin_dup_fd = STDIN_FILENO;
|
||||||
wstream_init_fd(&main_loop, &channel->stream.stdio.out, 1, 0);
|
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) {
|
if (rpc) {
|
||||||
rpc_start(channel);
|
rpc_start(channel);
|
||||||
|
@ -64,6 +64,9 @@
|
|||||||
#include "nvim/os/os.h"
|
#include "nvim/os/os.h"
|
||||||
#include "nvim/os/time.h"
|
#include "nvim/os/time.h"
|
||||||
#include "nvim/os/fileio.h"
|
#include "nvim/os/fileio.h"
|
||||||
|
#ifdef WIN32
|
||||||
|
# include "nvim/os/os_win_console.h"
|
||||||
|
#endif
|
||||||
#include "nvim/event/loop.h"
|
#include "nvim/event/loop.h"
|
||||||
#include "nvim/os/signal.h"
|
#include "nvim/os/signal.h"
|
||||||
#include "nvim/event/process.h"
|
#include "nvim/event/process.h"
|
||||||
@ -1120,13 +1123,7 @@ scripterror:
|
|||||||
const int stdin_dup_fd = os_dup(STDIN_FILENO);
|
const int stdin_dup_fd = os_dup(STDIN_FILENO);
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
// Replace the original stdin with the console input handle.
|
// Replace the original stdin with the console input handle.
|
||||||
close(STDIN_FILENO);
|
os_replace_stdin_to_conin();
|
||||||
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);
|
|
||||||
#endif
|
#endif
|
||||||
FileDescriptor *const stdin_dup = file_open_fd_new(
|
FileDescriptor *const stdin_dup = file_open_fd_new(
|
||||||
&error, stdin_dup_fd, kFileReadOnly|kFileNonBlocking);
|
&error, stdin_dup_fd, kFileReadOnly|kFileNonBlocking);
|
||||||
|
@ -76,6 +76,9 @@
|
|||||||
#include "nvim/undo.h"
|
#include "nvim/undo.h"
|
||||||
#include "nvim/window.h"
|
#include "nvim/window.h"
|
||||||
#include "nvim/os/os.h"
|
#include "nvim/os/os.h"
|
||||||
|
#ifdef WIN32
|
||||||
|
# include "nvim/os/pty_conpty_win.h"
|
||||||
|
#endif
|
||||||
#include "nvim/api/private/helpers.h"
|
#include "nvim/api/private/helpers.h"
|
||||||
#include "nvim/os/input.h"
|
#include "nvim/os/input.h"
|
||||||
#include "nvim/os/lang.h"
|
#include "nvim/os/lang.h"
|
||||||
|
42
src/nvim/os/os_win_console.c
Normal file
42
src/nvim/os/os_win_console.c
Normal file
@ -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);
|
||||||
|
}
|
8
src/nvim/os/os_win_console.h
Normal file
8
src/nvim/os/os_win_console.h
Normal file
@ -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
|
199
src/nvim/os/pty_conpty_win.c
Normal file
199
src/nvim/os/pty_conpty_win.c
Normal file
@ -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);
|
||||||
|
}
|
22
src/nvim/os/pty_conpty_win.h
Normal file
22
src/nvim/os/pty_conpty_win.h
Normal file
@ -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
|
@ -12,6 +12,7 @@
|
|||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8
|
#include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8
|
||||||
#include "nvim/os/pty_process_win.h"
|
#include "nvim/os/pty_process_win.h"
|
||||||
|
#include "nvim/os/pty_conpty_win.h"
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "os/pty_process_win.c.generated.h"
|
# 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;
|
PtyProcess *ptyproc = (PtyProcess *)context;
|
||||||
Process *proc = (Process *)ptyproc;
|
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);
|
uv_timer_init(&proc->loop->uv, &ptyproc->wait_eof_timer);
|
||||||
ptyproc->wait_eof_timer.data = (void *)ptyproc;
|
ptyproc->wait_eof_timer.data = (void *)ptyproc;
|
||||||
uv_timer_start(&ptyproc->wait_eof_timer, wait_eof_timer_cb, 200, 200);
|
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_config_t *cfg = NULL;
|
||||||
winpty_spawn_config_t *spawncfg = NULL;
|
winpty_spawn_config_t *spawncfg = NULL;
|
||||||
winpty_t *winpty_object = NULL;
|
winpty_t *winpty_object = NULL;
|
||||||
|
conpty_t *conpty_object = NULL;
|
||||||
char *in_name = NULL;
|
char *in_name = NULL;
|
||||||
char *out_name = NULL;
|
char *out_name = NULL;
|
||||||
HANDLE process_handle = NULL;
|
HANDLE process_handle = NULL;
|
||||||
@ -49,29 +56,39 @@ int pty_process_spawn(PtyProcess *ptyproc)
|
|||||||
|
|
||||||
assert(proc->err.closed);
|
assert(proc->err.closed);
|
||||||
|
|
||||||
cfg = winpty_config_new(WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION, &err);
|
if (os_has_conpty_working()) {
|
||||||
if (cfg == NULL) {
|
if ((conpty_object =
|
||||||
emsg = "winpty_config_new failed";
|
os_conpty_init(&in_name, &out_name,
|
||||||
goto cleanup;
|
ptyproc->width, ptyproc->height)) != NULL) {
|
||||||
|
ptyproc->type = kConpty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
winpty_config_set_initial_size(cfg, ptyproc->width, ptyproc->height);
|
if (ptyproc->type == kWinpty) {
|
||||||
winpty_object = winpty_open(cfg, &err);
|
cfg = winpty_config_new(WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION, &err);
|
||||||
if (winpty_object == NULL) {
|
if (cfg == NULL) {
|
||||||
emsg = "winpty_open failed";
|
emsg = "winpty_config_new failed";
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = utf16_to_utf8(winpty_conin_name(winpty_object), -1, &in_name);
|
winpty_config_set_initial_size(cfg, ptyproc->width, ptyproc->height);
|
||||||
if (status != 0) {
|
winpty_object = winpty_open(cfg, &err);
|
||||||
emsg = "utf16_to_utf8(winpty_conin_name) failed";
|
if (winpty_object == NULL) {
|
||||||
goto cleanup;
|
emsg = "winpty_open failed";
|
||||||
}
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
status = utf16_to_utf8(winpty_conout_name(winpty_object), -1, &out_name);
|
status = utf16_to_utf8(winpty_conin_name(winpty_object), -1, &in_name);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
emsg = "utf16_to_utf8(winpty_conout_name) failed";
|
emsg = "utf16_to_utf8(winpty_conin_name) failed";
|
||||||
goto cleanup;
|
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) {
|
if (!proc->in.closed) {
|
||||||
@ -107,32 +124,45 @@ int pty_process_spawn(PtyProcess *ptyproc)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
spawncfg = winpty_spawn_config_new(
|
if (ptyproc->type == kConpty) {
|
||||||
WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN,
|
if (!os_conpty_spawn(conpty_object,
|
||||||
NULL, // Optional application name
|
&process_handle,
|
||||||
cmd_line,
|
NULL,
|
||||||
cwd,
|
cmd_line,
|
||||||
NULL, // Optional environment variables
|
cwd,
|
||||||
&err);
|
NULL)) {
|
||||||
if (spawncfg == NULL) {
|
emsg = "os_conpty_spawn failed";
|
||||||
emsg = "winpty_spawn_config_new failed";
|
status = (int)GetLastError();
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
DWORD win_err = 0;
|
spawncfg = winpty_spawn_config_new(
|
||||||
if (!winpty_spawn(winpty_object,
|
WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN,
|
||||||
spawncfg,
|
NULL, // Optional application name
|
||||||
&process_handle,
|
cmd_line,
|
||||||
NULL, // Optional thread handle
|
cwd,
|
||||||
&win_err,
|
NULL, // Optional environment variables
|
||||||
&err)) {
|
&err);
|
||||||
if (win_err) {
|
if (spawncfg == NULL) {
|
||||||
status = (int)win_err;
|
emsg = "winpty_spawn_config_new failed";
|
||||||
emsg = "failed to spawn process";
|
goto cleanup;
|
||||||
} 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);
|
proc->pid = (int)GetProcessId(process_handle);
|
||||||
|
|
||||||
@ -152,9 +182,12 @@ int pty_process_spawn(PtyProcess *ptyproc)
|
|||||||
uv_run(&proc->loop->uv, UV_RUN_ONCE);
|
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;
|
ptyproc->process_handle = process_handle;
|
||||||
winpty_object = NULL;
|
winpty_object = NULL;
|
||||||
|
conpty_object = NULL;
|
||||||
process_handle = NULL;
|
process_handle = NULL;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@ -171,6 +204,7 @@ cleanup:
|
|||||||
winpty_config_free(cfg);
|
winpty_config_free(cfg);
|
||||||
winpty_spawn_config_free(spawncfg);
|
winpty_spawn_config_free(spawncfg);
|
||||||
winpty_free(winpty_object);
|
winpty_free(winpty_object);
|
||||||
|
os_conpty_free(conpty_object);
|
||||||
xfree(in_name);
|
xfree(in_name);
|
||||||
xfree(out_name);
|
xfree(out_name);
|
||||||
if (process_handle != NULL) {
|
if (process_handle != NULL) {
|
||||||
@ -192,8 +226,11 @@ void pty_process_resize(PtyProcess *ptyproc, uint16_t width,
|
|||||||
uint16_t height)
|
uint16_t height)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
if (ptyproc->winpty_object != NULL) {
|
if (ptyproc->type == kConpty
|
||||||
winpty_set_size(ptyproc->winpty_object, width, height, NULL);
|
&& 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)
|
void pty_process_close_master(PtyProcess *ptyproc)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
if (ptyproc->winpty_object != NULL) {
|
if (ptyproc->type == kWinpty
|
||||||
winpty_free(ptyproc->winpty_object);
|
&& ptyproc->object.winpty != NULL) {
|
||||||
ptyproc->winpty_object = NULL;
|
winpty_free(ptyproc->object.winpty);
|
||||||
|
ptyproc->object.winpty = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,12 +6,22 @@
|
|||||||
|
|
||||||
#include "nvim/event/process.h"
|
#include "nvim/event/process.h"
|
||||||
#include "nvim/lib/queue.h"
|
#include "nvim/lib/queue.h"
|
||||||
|
#include "nvim/os/pty_conpty_win.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
kWinpty,
|
||||||
|
kConpty
|
||||||
|
} PtyType;
|
||||||
|
|
||||||
typedef struct pty_process {
|
typedef struct pty_process {
|
||||||
Process process;
|
Process process;
|
||||||
char *term_name;
|
char *term_name;
|
||||||
uint16_t width, height;
|
uint16_t width, height;
|
||||||
winpty_t *winpty_object;
|
union {
|
||||||
|
winpty_t *winpty;
|
||||||
|
conpty_t *conpty;
|
||||||
|
} object;
|
||||||
|
PtyType type;
|
||||||
HANDLE finish_wait;
|
HANDLE finish_wait;
|
||||||
HANDLE process_handle;
|
HANDLE process_handle;
|
||||||
uv_timer_t wait_eof_timer;
|
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.term_name = NULL;
|
||||||
rv.width = 80;
|
rv.width = 80;
|
||||||
rv.height = 24;
|
rv.height = 24;
|
||||||
rv.winpty_object = NULL;
|
rv.object.winpty = NULL;
|
||||||
|
rv.type = kWinpty;
|
||||||
rv.finish_wait = NULL;
|
rv.finish_wait = NULL;
|
||||||
rv.process_handle = NULL;
|
rv.process_handle = NULL;
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
#include "nvim/os/os.h"
|
#include "nvim/os/os.h"
|
||||||
#include "nvim/os/input.h"
|
#include "nvim/os/input.h"
|
||||||
|
#ifdef WIN32
|
||||||
|
# include "nvim/os/os_win_console.h"
|
||||||
|
#endif
|
||||||
#include "nvim/event/rstream.h"
|
#include "nvim/event/rstream.h"
|
||||||
|
|
||||||
#define KEY_BUFFER_SIZE 0xfff
|
#define KEY_BUFFER_SIZE 0xfff
|
||||||
@ -37,13 +40,7 @@ void tinput_init(TermInput *input, Loop *loop)
|
|||||||
// ls *.md | xargs nvim
|
// ls *.md | xargs nvim
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
if (!os_isatty(input->in_fd)) {
|
if (!os_isatty(input->in_fd)) {
|
||||||
const HANDLE conin_handle = CreateFile("CONIN$",
|
input->in_fd = os_get_conin_fd();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (!os_isatty(input->in_fd) && os_isatty(STDERR_FILENO)) {
|
if (!os_isatty(input->in_fd) && os_isatty(STDERR_FILENO)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user