From df23952ce9509b90440a66b7ef863e6a1dfcebbc Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 26 Oct 2025 06:18:13 +0800 Subject: [PATCH] fix(tui): don't treat remote TUI as GUI (#36319) Set "stdin_tty" and "stdout_tty" UI options, so that a remote TUI is not treated as a GUI. --- src/nvim/api/ui.c | 10 +++++++--- src/nvim/ui_client.c | 12 +++++------- test/functional/terminal/tui_spec.lua | 21 +++++++++++++++++---- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index fe02809f82..e47d31b905 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -169,6 +169,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dict opt return; } RemoteUI *ui = xcalloc(1, sizeof(RemoteUI)); + ui->channel_id = channel_id; ui->width = (int)width; ui->height = (int)height; ui->pum_row = -1.0; @@ -195,7 +196,6 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dict opt ui->ui_ext[kUICmdline] = true; } - ui->channel_id = channel_id; ui->cur_event = NULL; ui->hl_id = 0; ui->client_col = -1; @@ -427,7 +427,9 @@ static void ui_set_option(RemoteUI *ui, bool init, String name, Object value, Er VALIDATE_T("stdin_tty", kObjectTypeBoolean, value.type, { return; }); - stdin_isatty = value.data.boolean; + if (ui->channel_id == CHAN_STDIO) { + stdin_isatty = value.data.boolean; + } ui->stdin_tty = value.data.boolean; return; } @@ -436,7 +438,9 @@ static void ui_set_option(RemoteUI *ui, bool init, String name, Object value, Er VALIDATE_T("stdout_tty", kObjectTypeBoolean, value.type, { return; }); - stdout_isatty = value.data.boolean; + if (ui->channel_id == CHAN_STDIO) { + stdout_isatty = value.data.boolean; + } ui->stdout_tty = value.data.boolean; return; } diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c index e25d76651c..9ce12c7a1a 100644 --- a/src/nvim/ui_client.c +++ b/src/nvim/ui_client.c @@ -105,13 +105,11 @@ void ui_client_attach(int width, int height, char *term, bool rgb) PUT_C(opts, "term_name", CSTR_AS_OBJ(term)); } PUT_C(opts, "term_colors", INTEGER_OBJ(t_colors)); - if (!ui_client_is_remote) { - PUT_C(opts, "stdin_tty", BOOLEAN_OBJ(stdin_isatty)); - PUT_C(opts, "stdout_tty", BOOLEAN_OBJ(stdout_isatty)); - if (ui_client_forward_stdin) { - PUT_C(opts, "stdin_fd", INTEGER_OBJ(UI_CLIENT_STDIN_FD)); - ui_client_forward_stdin = false; // stdin shouldn't be forwarded again #22292 - } + PUT_C(opts, "stdin_tty", BOOLEAN_OBJ(stdin_isatty)); + PUT_C(opts, "stdout_tty", BOOLEAN_OBJ(stdout_isatty)); + if (ui_client_forward_stdin) { + PUT_C(opts, "stdin_fd", INTEGER_OBJ(UI_CLIENT_STDIN_FD)); + ui_client_forward_stdin = false; // stdin shouldn't be forwarded again #22292 } ADD_C(args, DICT_OBJ(opts)); diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 1df4dcaa06..419b99e2b6 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -2562,6 +2562,13 @@ describe('TUI', function() eq(true, child_exec_lua('return _G.result')) end) end) + + it('nvim_ui_send works', function() + child_session:request('nvim_ui_send', '\027]2;TEST_TITLE\027\\') + retry(nil, nil, function() + eq('TEST_TITLE', api.nvim_buf_get_var(0, 'term_title')) + end) + end) end) describe('TUI', function() @@ -3887,9 +3894,8 @@ describe('TUI client', function() it('connects to remote instance (with its own TUI)', function() local _, screen_server, screen_client = start_tui_and_remote_client() - -- XXX: should has("gui_running") be 1 when there is a remote TUI? feed_data(':echo "GUI Running: " .. has("gui_running")\013') - screen_client:expect({ any = 'GUI Running: 1' }) + screen_client:expect({ any = 'GUI Running: 0' }) -- grid smaller than containing terminal window is cleared properly feed_data(":call setline(1,['a'->repeat(&columns)]->repeat(&lines))\n") @@ -3984,9 +3990,8 @@ describe('TUI client', function() ]]) feed_data('\027') - -- XXX: should has("gui_running") be 1 when there is a remote TUI? feed_data(':echo "GUI Running: " .. has("gui_running")\013') - screen_client:expect({ any = 'GUI Running: 1' }) + screen_client:expect({ any = 'GUI Running: 0' }) -- Run :restart on the client. -- The client should start a new server while the original server should exit. @@ -4049,6 +4054,14 @@ describe('TUI client', function() end) end) + it('nvim_ui_send works with remote client #36317', function() + local server, _, _ = start_headless_server_and_client() + server:request('nvim_ui_send', '\027]2;TEST_TITLE\027\\') + retry(nil, nil, function() + eq('TEST_TITLE', api.nvim_buf_get_var(0, 'term_title')) + end) + end) + it('throws error when no server exists', function() clear() local screen = tt.setup_child_nvim({