diff options
-rw-r--r-- | .github/workflows/ci.yml | 10 | ||||
-rw-r--r-- | src/nvim/globals.h | 3 | ||||
-rw-r--r-- | src/nvim/main.c | 32 | ||||
-rw-r--r-- | src/nvim/main.h | 3 | ||||
-rw-r--r-- | src/nvim/os/fs.c | 4 | ||||
-rw-r--r-- | src/nvim/os/input.c | 18 | ||||
-rw-r--r-- | src/nvim/os/input.h | 2 | ||||
-rw-r--r-- | src/nvim/os/os_win_console.c | 4 | ||||
-rw-r--r-- | src/nvim/testdir/test_shell.vim | 209 | ||||
-rw-r--r-- | src/nvim/testdir/test_startup.vim | 35 | ||||
-rw-r--r-- | src/nvim/testdir/test_system.vim | 36 | ||||
-rw-r--r-- | src/nvim/tui/input.c | 16 | ||||
-rw-r--r-- | src/nvim/tui/tui.c | 11 | ||||
-rw-r--r-- | src/nvim/ui_client.c | 9 |
14 files changed, 267 insertions, 125 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7699233ea3..399ac24ecc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,8 +83,10 @@ jobs: args: --check runtime/ - if: success() || failure() && steps.abort_job.outputs.status == 'success' - name: lintlua - run: make lintlua + name: luacheck + run: | + cmake -B $BUILD_DIR -G Ninja + cmake --build $BUILD_DIR --target lintlua-luacheck - if: success() || failure() && steps.abort_job.outputs.status == 'success' name: lintsh @@ -162,8 +164,8 @@ jobs: run: echo "status=${{ job.status }}" >> $GITHUB_OUTPUT - if: success() || failure() && steps.abort_job.outputs.status == 'success' - name: lintc - run: make lintc + name: clint.py + run: cmake --build build --target lintc-clint - if: success() || failure() && steps.abort_job.outputs.status == 'success' name: check-single-includes diff --git a/src/nvim/globals.h b/src/nvim/globals.h index d721b09c12..43b1d780be 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -494,6 +494,9 @@ EXTERN int v_dying INIT(= 0); EXTERN bool stdin_isatty INIT(= true); // is stdout a terminal? EXTERN bool stdout_isatty INIT(= true); +// is stderr a terminal? +EXTERN bool stderr_isatty INIT(= true); + /// filedesc set by embedder for reading first buffer like `cmd | nvim -` EXTERN int stdin_fd INIT(= -1); diff --git a/src/nvim/main.c b/src/nvim/main.c index f00d09b748..4dfb00f2db 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -286,7 +286,13 @@ int main(int argc, char **argv) } } - bool use_builtin_ui = (!headless_mode && !embedded_mode && !silent_mode); +#ifdef MSWIN + // on windows we use CONIN special file, thus we don't know this yet. + bool has_term = true; +#else + bool has_term = (stdin_isatty || stdout_isatty || stderr_isatty); +#endif + bool use_builtin_ui = (has_term && !headless_mode && !embedded_mode && !silent_mode); // don't bind the server yet, if we are using builtin ui. // This will be done when nvim server has been forked from the ui process @@ -302,7 +308,7 @@ int main(int argc, char **argv) bool remote_ui = (ui_client_channel_id != 0); if (use_builtin_ui && !remote_ui) { - ui_client_forward_stdin = !params.input_isatty; + ui_client_forward_stdin = !stdin_isatty; uint64_t rv = ui_client_start_server(params.argc, params.argv); if (!rv) { os_errmsg("Failed to start Nvim server!\n"); @@ -359,8 +365,8 @@ int main(int argc, char **argv) debug_break_level = params.use_debug_break_level; // Read ex-commands if invoked with "-es". - if (!params.input_isatty && !params.input_istext && silent_mode && exmode_active) { - input_start(STDIN_FILENO); + if (!stdin_isatty && !params.input_istext && silent_mode && exmode_active) { + input_start(); } if (ui_client_channel_id) { @@ -639,8 +645,8 @@ void os_exit(int r) if (!event_teardown() && r == 0) { r = 1; // Exit with error if main_loop did not teardown gracefully. } - if (input_global_fd() >= 0) { - stream_set_blocking(input_global_fd(), true); // normalize stream (#2598) + if (used_stdin) { + stream_set_blocking(STDIN_FILENO, true); // normalize stream (#2598) } ILOG("Nvim exit: %d", r); @@ -785,9 +791,9 @@ void preserve_exit(void) // Prevent repeated calls into this method. if (really_exiting) { - if (input_global_fd() >= 0) { + if (used_stdin) { // normalize stream (#2598) - stream_set_blocking(input_global_fd(), true); + stream_set_blocking(STDIN_FILENO, true); } exit(2); } @@ -963,7 +969,7 @@ static bool edit_stdin(mparm_T *parmp) bool implicit = !headless_mode && !(embedded_mode && stdin_fd <= 0) && (!exmode_active || parmp->input_istext) - && !parmp->input_isatty + && !stdin_isatty && parmp->scriptin == NULL; // `-s -` was not given. return parmp->had_stdin_file || implicit; } @@ -1449,11 +1455,9 @@ static void init_startuptime(mparm_T *paramp) static void check_and_set_isatty(mparm_T *paramp) { - stdin_isatty - = paramp->input_isatty = os_isatty(STDIN_FILENO); - stdout_isatty - = paramp->output_isatty = os_isatty(STDOUT_FILENO); - paramp->err_isatty = os_isatty(STDERR_FILENO); + stdin_isatty = os_isatty(STDIN_FILENO); + stdout_isatty = os_isatty(STDOUT_FILENO); + stderr_isatty = os_isatty(STDERR_FILENO); TIME_MSG("window checked"); } diff --git a/src/nvim/main.h b/src/nvim/main.h index 46d7217364..2d54837872 100644 --- a/src/nvim/main.h +++ b/src/nvim/main.h @@ -30,10 +30,7 @@ typedef struct { char *tagname; // tag from -t argument char *use_ef; // 'errorfile' from -q argument - bool input_isatty; // stdin is a terminal bool input_istext; // stdin is text, not executable (-E/-Es) - bool output_isatty; // stdout is a terminal - bool err_isatty; // stderr is a terminal int no_swap_file; // "-n" argument used int use_debug_break_level; diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index e0449d468a..98ec9aa826 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -302,7 +302,9 @@ static bool is_executable(const char *name, char **abspath) static bool is_executable_ext(const char *name, char **abspath) FUNC_ATTR_NONNULL_ARG(1) { - const bool is_unix_shell = strstr((char *)path_tail(p_sh), "sh") != NULL; + const bool is_unix_shell = strstr(path_tail(p_sh), "powershell") == NULL + && strstr(path_tail(p_sh), "pwsh") == NULL + && strstr(path_tail(p_sh), "sh") != NULL; char *nameext = strrchr(name, '.'); size_t nameext_len = nameext ? strlen(nameext) : 0; xstrlcpy(os_buf, name, sizeof(os_buf)); diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 5d2ac1e102..51cabfbcbf 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -44,7 +44,6 @@ typedef enum { static Stream read_stream = { .closed = true }; // Input before UI starts. static RBuffer *input_buffer = NULL; static bool input_eof = false; -static int global_fd = -1; static bool blocking = false; static int cursorhold_time = 0; ///< time waiting for CursorHold event static int cursorhold_tb_change_cnt = 0; ///< tb_change_cnt when waiting started @@ -58,25 +57,14 @@ void input_init(void) input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN); } -void input_global_fd_init(int fd) -{ - global_fd = fd; -} - -/// Global TTY (or pipe for "-es") input stream, before UI starts. -int input_global_fd(void) -{ - return global_fd; -} - -void input_start(int fd) +void input_start(void) { if (!read_stream.closed) { return; } - input_global_fd_init(fd); - rstream_init_fd(&main_loop, &read_stream, fd, READ_BUFFER_SIZE); + used_stdin = true; + rstream_init_fd(&main_loop, &read_stream, STDIN_FILENO, READ_BUFFER_SIZE); rstream_start(&read_stream, input_read_cb, NULL); } diff --git a/src/nvim/os/input.h b/src/nvim/os/input.h index 7026781407..6f25efdc7b 100644 --- a/src/nvim/os/input.h +++ b/src/nvim/os/input.h @@ -7,6 +7,8 @@ #include "nvim/api/private/defs.h" #include "nvim/event/multiqueue.h" +EXTERN bool used_stdin INIT(= false); + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/input.h.generated.h" #endif diff --git a/src/nvim/os/os_win_console.c b/src/nvim/os/os_win_console.c index ec0f03a1dc..18f6e8b37b 100644 --- a/src/nvim/os/os_win_console.c +++ b/src/nvim/os/os_win_console.c @@ -14,7 +14,7 @@ static HWND hWnd = NULL; static HICON hOrigIconSmall = NULL; static HICON hOrigIcon = NULL; -int os_get_conin_fd(void) +int os_open_conin_fd(void) { const HANDLE conin_handle = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, @@ -30,7 +30,7 @@ int os_get_conin_fd(void) void os_replace_stdin_to_conin(void) { close(STDIN_FILENO); - const int conin_fd = os_get_conin_fd(); + const int conin_fd = os_open_conin_fd(); assert(conin_fd == STDIN_FILENO); } diff --git a/src/nvim/testdir/test_shell.vim b/src/nvim/testdir/test_shell.vim new file mode 100644 index 0000000000..8b9c7a5b12 --- /dev/null +++ b/src/nvim/testdir/test_shell.vim @@ -0,0 +1,209 @@ +" Test for the shell related options ('shell', 'shellcmdflag', 'shellpipe', +" 'shellquote', 'shellredir', 'shellxescape', and 'shellxquote') + +source check.vim +source shared.vim + +func Test_shell_options() + " The expected value of 'shellcmdflag', 'shellpipe', 'shellquote', + " 'shellredir', 'shellxescape', 'shellxquote' for the supported shells. + let shells = [] + if has('unix') + let shells += [['sh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['ksh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['mksh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['zsh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['zsh-beta', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['bash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['fish', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['ash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['dash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['csh', '-c', '|& tee', '', '>&', '', ''], + \ ['tcsh', '-c', '|& tee', '', '>&', '', '']] + endif + if has('win32') + let shells += [['cmd', '/s /c', '>%s 2>&1', '', '>%s 2>&1', '', '"']] + endif + + " start a new Vim instance with 'shell' set to each of the supported shells + " and check the default shell option settings + let after =<< trim END + let l = [&shell, &shellcmdflag, &shellpipe, &shellquote] + let l += [&shellredir, &shellxescape, &shellxquote] + call writefile([json_encode(l)], 'Xtestout') + qall! + END + for e in shells + if RunVim([], after, '--cmd "set shell=' .. e[0] .. '"') + call assert_equal(e, json_decode(readfile('Xtestout')[0])) + endif + endfor + + " Test shellescape() for each of the shells. + for e in shells + exe 'set shell=' .. e[0] + if e[0] =~# '.*csh$' || e[0] =~# '.*csh.exe$' + let str1 = "'cmd \"arg1\" '\\''arg2'\\'' \\!%#'" + let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\\\!\\%\\#'" + elseif e[0] =~# '.*powershell$' || e[0] =~# '.*powershell.exe$' + let str1 = "'cmd \"arg1\" ''arg2'' !%#'" + let str2 = "'cmd \"arg1\" ''arg2'' \\!\\%\\#'" + else + let str1 = "'cmd \"arg1\" '\\''arg2'\\'' !%#'" + let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\!\\%\\#'" + endif + call assert_equal(str1, shellescape("cmd \"arg1\" 'arg2' !%#"), e[0]) + call assert_equal(str2, shellescape("cmd \"arg1\" 'arg2' !%#", 1), e[0]) + + " Try running an external command with the shell. + if executable(e[0]) + " set the shell options for the current 'shell' + let [&shellcmdflag, &shellpipe, &shellquote, &shellredir, + \ &shellxescape, &shellxquote] = e[1:6] + new + r !echo hello + call assert_equal('hello', substitute(getline(2), '\W', '', 'g'), e[0]) + bwipe! + endif + endfor + set shell& shellcmdflag& shellpipe& shellquote& + set shellredir& shellxescape& shellxquote& + call delete('Xtestout') +endfunc + +" Test for the 'shell' option +func Test_shell() + throw 'Skipped: Nvim missing :shell currently' + CheckUnix + let save_shell = &shell + set shell= + let caught_e91 = 0 + try + shell + catch /E91:/ + let caught_e91 = 1 + endtry + call assert_equal(1, caught_e91) + let &shell = save_shell +endfunc + +" Test for the 'shellquote' option +func Test_shellquote() + CheckUnix + set shellquote=# + set verbose=20 + redir => v + silent! !echo Hello + redir END + set verbose& + set shellquote& + call assert_match(': "#echo Hello#"', v) +endfunc + +" Test for the 'shellescape' option +func Test_shellescape() + let save_shell = &shell + set shell=bash + call assert_equal("'text'", shellescape('text')) + call assert_equal("'te\"xt'", 'te"xt'->shellescape()) + call assert_equal("'te'\\''xt'", shellescape("te'xt")) + + call assert_equal("'te%xt'", shellescape("te%xt")) + call assert_equal("'te\\%xt'", shellescape("te%xt", 1)) + call assert_equal("'te#xt'", shellescape("te#xt")) + call assert_equal("'te\\#xt'", shellescape("te#xt", 1)) + call assert_equal("'te!xt'", shellescape("te!xt")) + call assert_equal("'te\\!xt'", shellescape("te!xt", 1)) + + call assert_equal("'te\nxt'", shellescape("te\nxt")) + call assert_equal("'te\\\nxt'", shellescape("te\nxt", 1)) + set shell=tcsh + call assert_equal("'te\\!xt'", shellescape("te!xt")) + call assert_equal("'te\\\\!xt'", shellescape("te!xt", 1)) + call assert_equal("'te\\\nxt'", shellescape("te\nxt")) + call assert_equal("'te\\\\\nxt'", shellescape("te\nxt", 1)) + + let &shell = save_shell +endfunc + +" Test for 'shellslash' +func Test_shellslash() + CheckOption shellslash + let save_shellslash = &shellslash + " The shell and cmdflag, and expected slash in tempname with shellslash set or + " unset. The assert checks the file separator before the leafname. + " ".*\\\\[^\\\\]*$" + let shells = [['cmd', '/c', '/', '/'], + \ ['powershell', '-Command', '/', '/'], + \ ['sh', '-c', '/', '/']] + for e in shells + exe 'set shell=' .. e[0] .. ' | set shellcmdflag=' .. e[1] + set noshellslash + let file = tempname() + call assert_match('^.\+' .. e[2] .. '[^' .. e[2] .. ']\+$', file, e[0] .. ' ' .. e[1] .. ' nossl') + set shellslash + let file = tempname() + call assert_match('^.\+' .. e[3] .. '[^' .. e[3] .. ']\+$', file, e[0] .. ' ' .. e[1] .. ' ssl') + endfor + let &shellslash = save_shellslash +endfunc + +" Test for 'shellxquote' +func Test_shellxquote() + CheckUnix + + let save_shell = &shell + let save_sxq = &shellxquote + let save_sxe = &shellxescape + + call writefile(['#!/bin/sh', 'echo "Cmd: [$*]" > Xlog'], 'Xtestshell') + call setfperm('Xtestshell', "r-x------") + set shell=./Xtestshell + + set shellxquote=\\" + call feedkeys(":!pwd\<CR>\<CR>", 'xt') + call assert_equal(['Cmd: [-c "pwd"]'], readfile('Xlog')) + + set shellxquote=( + call feedkeys(":!pwd\<CR>\<CR>", 'xt') + call assert_equal(['Cmd: [-c (pwd)]'], readfile('Xlog')) + + set shellxquote=\\"( + call feedkeys(":!pwd\<CR>\<CR>", 'xt') + call assert_equal(['Cmd: [-c "(pwd)"]'], readfile('Xlog')) + + set shellxescape=\"&<<()@^ + set shellxquote=( + call feedkeys(":!pwd\"&<<{}@^\<CR>\<CR>", 'xt') + call assert_equal(['Cmd: [-c (pwd^"^&^<^<{}^@^^)]'], readfile('Xlog')) + + let &shell = save_shell + let &shellxquote = save_sxq + let &shellxescape = save_sxe + call delete('Xtestshell') + call delete('Xlog') +endfunc + +" Test for using the shell set in the $SHELL environment variable +func Test_set_shell() + let after =<< trim [CODE] + call writefile([&shell], "Xtestout") + quit! + [CODE] + + if has('win32') + let $SHELL = 'C:\with space\cmd.exe' + let expected = '"C:\with space\cmd.exe"' + else + let $SHELL = '/bin/with space/sh' + let expected = '"/bin/with space/sh"' + endif + + if RunVimPiped([], after, '', '') + let lines = readfile('Xtestout') + call assert_equal(expected, lines[0]) + endif + call delete('Xtestout') +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim index 54b7636f69..1ee1d0dfe3 100644 --- a/src/nvim/testdir/test_startup.vim +++ b/src/nvim/testdir/test_startup.vim @@ -725,27 +725,6 @@ func Test_read_stdin() call delete('Xtestout') endfunc -func Test_set_shell() - let after =<< trim [CODE] - call writefile([&shell], "Xtestout") - quit! - [CODE] - - if has('win32') - let $SHELL = 'C:\with space\cmd.exe' - let expected = '"C:\with space\cmd.exe"' - else - let $SHELL = '/bin/with space/sh' - let expected = '"/bin/with space/sh"' - endif - - if RunVimPiped([], after, '', '') - let lines = readfile('Xtestout') - call assert_equal(expected, lines[0]) - endif - call delete('Xtestout') -endfunc - func Test_progpath() " Tests normally run with "./vim" or "../vim", these must have been expanded " to a full path. @@ -1064,7 +1043,7 @@ func Test_io_not_a_terminal() \ 'Vim: Warning: Input is not from a terminal'], l) endfunc -" Test for --not-a-term avoiding escape codes. +" Test for not being a term avoiding escape codes. func Test_not_a_term() CheckUnix CheckNotGui @@ -1075,18 +1054,14 @@ func Test_not_a_term() let redir = &shellredir .. ' Xvimout' endif - " Without --not-a-term there are a few escape sequences. - " This will take 2 seconds because of the missing --not-a-term + " As nvim checks the environment by itself there will be no escape sequences + " This will also happen to take two (2) seconds. let cmd = GetVimProg() .. ' --cmd quit ' .. redir exe "silent !" . cmd - call assert_match("\<Esc>", readfile('Xvimout')->join()) + call assert_notmatch("\e", readfile('Xvimout')->join()) call delete('Xvimout') - " With --not-a-term there are no escape sequences. - let cmd = GetVimProg() .. ' --not-a-term --cmd quit ' .. redir - exe "silent !" . cmd - call assert_notmatch("\<Esc>", readfile('Xvimout')->join()) - call delete('Xvimout') + " --not-a-term flag has thus been deleted endfunc diff --git a/src/nvim/testdir/test_system.vim b/src/nvim/testdir/test_system.vim index bfa8a277bd..6c8373b335 100644 --- a/src/nvim/testdir/test_system.vim +++ b/src/nvim/testdir/test_system.vim @@ -142,40 +142,4 @@ func Test_system_with_shell_quote() endtry endfunc -" Test for 'shellxquote' -func Test_Shellxquote() - CheckUnix - - let save_shell = &shell - let save_sxq = &shellxquote - let save_sxe = &shellxescape - - call writefile(['#!/bin/sh', 'echo "Cmd: [$*]" > Xlog'], 'Xtestshell') - call setfperm('Xtestshell', "r-x------") - set shell=./Xtestshell - - set shellxquote=\\" - call feedkeys(":!pwd\<CR>\<CR>", 'xt') - call assert_equal(['Cmd: [-c "pwd"]'], readfile('Xlog')) - - set shellxquote=( - call feedkeys(":!pwd\<CR>\<CR>", 'xt') - call assert_equal(['Cmd: [-c (pwd)]'], readfile('Xlog')) - - set shellxquote=\\"( - call feedkeys(":!pwd\<CR>\<CR>", 'xt') - call assert_equal(['Cmd: [-c "(pwd)"]'], readfile('Xlog')) - - set shellxescape=\"&<<()@^ - set shellxquote=( - call feedkeys(":!pwd\"&<<{}@^\<CR>\<CR>", 'xt') - call assert_equal(['Cmd: [-c (pwd^"^&^<^<{}^@^^)]'], readfile('Xlog')) - - let &shell = save_shell - let &shellxquote = save_sxq - let &shellxescape = save_sxe - call delete('Xtestshell') - call delete('Xlog') -endfunc - " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 55a8b3666e..5325ae3e4d 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -149,19 +149,7 @@ void tinput_init(TermInput *input, Loop *loop) kitty_key_map_entry[i].name); } - // If stdin is not a pty, switch to stderr. For cases like: - // echo q | nvim -es - // ls *.md | xargs nvim -#ifdef MSWIN - if (!os_isatty(input->in_fd)) { - input->in_fd = os_get_conin_fd(); - } -#else - if (!os_isatty(input->in_fd) && os_isatty(STDERR_FILENO)) { - input->in_fd = STDERR_FILENO; - } -#endif - input_global_fd_init(input->in_fd); + input->in_fd = STDIN_FILENO; const char *term = os_getenv("TERM"); if (!term) { @@ -170,7 +158,7 @@ void tinput_init(TermInput *input, Loop *loop) input->tk = termkey_new_abstract(term, TERMKEY_FLAG_UTF8 | TERMKEY_FLAG_NOSTART); - termkey_hook_terminfo_getstr(input->tk, input->tk_ti_hook_fn, NULL); + termkey_hook_terminfo_getstr(input->tk, input->tk_ti_hook_fn, input); termkey_start(input->tk); int curflags = termkey_get_canonflags(input->tk); diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 5232bcad19..44b99f6c84 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1338,7 +1338,7 @@ static void suspend_event(void **argv) TUIData *tui = argv[0]; bool enable_mouse = tui->mouse_enabled; tui_terminal_stop(tui); - stream_set_blocking(input_global_fd(), true); // normalize stream (#2598) + stream_set_blocking(tui->input.in_fd, true); // normalize stream (#2598) kill(0, SIGTSTP); @@ -1347,7 +1347,7 @@ static void suspend_event(void **argv) if (enable_mouse) { tui_mouse_on(tui); } - stream_set_blocking(input_global_fd(), false); // libuv expects this + stream_set_blocking(tui->input.in_fd, false); // libuv expects this } #endif @@ -2234,12 +2234,12 @@ static void flush_buf(TUIData *tui) /// /// @see tmux/tty-keys.c fe4e9470bb504357d073320f5d305b22663ee3fd /// @see https://bugzilla.redhat.com/show_bug.cgi?id=142659 -static const char *tui_get_stty_erase(void) +static const char *tui_get_stty_erase(int fd) { static char stty_erase[2] = { 0 }; #if defined(HAVE_TERMIOS_H) struct termios t; - if (tcgetattr(input_global_fd(), &t) != -1) { + if (tcgetattr(fd, &t) != -1) { stty_erase[0] = (char)t.c_cc[VERASE]; stty_erase[1] = '\0'; DLOG("stty/termios:erase=%s", stty_erase); @@ -2252,9 +2252,10 @@ static const char *tui_get_stty_erase(void) /// @see TermInput.tk_ti_hook_fn static const char *tui_tk_ti_getstr(const char *name, const char *value, void *data) { + TermInput *input = data; static const char *stty_erase = NULL; if (stty_erase == NULL) { - stty_erase = tui_get_stty_erase(); + stty_erase = tui_get_stty_erase(input->in_fd); } if (strequal(name, "key_backspace")) { diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c index b80b250cec..222ba3d5dd 100644 --- a/src/nvim/ui_client.c +++ b/src/nvim/ui_client.c @@ -51,9 +51,16 @@ uint64_t ui_client_start_server(int argc, char **argv) on_err, CALLBACK_NONE, false, true, true, false, kChannelStdinPipe, NULL, 0, 0, NULL, &exit_status); + + // If stdin is not a pty, it is forwarded to the client. + // Replace stdin in the TUI process with the tty fd. if (ui_client_forward_stdin) { close(0); - dup(2); +#ifdef MSWIN + os_open_conin_fd(); +#else + dup(stderr_isatty ? STDERR_FILENO : STDOUT_FILENO); +#endif } return channel->id; |