From 2c5906b55bb6092121f4d3b032d5449da7675c2b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 2 Feb 2023 10:05:03 +0800 Subject: fix(exit): skip unnecessary steps in TUI preserve_exit() (#21897) This prevents the TUI from doing unexpected things when receiving a deadly signal or running out of memory. --- src/nvim/tui/tui.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index a50e44f7a3..ceda3b2076 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -458,6 +458,9 @@ static void tui_terminal_stop(TUIData *tui) void tui_stop(TUIData *tui) { + if (tui->stopped) { + return; + } tui_terminal_stop(tui); stream_set_blocking(tui->input.in_fd, true); // normalize stream (#2598) tinput_destroy(&tui->input); -- cgit From d3355ad01c3b9d1dbc62210c29d8e51245f081aa Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 2 Feb 2023 22:42:15 +0800 Subject: fix(tui): detach/attach on suspend/resume (#22040) Problem: When a TUI client is suspended it still receives UI events from the server, and has to process these accumulated events when it is resumed. With mulitple TUI clients this is a bigger problem, considering the following steps: 1. A TUI client is attached. 2. CTRL-Z is pressed and the first client is suspended. 3. Another TUI client is attached. 4. CTRL-Z is pressed and a "suspend" event is sent to both clients. The second client is suspended, while the first client isn't able to process the event because it has already been suspended. 5. The first client is resumed. It processes the accumulated "suspend" event and suspends immediately. Solution: Make a TUI client detach on suspend and re-attach on resume. --- src/nvim/tui/tui.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index ceda3b2076..f760e99262 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1347,6 +1347,7 @@ static void show_verbose_terminfo(TUIData *tui) static void suspend_event(void **argv) { TUIData *tui = argv[0]; + ui_client_detach(); bool enable_mouse = tui->mouse_enabled; tui_terminal_stop(tui); stream_set_blocking(tui->input.in_fd, true); // normalize stream (#2598) @@ -1359,6 +1360,7 @@ static void suspend_event(void **argv) tui_mouse_on(tui); } stream_set_blocking(tui->input.in_fd, false); // libuv expects this + ui_client_attach(tui->width, tui->height, tui->term); } #endif -- cgit From 69bb145cea56067e6e82ed0a130a51c0d611e540 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 4 Feb 2023 20:14:31 +0800 Subject: refactor(exit): pass error message to preserve_exit() (#22097) Problem: 1. Some calls to preserve_exit() don't put a message in IObuff, so the IObuff printed by preserve_exit() contains unrelated information. 2. If a TUI client runs out of memory or receives a deadly signal, the error message is shown on alternate screen and cannot be easily seen because the TUI exits alternate screen soon afterwards. Solution: Pass error message to preserve_exit() and exit alternate screen before printing it. Note that this doesn't fix the problem that server error messages cannot be easily seen on exit. This is tracked in #21608 and #21843. --- src/nvim/tui/tui.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index f760e99262..fff5c865bf 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -458,9 +458,6 @@ static void tui_terminal_stop(TUIData *tui) void tui_stop(TUIData *tui) { - if (tui->stopped) { - return; - } tui_terminal_stop(tui); stream_set_blocking(tui->input.in_fd, true); // normalize stream (#2598) tinput_destroy(&tui->input); @@ -470,7 +467,7 @@ void tui_stop(TUIData *tui) } /// Returns true if UI `ui` is stopped. -static bool tui_is_stopped(TUIData *tui) +bool tui_is_stopped(TUIData *tui) { return tui->stopped; } -- cgit From 7224c889e0d5d70b99ae377036baa6377c33a568 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 11 Feb 2023 10:25:24 +0100 Subject: build: enable MSVC level 3 warnings (#21934) MSVC has 4 different warning levels: 1 (severe), 2 (significant), 3 (production quality) and 4 (informational). Enabling level 3 warnings mostly revealed conversion problems, similar to GCC/clang -Wconversion flag. --- src/nvim/tui/tui.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index fff5c865bf..9415917e34 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -34,15 +34,17 @@ #include "nvim/msgpack_rpc/channel.h" #include "nvim/os/input.h" #include "nvim/os/os.h" -#include "nvim/ui_client.h" -#ifdef MSWIN -# include "nvim/os/os_win_console.h" -#endif #include "nvim/tui/input.h" #include "nvim/tui/terminfo.h" #include "nvim/tui/tui.h" #include "nvim/ugrid.h" #include "nvim/ui.h" +#include "nvim/ui_client.h" + +#ifdef MSWIN +# include "nvim/os/os_win_console.h" +# include "nvim/os/tty.h" +#endif // Space reserved in two output buffers to make the cursor normal or invisible // when flushing. No existing terminal will require 32 bytes to do that. -- cgit From 820430dc0bb84011edae801262e64a10be7ebb9d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 13 Feb 2023 16:33:20 +0800 Subject: fix(tui): exit on input eof --- src/nvim/tui/tui.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 9415917e34..f7bc931e21 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -167,7 +167,7 @@ static bool cursor_style_enabled = false; # include "tui/tui.c.generated.h" #endif -TUIData *tui_start(int *width, int *height, char **term) +void tui_start(TUIData **tui_p, int *width, int *height, char **term) { TUIData *tui = xcalloc(1, sizeof(TUIData)); tui->is_starting = true; @@ -190,11 +190,11 @@ TUIData *tui_start(int *width, int *height, char **term) uv_timer_start(&tui->startup_delay_timer, after_startup_cb, 100, 0); + *tui_p = tui; loop_poll_events(&main_loop, 1); *width = tui->width; *height = tui->height; *term = tui->term; - return tui; } void tui_enable_extkeys(TUIData *tui) -- cgit From e03ecb7d31c10aab8a8acbfb3cdd7ec558cd49eb Mon Sep 17 00:00:00 2001 From: Enan Ajmain <3nan.ajmain@gmail.com> Date: Wed, 15 Feb 2023 01:15:28 +0600 Subject: fix: uv_tty_set_mode failed in Windows #22264 Problem: uv_tty_set_mode on stdout in Windows exits with error. Cause: Windows cannot set the properties of the output of a tty. Solution: Remove call to uv_tty_set_mode. Ref: #21445 Ref: https://github.com/libuv/libuv/commit/88634c1405097c19582e870d278dd0e29dc55455#r100598822 --- src/nvim/tui/tui.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index f7bc931e21..8df6e49b77 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -359,12 +359,7 @@ static void terminfo_start(TUIData *tui) if (ret) { ELOG("uv_tty_init failed: %s", uv_strerror(ret)); } -#ifdef MSWIN - ret = uv_tty_set_mode(&tui->output_handle.tty, UV_TTY_MODE_RAW); - if (ret) { - ELOG("uv_tty_set_mode failed: %s", uv_strerror(ret)); - } -#else +#ifndef MSWIN int retry_count = 10; // A signal may cause uv_tty_set_mode() to fail (e.g., SIGCONT). Retry a // few times. #12322 -- cgit From 40287319002ff6ced3d280657c276fb7c9ef4df5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 19 Feb 2023 20:56:15 +0800 Subject: fix(tui): properly check if stdin is a tty (#22321) After #21831 `in_fd` is no longer set to stderr when starting TUI, so check for `stdin_isatty` instead. Fix #22259. --- src/nvim/tui/tui.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 8df6e49b77..fee1d21672 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1147,7 +1147,7 @@ void tui_mode_change(TUIData *tui, String mode, Integer mode_idx) // If stdin is not a TTY, the LHS of pipe may change the state of the TTY // after calling uv_tty_set_mode. So, set the mode of the TTY again here. // #13073 - if (tui->is_starting && tui->input.in_fd == STDERR_FILENO) { + if (tui->is_starting && !stdin_isatty) { int ret = uv_tty_set_mode(&tui->output_handle.tty, UV_TTY_MODE_NORMAL); if (ret) { ELOG("uv_tty_set_mode failed: %s", uv_strerror(ret)); -- cgit From 2630341db65772e0a636c2a1cfbd6bba8ca9b28d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 28 Feb 2023 07:19:03 +0800 Subject: fix(tui): avoid stack-use-after-scope with cursor color (#22435) --- src/nvim/tui/tui.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index fee1d21672..48dc860ebd 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1109,8 +1109,8 @@ void tui_set_mode(TUIData *tui, ModeShape mode) // Hopefully the user's default cursor color is inverse. unibi_out_ext(tui, tui->unibi_ext.reset_cursor_color); } else { + char hexbuf[8]; if (tui->set_cursor_color_as_str) { - char hexbuf[8]; snprintf(hexbuf, 7 + 1, "#%06x", aep.rgb_bg_color); UNIBI_SET_STR_VAR(tui->params[0], hexbuf); } else { -- cgit From 848dac0aaa68a6ecbb7fe346a90bb5e5f5d7f09f Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 27 Feb 2023 19:51:25 +0100 Subject: refactor(build): graduate unibilium VAR_FROM feature from 2017 --- src/nvim/tui/tui.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 48dc860ebd..df7c87ad60 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -60,27 +60,14 @@ #define LINUXSET0C "\x1b[?0c" #define LINUXSET1C "\x1b[?1c" -#ifdef NVIM_UNIBI_HAS_VAR_FROM -# define UNIBI_SET_NUM_VAR(var, num) \ +#define UNIBI_SET_NUM_VAR(var, num) \ do { \ (var) = unibi_var_from_num((num)); \ } while (0) -# define UNIBI_SET_STR_VAR(var, str) \ +#define UNIBI_SET_STR_VAR(var, str) \ do { \ (var) = unibi_var_from_str((str)); \ } while (0) -#else -# define UNIBI_SET_NUM_VAR(var, num) \ - do { \ - (var).p = NULL; \ - (var).i = (num); \ - } while (0) -# define UNIBI_SET_STR_VAR(var, str) \ - do { \ - (var).i = INT_MIN; \ - (var).p = str; \ - } while (0) -#endif typedef struct { int top, bot, left, right; -- cgit From 706f871014b46300180156590ff269ee38473989 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 19 Apr 2023 17:04:00 +0100 Subject: build: update uncrustify to 0.76 --- src/nvim/tui/tui.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index df7c87ad60..eecaa8c55a 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1369,7 +1369,8 @@ void tui_set_title(TUIData *tui, String title) } void tui_set_icon(TUIData *tui, String icon) -{} +{ +} void tui_screenshot(TUIData *tui, String path) { -- cgit From 3b0df1780e2c8526bda5dead18ee7cc45925caba Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Wed, 26 Apr 2023 23:23:44 +0200 Subject: refactor: uncrustify Notable changes: replace all infinite loops to `while(true)` and remove `int` from `unsigned int`. --- src/nvim/tui/tui.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index eecaa8c55a..2f4ff13bde 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -209,7 +209,7 @@ void tui_enable_extkeys(TUIData *tui) unibi_out_ext(tui, tui->unibi_ext.enable_extended_keys); } -static size_t unibi_pre_fmt_str(TUIData *tui, unsigned int unibi_index, char *buf, size_t len) +static size_t unibi_pre_fmt_str(TUIData *tui, unsigned unibi_index, char *buf, size_t len) { const char *str = unibi_get_str(tui->ut, unibi_index); if (!str) { @@ -1617,7 +1617,7 @@ static void pad(void *ctx, size_t delay, int scale FUNC_ATTR_UNUSED, int force) } flush_buf(tui); - uv_sleep((unsigned int)(delay/10)); + uv_sleep((unsigned)(delay/10)); } static void unibi_set_if_empty(unibi_term *ut, enum unibi_string str, const char *val) -- cgit From 4f235e3cafba5dc305aa0be33cdec093e9c5a92d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 28 Apr 2023 20:26:02 +0800 Subject: fix(tui): position cursor at bottom-left before stopping (#23369) Fix #23361 --- src/nvim/tui/tui.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 2f4ff13bde..975ad375a0 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -437,6 +437,8 @@ static void tui_terminal_stop(TUIData *tui) } tinput_stop(&tui->input); signal_watcher_stop(&tui->winch_handle); + // Position the cursor on the last screen line, below all the text + cursor_goto(tui, tui->height - 1, 0); terminfo_stop(tui); } -- cgit From 0f1b511f2302324684c3ed9ff586f51c2129694d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 1 May 2023 12:20:07 +0800 Subject: fix(tui): redraw on SIGWINCH even if size didn't change --- src/nvim/tui/tui.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 975ad375a0..b267027d02 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1529,12 +1529,11 @@ void tui_guess_size(TUIData *tui) height = DFLT_ROWS; } - if (tui->width != width || tui->height != height) { - tui->width = width; - tui->height = height; + tui->width = width; + tui->height = height; - ui_client_set_size(width, height); - } + // Redraw on SIGWINCH event if size didn't change. #23411 + ui_client_set_size(width, height); } static void unibi_goto(TUIData *tui, int row, int col) -- cgit From 197827321a39168dbaa143c9f7b4f5db668f893c Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Mon, 1 May 2023 20:08:25 +0200 Subject: fix(tui): grid_clear properly clears the screen Problem: When setting a shell size smaller than the containing terminal window through `:winsize` or `:set lines/columns` the screen is not properly cleared. Solution: Clear the tui dimensions rather than the grid dimensions. --- src/nvim/tui/tui.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 975ad375a0..0d661d2b58 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -977,7 +977,7 @@ void tui_grid_clear(TUIData *tui, Integer g) UGrid *grid = &tui->grid; ugrid_clear(grid); kv_size(tui->invalid_regions) = 0; - clear_region(tui, 0, grid->height, 0, grid->width, 0); + clear_region(tui, 0, tui->height, 0, tui->width, 0); } void tui_grid_cursor_goto(TUIData *tui, Integer grid, Integer row, Integer col) -- cgit From 3ae62c470634e30c55d822c452af135fee50ddd5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 19 May 2023 07:30:22 +0800 Subject: fix(tui): make disabling title restore old title from stack (#23585) This makes setting 'notitle' in Nvim behave more like Vim in terminals that support title stacking. --- src/nvim/tui/tui.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 2de1467511..6a9769e351 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -106,6 +106,7 @@ struct TUIData { bool bce; bool mouse_enabled; bool mouse_move_enabled; + bool title_enabled; bool busy, is_invisible, want_invisible; bool cork, overflow; bool set_cursor_color_as_str; @@ -325,8 +326,6 @@ static void terminfo_start(TUIData *tui) // Enter alternate screen, save title, and clear. // NOTE: Do this *before* changing terminal settings. #6433 unibi_out(tui, unibi_enter_ca_mode); - // Save title/icon to the "stack". #4063 - unibi_out_ext(tui, tui->unibi_ext.save_title); unibi_out(tui, unibi_keypad_xmit); unibi_out(tui, unibi_clear_screen); // Ask the terminal to send us the background color. @@ -383,8 +382,7 @@ static void terminfo_stop(TUIData *tui) // Disable extended keys before exiting alternate screen. unibi_out_ext(tui, tui->unibi_ext.disable_extended_keys); unibi_out(tui, unibi_exit_ca_mode); - // Restore title/icon from the "stack". #4063 - unibi_out_ext(tui, tui->unibi_ext.restore_title); + tui_set_title(tui, (String)STRING_INIT); if (tui->cursor_color_changed) { unibi_out_ext(tui, tui->unibi_ext.reset_cursor_color); } @@ -1361,13 +1359,24 @@ void tui_suspend(TUIData *tui) void tui_set_title(TUIData *tui, String title) { - if (!(title.data && unibi_get_str(tui->ut, unibi_to_status_line) + if (!(unibi_get_str(tui->ut, unibi_to_status_line) && unibi_get_str(tui->ut, unibi_from_status_line))) { return; } - unibi_out(tui, unibi_to_status_line); - out(tui, title.data, title.size); - unibi_out(tui, unibi_from_status_line); + if (title.size > 0) { + if (!tui->title_enabled) { + // Save title/icon to the "stack". #4063 + unibi_out_ext(tui, tui->unibi_ext.save_title); + tui->title_enabled = true; + } + unibi_out(tui, unibi_to_status_line); + out(tui, title.data, title.size); + unibi_out(tui, unibi_from_status_line); + } else if (tui->title_enabled) { + // Restore title/icon from the "stack". #4063 + unibi_out_ext(tui, tui->unibi_ext.restore_title); + tui->title_enabled = false; + } } void tui_set_icon(TUIData *tui, String icon) -- cgit From cfd4fdfea4d0e68ea50ad412b88b5289ded6fd6f Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Tue, 23 May 2023 14:25:10 +0600 Subject: refactor(api): new helper macros Adds new API helper macros `CSTR_AS_OBJ()`, `STATIC_CSTR_AS_OBJ()`, and `STATIC_CSTR_TO_OBJ()`, which cleans up a lot of the current code. These macros will also be used extensively in the upcoming option refactor PRs because then API Objects will be used to get/set options. This PR also modifies pre-existing code to use old API helper macros like `CSTR_TO_OBJ()` to make them cleaner. --- src/nvim/tui/tui.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 6a9769e351..c9d9b08b79 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1302,16 +1302,16 @@ static void show_verbose_terminfo(TUIData *tui) Array chunks = ARRAY_DICT_INIT; Array title = ARRAY_DICT_INIT; - ADD(title, STRING_OBJ(cstr_to_string("\n\n--- Terminal info --- {{{\n"))); - ADD(title, STRING_OBJ(cstr_to_string("Title"))); + ADD(title, CSTR_TO_OBJ("\n\n--- Terminal info --- {{{\n")); + ADD(title, CSTR_TO_OBJ("Title")); ADD(chunks, ARRAY_OBJ(title)); Array info = ARRAY_DICT_INIT; String str = terminfo_info_msg(ut, tui->term); ADD(info, STRING_OBJ(str)); ADD(chunks, ARRAY_OBJ(info)); Array end_fold = ARRAY_DICT_INIT; - ADD(end_fold, STRING_OBJ(cstr_to_string("}}}\n"))); - ADD(end_fold, STRING_OBJ(cstr_to_string("Title"))); + ADD(end_fold, CSTR_TO_OBJ("}}}\n")); + ADD(end_fold, CSTR_TO_OBJ("Title")); ADD(chunks, ARRAY_OBJ(end_fold)); Array args = ARRAY_DICT_INIT; @@ -1425,7 +1425,7 @@ void tui_option_set(TUIData *tui, String name, Object value) if (ui_client_channel_id) { MAXSIZE_TEMP_ARRAY(args, 2); - ADD_C(args, STRING_OBJ(cstr_as_string("rgb"))); + ADD_C(args, CSTR_AS_OBJ("rgb")); ADD_C(args, BOOLEAN_OBJ(value.data.boolean)); rpc_send_event(ui_client_channel_id, "nvim_ui_set_option", args); } -- cgit From 8e6971695383047ee5ba2921c91d98acb18c6d7a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 27 May 2023 10:13:51 +0800 Subject: fix(tui): restore title before exiting alternate screen (#23776) Since title stack is now saved after entering alternate screen, it makes more sense to restore title before exiting alternate screen. --- src/nvim/tui/tui.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index c9d9b08b79..0983667695 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -381,8 +381,10 @@ static void terminfo_stop(TUIData *tui) unibi_out(tui, unibi_keypad_local); // Disable extended keys before exiting alternate screen. unibi_out_ext(tui, tui->unibi_ext.disable_extended_keys); - unibi_out(tui, unibi_exit_ca_mode); + // May restore old title before exiting alternate screen. tui_set_title(tui, (String)STRING_INIT); + // Exit alternate screen. + unibi_out(tui, unibi_exit_ca_mode); if (tui->cursor_color_changed) { unibi_out_ext(tui, tui->unibi_ext.reset_cursor_color); } -- cgit From 8da986ea877b07a5eb117446f410f2a7fc8cd9cb Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 13 Sep 2023 13:39:18 +0200 Subject: refactor(grid): change schar_T representation to be more compact Previously, a screen cell would occupy 28+4=32 bytes per cell as we always made space for up to MAX_MCO+1 codepoints in a cell. As an example, even a pretty modest 50*80 screen would consume 50*80*2*32 = 256000, i e a quarter megabyte With the factor of two due to the TUI side buffer, and even more when using msg_grid and/or ext_multigrid. This instead stores a 4-byte union of either: - a valid UTF-8 sequence up to 4 bytes - an escape char which is invalid UTF-8 (0xFF) plus a 24-bit index to a glyph cache This avoids allocating space for huge composed glyphs _upfront_, while still keeping rendering such glyphs reasonably fast (1 hash table lookup + one plain index lookup). If the same large glyphs are using repeatedly on the screen, this is still a net reduction of memory/cache consumption. The only case which really gets worse is if you blast the screen full with crazy emojis and zalgo text and even this case only leads to 4 extra bytes per char. When only <= 4-byte glyphs are used, plus the 4-byte attribute code, i e 8 bytes in total there is a factor of four reduction of memory use. Memory which will be quite hot in cache as the screen buffer is scanned over in win_line() buffer text drawing A slight complication is that the representation depends on host byte order. I've tested this manually by compling and running this in qemu-s390x and it works fine. We might add a qemu based solution to CI at some point. --- src/nvim/tui/tui.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 0983667695..9fea6442a9 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -24,6 +24,7 @@ #include "nvim/event/signal.h" #include "nvim/event/stream.h" #include "nvim/globals.h" +#include "nvim/grid.h" #include "nvim/grid_defs.h" #include "nvim/highlight_defs.h" #include "nvim/log.h" @@ -675,15 +676,15 @@ static void final_column_wrap(TUIData *tui) /// It is undocumented, but in the majority of terminals and terminal emulators /// printing at the right margin does not cause an automatic wrap until the /// next character is printed, holding the cursor in place until then. -static void print_cell(TUIData *tui, UCell *ptr) +static void print_cell(TUIData *tui, char *buf, sattr_T attr) { UGrid *grid = &tui->grid; if (!tui->immediate_wrap_after_last_column) { // Printing the next character finally advances the cursor. final_column_wrap(tui); } - update_attrs(tui, ptr->attr); - out(tui, ptr->data, strlen(ptr->data)); + update_attrs(tui, attr); + out(tui, buf, strlen(buf)); grid->col++; if (tui->immediate_wrap_after_last_column) { // Printing at the right margin immediately advances the cursor. @@ -703,8 +704,8 @@ static bool cheap_to_print(TUIData *tui, int row, int col, int next) return false; } } - if (strlen(cell->data) > 1) { - return false; + if (schar_get_ascii(cell->data) == 0) { + return false; // not ascii } cell++; } @@ -831,14 +832,16 @@ static void print_cell_at_pos(TUIData *tui, int row, int col, UCell *cell, bool { UGrid *grid = &tui->grid; - if (grid->row == -1 && cell->data[0] == NUL) { + if (grid->row == -1 && cell->data == NUL) { // If cursor needs to repositioned and there is nothing to print, don't move cursor. return; } cursor_goto(tui, row, col); - bool is_ambiwidth = utf_ambiguous_width(utf_ptr2char(cell->data)); + char buf[MAX_SCHAR_SIZE]; + schar_get(buf, cell->data); + bool is_ambiwidth = utf_ambiguous_width(utf_ptr2char(buf)); if (is_ambiwidth && is_doublewidth) { // Clear the two screen cells. // If the character is single-width in the host terminal it won't change the second cell. @@ -847,7 +850,7 @@ static void print_cell_at_pos(TUIData *tui, int row, int col, UCell *cell, bool cursor_goto(tui, row, col); } - print_cell(tui, cell); + print_cell(tui, buf, cell->attr); if (is_ambiwidth) { // Force repositioning cursor after printing an ambiguous-width character. @@ -976,6 +979,8 @@ void tui_grid_clear(TUIData *tui, Integer g) { UGrid *grid = &tui->grid; ugrid_clear(grid); + // safe to clear cache at this point + schar_cache_clear_if_full(); kv_size(tui->invalid_regions) = 0; clear_region(tui, 0, tui->height, 0, tui->width, 0); } @@ -1273,7 +1278,7 @@ void tui_flush(TUIData *tui) int clear_col; for (clear_col = r.right; clear_col > 0; clear_col--) { UCell *cell = &grid->cells[row][clear_col - 1]; - if (!(cell->data[0] == ' ' && cell->data[1] == NUL + if (!(cell->data == schar_from_ascii(' ') && cell->attr == clear_attr)) { break; } @@ -1281,7 +1286,7 @@ void tui_flush(TUIData *tui) UGRID_FOREACH_CELL(grid, row, r.left, clear_col, { print_cell_at_pos(tui, row, curcol, cell, - curcol < clear_col - 1 && (cell + 1)->data[0] == NUL); + curcol < clear_col - 1 && (cell + 1)->data == NUL); }); if (clear_col < r.right) { clear_region(tui, row, row + 1, clear_col, r.right, clear_attr); @@ -1399,7 +1404,10 @@ void tui_screenshot(TUIData *tui, String path) for (int i = 0; i < grid->height; i++) { cursor_goto(tui, i, 0); for (int j = 0; j < grid->width; j++) { - print_cell(tui, &grid->cells[i][j]); + UCell cell = grid->cells[i][j]; + char buf[MAX_SCHAR_SIZE]; + schar_get(buf, cell.data); + print_cell(tui, buf, cell.attr); } } flush_buf(tui); @@ -1446,13 +1454,13 @@ void tui_raw_line(TUIData *tui, Integer g, Integer linerow, Integer startcol, In { UGrid *grid = &tui->grid; for (Integer c = startcol; c < endcol; c++) { - memcpy(grid->cells[linerow][c].data, chunk[c - startcol], sizeof(schar_T)); + grid->cells[linerow][c].data = chunk[c - startcol]; assert((size_t)attrs[c - startcol] < kv_size(tui->attrs)); grid->cells[linerow][c].attr = attrs[c - startcol]; } UGRID_FOREACH_CELL(grid, (int)linerow, (int)startcol, (int)endcol, { print_cell_at_pos(tui, (int)linerow, curcol, cell, - curcol < endcol - 1 && (cell + 1)->data[0] == NUL); + curcol < endcol - 1 && (cell + 1)->data == NUL); }); if (clearcol > endcol) { @@ -1469,7 +1477,7 @@ void tui_raw_line(TUIData *tui, Integer g, Integer linerow, Integer startcol, In if (endcol != grid->width) { // Print the last char of the row, if we haven't already done so. - int size = grid->cells[linerow][grid->width - 1].data[0] == NUL ? 2 : 1; + int size = grid->cells[linerow][grid->width - 1].data == NUL ? 2 : 1; print_cell_at_pos(tui, (int)linerow, grid->width - size, &grid->cells[linerow][grid->width - size], size == 2); } -- cgit From 911f3d962358bb032b55e9984d0b25ffc522ff49 Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 21 Sep 2023 10:18:37 +0200 Subject: fix(tui): don't overwrite an assertion faliure message on exit If nvim exited with nonzero status this is for one of the two reasons - `:cquit` was invoked. This is used by users and plugins to communicate a result, like a nonzero status will fail a `git commit` operation - There was an internal error or deadly signal. in this case an error message was likely written to stderr or to the screen. In the latter case, the error message was often hidden by the TUI exiting altscreen mode, which erases all visible terminal text. This change prevents this in the latter case, while still cleaning up the terminal properly when `:cquit` was deliberatily invoked. Other cleanup like exiting mouse mode and raw mode is still done. --- src/nvim/tui/tui.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 9fea6442a9..4097b770c9 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -145,6 +145,7 @@ struct TUIData { } unibi_ext; char *space_buf; bool stopped; + int seen_error_exit; int width; int height; bool rgb; @@ -162,6 +163,7 @@ void tui_start(TUIData **tui_p, int *width, int *height, char **term) tui->is_starting = true; tui->screenshot = NULL; tui->stopped = false; + tui->seen_error_exit = 0; tui->loop = &main_loop; kv_init(tui->invalid_regions); signal_watcher_init(tui->loop, &tui->winch_handle, tui); @@ -384,8 +386,13 @@ static void terminfo_stop(TUIData *tui) unibi_out_ext(tui, tui->unibi_ext.disable_extended_keys); // May restore old title before exiting alternate screen. tui_set_title(tui, (String)STRING_INIT); - // Exit alternate screen. - unibi_out(tui, unibi_exit_ca_mode); + // if nvim exited with nonzero status, without indicated this was an + // intentional exit (like `:1cquit`), it likely was an internal failure. + // Don't clobber the stderr error message in this case. + if (ui_client_exit_status == tui->seen_error_exit) { + // Exit alternate screen. + unibi_out(tui, unibi_exit_ca_mode); + } if (tui->cursor_color_changed) { unibi_out_ext(tui, tui->unibi_ext.reset_cursor_color); } @@ -443,6 +450,11 @@ static void tui_terminal_stop(TUIData *tui) terminfo_stop(tui); } +void tui_error_exit(TUIData *tui, Integer status) +{ + tui->seen_error_exit = (int)status; +} + void tui_stop(TUIData *tui) { tui_terminal_stop(tui); -- cgit From c26b39a9aa56e834262753e08372240fde9dcdf1 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 23 Sep 2023 11:00:20 +0800 Subject: fix(tui): make :cquit work properly with remote TUI (#25313) --- src/nvim/tui/tui.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 4097b770c9..db15cdb053 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -386,6 +386,9 @@ static void terminfo_stop(TUIData *tui) unibi_out_ext(tui, tui->unibi_ext.disable_extended_keys); // May restore old title before exiting alternate screen. tui_set_title(tui, (String)STRING_INIT); + if (ui_client_exit_status == 0) { + ui_client_exit_status = tui->seen_error_exit; + } // if nvim exited with nonzero status, without indicated this was an // intentional exit (like `:1cquit`), it likely was an internal failure. // Don't clobber the stderr error message in this case. -- cgit From cf8b2c0e74fd5e723b0c15c2ce84e6900fd322d3 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 30 Sep 2023 12:05:28 +0800 Subject: build(iwyu): add a few more _defs.h mappings (#25435) --- src/nvim/tui/tui.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index db15cdb053..944c1d14c2 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -25,7 +25,6 @@ #include "nvim/event/stream.h" #include "nvim/globals.h" #include "nvim/grid.h" -#include "nvim/grid_defs.h" #include "nvim/highlight_defs.h" #include "nvim/log.h" #include "nvim/macros.h" -- cgit From 8e932480f61d6101bf8bea1abc07ed93826221fd Mon Sep 17 00:00:00 2001 From: dundargoc Date: Fri, 29 Sep 2023 14:58:48 +0200 Subject: refactor: the long goodbye long is 32 bits on windows, while it is 64 bits on other architectures. This makes the type suboptimal for a codebase meant to be cross-platform. Replace it with more appropriate integer types. --- src/nvim/tui/tui.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 944c1d14c2..9b4d63e7c6 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -287,7 +287,7 @@ static void terminfo_start(TUIData *tui) const char *colorterm = os_getenv("COLORTERM"); const char *termprg = os_getenv("TERM_PROGRAM"); const char *vte_version_env = os_getenv("VTE_VERSION"); - long vtev = vte_version_env ? strtol(vte_version_env, NULL, 10) : 0; + int vtev = vte_version_env ? (int)strtol(vte_version_env, NULL, 10) : 0; bool iterm_env = termprg && strstr(termprg, "iTerm.app"); bool nsterm = (termprg && strstr(termprg, "Apple_Terminal")) || terminfo_is_term_family(term, "nsterm"); @@ -295,7 +295,7 @@ static void terminfo_start(TUIData *tui) || os_getenv("KONSOLE_PROFILE_NAME") || os_getenv("KONSOLE_DBUS_SESSION"); const char *konsolev_env = os_getenv("KONSOLE_VERSION"); - long konsolev = konsolev_env ? strtol(konsolev_env, NULL, 10) + int konsolev = konsolev_env ? (int)strtol(konsolev_env, NULL, 10) : (konsole ? 1 : 0); patch_terminfo_bugs(tui, term, colorterm, vtev, konsolev, iterm_env, nsterm); @@ -1456,7 +1456,7 @@ void tui_option_set(TUIData *tui, String name, Object value) } else if (strequal(name.data, "ttimeout")) { tui->input.ttimeout = value.data.boolean; } else if (strequal(name.data, "ttimeoutlen")) { - tui->input.ttimeoutlen = (long)value.data.integer; + tui->input.ttimeoutlen = (OptInt)value.data.integer; } else if (strequal(name.data, "verbose")) { tui->verbose = value.data.integer; } @@ -1689,7 +1689,7 @@ static int unibi_find_ext_bool(unibi_term *ut, const char *name) /// Several entries in terminfo are known to be deficient or outright wrong; /// and several terminal emulators falsely announce incorrect terminal types. static void patch_terminfo_bugs(TUIData *tui, const char *term, const char *colorterm, - long vte_version, long konsolev, bool iterm_env, bool nsterm) + int vte_version, int konsolev, bool iterm_env, bool nsterm) { unibi_term *ut = tui->ut; const char *xterm_version = os_getenv("XTERM_VERSION"); @@ -2019,7 +2019,7 @@ static void patch_terminfo_bugs(TUIData *tui, const char *term, const char *colo /// This adds stuff that is not in standard terminfo as extended unibilium /// capabilities. -static void augment_terminfo(TUIData *tui, const char *term, long vte_version, long konsolev, +static void augment_terminfo(TUIData *tui, const char *term, int vte_version, int konsolev, bool iterm_env, bool nsterm) { unibi_term *ut = tui->ut; -- cgit From 9ff6f73f838a1f90d09922448c434033ba5e094e Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Mon, 9 Oct 2023 00:36:48 +0600 Subject: refactor: allow not having a `default` case for enum Problem: The style guide states that all switch statements that are not conditional on an enum must have a `default` case, but does not give any explicit guideline for switch statements that are conditional on enums. As a result, a `default` case is added in many enum switch statements, even when the switch statement is exhaustive. This is not ideal because it removes the ability to have compiler errors to easily detect unchanged switch statements when a new possible value for an enum is added. Solution: Add explicit guidelines for switch statements that are conditional on an enum, clarifying that a `default` case is not necessary if the switch statement is exhaustive. Also refactor pre-existing code with unnecessary `default` cases. --- src/nvim/tui/tui.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 9b4d63e7c6..260bf55093 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1135,8 +1135,6 @@ void tui_set_mode(TUIData *tui, ModeShape mode) int shape; switch (c.shape) { - default: - abort(); break; case SHAPE_BLOCK: shape = 1; break; case SHAPE_HOR: -- cgit From 353a4be7e84fdc101318215bdcc8a7e780d737fe Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sun, 12 Nov 2023 13:13:58 +0100 Subject: build: remove PVS We already have an extensive suite of static analysis tools we use, which causes a fair bit of redundancy as we get duplicate warnings. PVS is also prone to give false warnings which creates a lot of work to identify and disable. --- src/nvim/tui/tui.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 260bf55093..177ef0c3cf 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1,6 +1,3 @@ -// 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 - // Terminal UI functions. Invoked (by ui_client.c) on the UI process. #include @@ -439,7 +436,7 @@ static void tui_terminal_after_startup(TUIData *tui) /// stop the terminal but allow it to restart later (like after suspend) static void tui_terminal_stop(TUIData *tui) { - if (uv_is_closing(STRUCT_CAST(uv_handle_t, &tui->output_handle))) { + if (uv_is_closing((uv_handle_t *)&tui->output_handle)) { // Race between SIGCONT (tui.c) and SIGHUP (os/signal.c)? #8075 ELOG("TUI already stopped (race?)"); tui->stopped = true; @@ -1174,9 +1171,8 @@ void tui_mode_change(TUIData *tui, String mode, Integer mode_idx) tui->showing_mode = (ModeShape)mode_idx; } -void tui_grid_scroll(TUIData *tui, Integer g, Integer startrow, // -V751 - Integer endrow, Integer startcol, Integer endcol, Integer rows, - Integer cols FUNC_ATTR_UNUSED) +void tui_grid_scroll(TUIData *tui, Integer g, Integer startrow, Integer endrow, Integer startcol, + Integer endcol, Integer rows, Integer cols FUNC_ATTR_UNUSED) { UGrid *grid = &tui->grid; int top = (int)startrow, bot = (int)endrow - 1; @@ -2250,8 +2246,8 @@ static void flush_buf(TUIData *tui) fwrite(bufs[i].base, bufs[i].len, 1, tui->screenshot); } } else { - int ret = uv_write(&req, STRUCT_CAST(uv_stream_t, &tui->output_handle), - bufs, (unsigned)(bufp - bufs), NULL); + int ret + = uv_write(&req, (uv_stream_t *)&tui->output_handle, bufs, (unsigned)(bufp - bufs), NULL); if (ret) { ELOG("uv_write failed: %s", uv_strerror(ret)); } -- cgit From ab102f188e86bdbfce1d4de2ef633092a906e8fe Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Mon, 6 Nov 2023 15:46:44 -0600 Subject: refactor: move background color detection into Lua --- src/nvim/tui/tui.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 177ef0c3cf..8aab4d836c 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -133,7 +133,6 @@ struct TUIData { int reset_scroll_region; int set_cursor_style, reset_cursor_style; int save_title, restore_title; - int get_bg; int set_underline_style; int set_underline_color; int enable_extended_keys, disable_extended_keys; @@ -250,7 +249,6 @@ static void terminfo_start(TUIData *tui) tui->unibi_ext.reset_scroll_region = -1; tui->unibi_ext.set_cursor_style = -1; tui->unibi_ext.reset_cursor_style = -1; - tui->unibi_ext.get_bg = -1; tui->unibi_ext.set_underline_color = -1; tui->unibi_ext.enable_extended_keys = -1; tui->unibi_ext.disable_extended_keys = -1; @@ -327,9 +325,7 @@ static void terminfo_start(TUIData *tui) unibi_out(tui, unibi_enter_ca_mode); unibi_out(tui, unibi_keypad_xmit); unibi_out(tui, unibi_clear_screen); - // Ask the terminal to send us the background color. - tui->input.waiting_for_bg_response = 5; - unibi_out_ext(tui, tui->unibi_ext.get_bg); + // Enable bracketed paste unibi_out_ext(tui, tui->unibi_ext.enable_bracketed_paste); @@ -1882,9 +1878,6 @@ static void patch_terminfo_bugs(TUIData *tui, const char *term, const char *colo #define XTERM_SETAB_16 \ "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e39%;m" - tui->unibi_ext.get_bg = (int)unibi_add_ext_str(ut, "ext.get_bg", - "\x1b]11;?\x07"); - // Query the terminal to see if it supports CSI u key encoding by writing CSI // ? u followed by a request for the primary device attributes (CSI c) // See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#detection-of-support-for-this-protocol -- cgit From ac8ed77afb359694a716501d9e87b0c9949b2445 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Tue, 14 Nov 2023 08:53:58 -0600 Subject: feat(tui): add 'termsync' option (#25871) The 'termsync' option enables a mode (provided the underlying terminal supports it) where all screen updates during a redraw cycle are buffered and drawn together when the redraw is complete. This eliminates tearing or flickering in cases where Nvim redraws slower than the terminal redraws the screen. --- src/nvim/tui/tui.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 8aab4d836c..aff7b100d8 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -104,6 +104,7 @@ struct TUIData { bool mouse_enabled; bool mouse_move_enabled; bool title_enabled; + bool sync_output; bool busy, is_invisible, want_invisible; bool cork, overflow; bool set_cursor_color_as_str; @@ -137,6 +138,7 @@ struct TUIData { int set_underline_color; int enable_extended_keys, disable_extended_keys; int get_extkeys; + int sync; } unibi_ext; char *space_buf; bool stopped; @@ -217,6 +219,41 @@ static size_t unibi_pre_fmt_str(TUIData *tui, unsigned unibi_index, char *buf, s return unibi_run(str, tui->params, buf, len); } +/// Request the terminal's DEC mode (DECRQM). +/// +/// @see handle_modereport +static void tui_dec_request_mode(TUIData *tui, TerminalDecMode mode) +{ + // 5 bytes for \x1b[?$p, 1 byte for null terminator, 6 bytes for mode digits (more than enough) + char buf[12]; + int len = snprintf(buf, sizeof(buf), "\x1b[?%d$p", (int)mode); + assert((len > 0) && (len < (int)sizeof(buf))); + out(tui, buf, (size_t)len); +} + +/// Handle a DECRPM response from the terminal. +void tui_dec_report_mode(TUIData *tui, TerminalDecMode mode, TerminalModeState state) +{ + assert(tui); + switch (state) { + case kTerminalModeNotRecognized: + case kTerminalModePermanentlySet: + case kTerminalModePermanentlyReset: + // If the mode is not recognized, or if the terminal emulator does not allow it to be changed, + // then there is nothing to do + break; + case kTerminalModeSet: + case kTerminalModeReset: + // The terminal supports changing the given mode + switch (mode) { + case kDecModeSynchronizedOutput: + // Ref: https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036 + tui->unibi_ext.sync = (int)unibi_add_ext_str(tui->ut, "Sync", + "\x1b[?2026%?%p1%{1}%-%tl%eh%;"); + } + } +} + static void terminfo_start(TUIData *tui) { tui->scroll_region_is_full_screen = true; @@ -253,6 +290,7 @@ static void terminfo_start(TUIData *tui) tui->unibi_ext.enable_extended_keys = -1; tui->unibi_ext.disable_extended_keys = -1; tui->unibi_ext.get_extkeys = -1; + tui->unibi_ext.sync = -1; tui->out_fd = STDOUT_FILENO; tui->out_isatty = os_isatty(tui->out_fd); tui->input.tui_data = tui; @@ -329,6 +367,11 @@ static void terminfo_start(TUIData *tui) // Enable bracketed paste unibi_out_ext(tui, tui->unibi_ext.enable_bracketed_paste); + // Query support for mode 2026 (Synchronized Output). Some terminals also + // support an older DCS sequence for synchronized output, but we will only use + // mode 2026 + tui_dec_request_mode(tui, kDecModeSynchronizedOutput); + // Query the terminal to see if it supports CSI u tui->input.waiting_for_csiu_response = 5; unibi_out_ext(tui, tui->unibi_ext.get_extkeys); @@ -395,6 +438,11 @@ static void terminfo_stop(TUIData *tui) unibi_out_ext(tui, tui->unibi_ext.disable_bracketed_paste); // Disable focus reporting unibi_out_ext(tui, tui->unibi_ext.disable_focus_reporting); + + // Disable synchronized output + UNIBI_SET_NUM_VAR(tui->params[0], 0); + unibi_out_ext(tui, tui->unibi_ext.sync); + flush_buf(tui); uv_tty_reset_mode(); uv_close((uv_handle_t *)&tui->output_handle, NULL); @@ -1257,6 +1305,20 @@ void tui_default_colors_set(TUIData *tui, Integer rgb_fg, Integer rgb_bg, Intege invalidate(tui, 0, tui->grid.height, 0, tui->grid.width); } +/// Enable synchronized output. When enabled, the terminal emulator will preserve the last rendered +/// state on subsequent re-renders. It will continue to process incoming events. When synchronized +/// mode is disabled again the emulator renders using the most recent state. This avoids tearing +/// when the terminal updates the screen faster than Nvim can redraw it. +static void tui_sync_output(TUIData *tui, bool enable) +{ + if (!tui->sync_output) { + return; + } + + UNIBI_SET_NUM_VAR(tui->params[0], enable ? 1 : 0); + unibi_out_ext(tui, tui->unibi_ext.sync); +} + void tui_flush(TUIData *tui) { UGrid *grid = &tui->grid; @@ -1273,6 +1335,8 @@ void tui_flush(TUIData *tui) tui_busy_stop(tui); // avoid hidden cursor } + tui_sync_output(tui, true); + while (kv_size(tui->invalid_regions)) { Rect r = kv_pop(tui->invalid_regions); assert(r.bot <= grid->height && r.right <= grid->width); @@ -1300,6 +1364,8 @@ void tui_flush(TUIData *tui) cursor_goto(tui, tui->row, tui->col); + tui_sync_output(tui, false); + flush_buf(tui); } @@ -1449,6 +1515,8 @@ void tui_option_set(TUIData *tui, String name, Object value) tui->input.ttimeoutlen = (OptInt)value.data.integer; } else if (strequal(name.data, "verbose")) { tui->verbose = value.data.integer; + } else if (strequal(name.data, "termsync")) { + tui->sync_output = value.data.boolean; } } -- cgit From 405bad5e085fb359879646b6fd6fbcddae83eac5 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Wed, 15 Nov 2023 15:55:19 -0600 Subject: fix(tui): do not toggle cursor visibility when flushing the buffer (#26055) When writing large amounts of data to the tty it is common to first hide the cursor to avoid a flickering effect. This has been done in Nvim for a long time and was implemented in the function that actually flushed the TUI buffer out to the TTY. However, when using synchronized updates with the 'termsync' option this is no longer necessary, as the terminal emulator will buffer all of the updates and display them atomically. Thus there is no need to toggle the cursor visibility when flushing the buffer when synchronized updates are used. In fact, doing so can actually reintroduce cursor flickering in certain scenarios because the visibility state is itself being synchronized by the terminal. In addition, the management of the cursor visibility should not happen when the TUI _buffer_ is flushed, but rather when the TUI itself is flushed. This is a subtle but meaningful distinction: the former literally writes bytes to the TTY while the latter flushes the TUI's grid into its buffer. There is no need to hide the cursor every time we write bytes to the TTY, only at the beginning of a full TUI "flush" event. --- src/nvim/tui/tui.c | 122 ++++++++++++++++++----------------------------------- 1 file changed, 41 insertions(+), 81 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index aff7b100d8..56134dd955 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -75,9 +75,6 @@ struct TUIData { unibi_var_t params[9]; char buf[OUTBUF_SIZE]; size_t bufpos; - char norm[CNORM_COMMAND_MAX_SIZE]; - char invis[CNORM_COMMAND_MAX_SIZE]; - size_t normlen, invislen; TermInput input; uv_loop_t write_loop; unibi_term *ut; @@ -210,19 +207,11 @@ void tui_enable_extkeys(TUIData *tui) unibi_out_ext(tui, tui->unibi_ext.enable_extended_keys); } -static size_t unibi_pre_fmt_str(TUIData *tui, unsigned unibi_index, char *buf, size_t len) -{ - const char *str = unibi_get_str(tui->ut, unibi_index); - if (!str) { - return 0U; - } - return unibi_run(str, tui->params, buf, len); -} - /// Request the terminal's DEC mode (DECRQM). /// /// @see handle_modereport static void tui_dec_request_mode(TUIData *tui, TerminalDecMode mode) + FUNC_ATTR_NONNULL_ALL { // 5 bytes for \x1b[?$p, 1 byte for null terminator, 6 bytes for mode digits (more than enough) char buf[12]; @@ -233,8 +222,8 @@ static void tui_dec_request_mode(TUIData *tui, TerminalDecMode mode) /// Handle a DECRPM response from the terminal. void tui_dec_report_mode(TUIData *tui, TerminalDecMode mode, TerminalModeState state) + FUNC_ATTR_NONNULL_ALL { - assert(tui); switch (state) { case kTerminalModeNotRecognized: case kTerminalModePermanentlySet: @@ -352,10 +341,6 @@ static void terminfo_start(TUIData *tui) || terminfo_is_term_family(term, "win32con") || terminfo_is_term_family(term, "interix"); tui->bce = unibi_get_bool(tui->ut, unibi_back_color_erase); - tui->normlen = unibi_pre_fmt_str(tui, unibi_cursor_normal, - tui->norm, sizeof tui->norm); - tui->invislen = unibi_pre_fmt_str(tui, unibi_cursor_invisible, - tui->invis, sizeof tui->invis); // Set 't_Co' from the result of unibilium & fix_terminfo. t_colors = unibi_get_num(tui->ut, unibi_max_colors); // Enter alternate screen, save title, and clear. @@ -1151,9 +1136,7 @@ void tui_set_mode(TUIData *tui, ModeShape mode) HlAttrs aep = kv_A(tui->attrs, c.id); tui->want_invisible = aep.hl_blend == 100; - if (tui->want_invisible) { - unibi_out(tui, unibi_cursor_invisible); - } else if (aep.rgb_ae_attr & HL_INVERSE) { + if (!tui->want_invisible && aep.rgb_ae_attr & HL_INVERSE) { // We interpret "inverse" as "default" (no termcode for "inverse"...). // Hopefully the user's default cursor color is inverse. unibi_out_ext(tui, tui->unibi_ext.reset_cursor_color); @@ -1174,6 +1157,14 @@ void tui_set_mode(TUIData *tui, ModeShape mode) unibi_out_ext(tui, tui->unibi_ext.reset_cursor_color); } + if (tui->want_invisible && !tui->is_invisible) { + unibi_out(tui, unibi_cursor_invisible); + tui->is_invisible = true; + } else if (!tui->want_invisible && tui->is_invisible) { + unibi_out(tui, unibi_cursor_normal); + tui->is_invisible = false; + } + int shape; switch (c.shape) { case SHAPE_BLOCK: @@ -1305,18 +1296,30 @@ void tui_default_colors_set(TUIData *tui, Integer rgb_fg, Integer rgb_bg, Intege invalidate(tui, 0, tui->grid.height, 0, tui->grid.width); } -/// Enable synchronized output. When enabled, the terminal emulator will preserve the last rendered -/// state on subsequent re-renders. It will continue to process incoming events. When synchronized -/// mode is disabled again the emulator renders using the most recent state. This avoids tearing -/// when the terminal updates the screen faster than Nvim can redraw it. -static void tui_sync_output(TUIData *tui, bool enable) +/// Begin flushing the TUI. If 'termsync' is set and the terminal supports synchronized updates, +/// begin a synchronized update. Otherwise, hide the cursor to avoid cursor jumping. +static void tui_flush_start(TUIData *tui) + FUNC_ATTR_NONNULL_ALL { - if (!tui->sync_output) { - return; + if (tui->sync_output && tui->unibi_ext.sync != -1) { + UNIBI_SET_NUM_VAR(tui->params[0], 1); + unibi_out_ext(tui, tui->unibi_ext.sync); + } else { + unibi_out(tui, unibi_cursor_invisible); } +} - UNIBI_SET_NUM_VAR(tui->params[0], enable ? 1 : 0); - unibi_out_ext(tui, tui->unibi_ext.sync); +/// Finish flushing the TUI. If 'termsync' is set and the terminal supports synchronized updates, +/// end a synchronized update. Otherwise, make the cursor visible again. +static void tui_flush_end(TUIData *tui) + FUNC_ATTR_NONNULL_ALL +{ + if (tui->sync_output && tui->unibi_ext.sync != -1) { + UNIBI_SET_NUM_VAR(tui->params[0], 0); + unibi_out_ext(tui, tui->unibi_ext.sync); + } else if (!tui->busy && !tui->want_invisible) { + unibi_out(tui, unibi_cursor_normal); + } } void tui_flush(TUIData *tui) @@ -1335,7 +1338,7 @@ void tui_flush(TUIData *tui) tui_busy_stop(tui); // avoid hidden cursor } - tui_sync_output(tui, true); + tui_flush_start(tui); while (kv_size(tui->invalid_regions)) { Rect r = kv_pop(tui->invalid_regions); @@ -1364,7 +1367,7 @@ void tui_flush(TUIData *tui) cursor_goto(tui, tui->row, tui->col); - tui_sync_output(tui, false); + tui_flush_end(tui); flush_buf(tui); } @@ -2252,63 +2255,20 @@ static void augment_terminfo(TUIData *tui, const char *term, int vte_version, in static void flush_buf(TUIData *tui) { uv_write_t req; - uv_buf_t bufs[3]; - uv_buf_t *bufp = &bufs[0]; - - // The content of the output for each condition is shown in the following - // table. Therefore, if tui->bufpos == 0 and N/A or invis + norm, there is - // no need to output it. - // - // | is_invisible | !is_invisible - // ------+-----------------+--------------+--------------- - // busy | want_invisible | N/A | invis - // | !want_invisible | N/A | invis - // ------+-----------------+--------------+--------------- - // !busy | want_invisible | N/A | invis - // | !want_invisible | norm | invis + norm - // ------+-----------------+--------------+--------------- - // - if (tui->bufpos <= 0 - && ((tui->is_invisible && tui->busy) - || (tui->is_invisible && !tui->busy && tui->want_invisible) - || (!tui->is_invisible && !tui->busy && !tui->want_invisible))) { - return; - } + uv_buf_t buf; - if (!tui->is_invisible) { - // cursor is visible. Write a "cursor invisible" command before writing the - // buffer. - bufp->base = tui->invis; - bufp->len = UV_BUF_LEN(tui->invislen); - bufp++; - tui->is_invisible = true; - } - - if (tui->bufpos > 0) { - bufp->base = tui->buf; - bufp->len = UV_BUF_LEN(tui->bufpos); - bufp++; + if (tui->bufpos <= 0) { + return; } - if (!tui->busy) { - assert(tui->is_invisible); - // not busy and the cursor is invisible. Write a "cursor normal" command - // after writing the buffer. - if (!tui->want_invisible) { - bufp->base = tui->norm; - bufp->len = UV_BUF_LEN(tui->normlen); - bufp++; - tui->is_invisible = false; - } - } + buf.base = tui->buf; + buf.len = UV_BUF_LEN(tui->bufpos); if (tui->screenshot) { - for (size_t i = 0; i < (size_t)(bufp - bufs); i++) { - fwrite(bufs[i].base, bufs[i].len, 1, tui->screenshot); - } + fwrite(buf.base, buf.len, 1, tui->screenshot); } else { int ret - = uv_write(&req, (uv_stream_t *)&tui->output_handle, bufs, (unsigned)(bufp - bufs), NULL); + = uv_write(&req, (uv_stream_t *)&tui->output_handle, &buf, 1, NULL); if (ret) { ELOG("uv_write failed: %s", uv_strerror(ret)); } -- cgit From bb4b4576e384c71890b4df4fa4f1ae76fad3a59d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 16 Nov 2023 10:55:54 +0800 Subject: refactor: iwyu (#26062) --- src/nvim/tui/tui.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 56134dd955..ad82b0d783 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -34,6 +34,7 @@ #include "nvim/tui/input.h" #include "nvim/tui/terminfo.h" #include "nvim/tui/tui.h" +#include "nvim/types.h" #include "nvim/ugrid.h" #include "nvim/ui.h" #include "nvim/ui_client.h" -- cgit From ad867fee26c8124d23693823b56f849e4487b828 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 17 Nov 2023 22:13:30 +0800 Subject: fix(tui): handle cursor visibility properly (#26091) The test is for the case without 'termsync' because libvterm doesn't support synchronized output, and it passes without this PR. --- src/nvim/tui/tui.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index ad82b0d783..a64f9af454 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1158,14 +1158,6 @@ void tui_set_mode(TUIData *tui, ModeShape mode) unibi_out_ext(tui, tui->unibi_ext.reset_cursor_color); } - if (tui->want_invisible && !tui->is_invisible) { - unibi_out(tui, unibi_cursor_invisible); - tui->is_invisible = true; - } else if (!tui->want_invisible && tui->is_invisible) { - unibi_out(tui, unibi_cursor_normal); - tui->is_invisible = false; - } - int shape; switch (c.shape) { case SHAPE_BLOCK: @@ -1305,8 +1297,9 @@ static void tui_flush_start(TUIData *tui) if (tui->sync_output && tui->unibi_ext.sync != -1) { UNIBI_SET_NUM_VAR(tui->params[0], 1); unibi_out_ext(tui, tui->unibi_ext.sync); - } else { + } else if (!tui->is_invisible) { unibi_out(tui, unibi_cursor_invisible); + tui->is_invisible = true; } } @@ -1318,8 +1311,14 @@ static void tui_flush_end(TUIData *tui) if (tui->sync_output && tui->unibi_ext.sync != -1) { UNIBI_SET_NUM_VAR(tui->params[0], 0); unibi_out_ext(tui, tui->unibi_ext.sync); - } else if (!tui->busy && !tui->want_invisible) { + } + bool should_invisible = tui->busy || tui->want_invisible; + if (tui->is_invisible && !should_invisible) { unibi_out(tui, unibi_cursor_normal); + tui->is_invisible = false; + } else if (!tui->is_invisible && should_invisible) { + unibi_out(tui, unibi_cursor_invisible); + tui->is_invisible = true; } } -- cgit From 89dd939c154d11a7bbb41ac5defb87b13ca10b60 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Wed, 1 Nov 2023 08:24:35 -0500 Subject: refactor(tui): refactor Kitty keyboard query implementation Refactor our implementation of querying for Kitty keyboard protocol support: - Remove usage of the "extkeys" term. This is not standard or really used elsewhere. Use "key encoding" instead - Replace usages of "CSIu" with "Kitty". "Kitty keyboard protocol" is vastly more common than "CSIu" now - Replace the countdown response counter with a simple boolean flag. We don't actually need a countdown counter because we request the primary device attributes along with the Kitty keyboard query, so we will always receive a "terminating event", making a countdown/timer unnecessary - Move the CSI response handling into a dedicated function - Bypass Unibilium for sending key encoding escape sequences. These sequences are not part of terminfo and do not have any parameters, so there's no reason to go through Unibilium --- src/nvim/tui/tui.c | 81 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 35 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index a64f9af454..cdc8f769a1 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -134,8 +134,6 @@ struct TUIData { int save_title, restore_title; int set_underline_style; int set_underline_color; - int enable_extended_keys, disable_extended_keys; - int get_extkeys; int sync; } unibi_ext; char *space_buf; @@ -183,29 +181,34 @@ void tui_start(TUIData **tui_p, int *width, int *height, char **term) *term = tui->term; } -void tui_enable_extkeys(TUIData *tui) +void tui_set_key_encoding(TUIData *tui) + FUNC_ATTR_NONNULL_ALL { - TermInput input = tui->input; - unibi_term *ut = tui->ut; - - switch (input.extkeys_type) { - case kExtkeysCSIu: - tui->unibi_ext.enable_extended_keys = (int)unibi_add_ext_str(ut, "ext.enable_extended_keys", - "\x1b[>1u"); - tui->unibi_ext.disable_extended_keys = (int)unibi_add_ext_str(ut, "ext.disable_extended_keys", - "\x1b[<1u"); + switch (tui->input.key_encoding) { + case kKeyEncodingKitty: + out(tui, S_LEN("\x1b[>1u")); break; - case kExtkeysXterm: - tui->unibi_ext.enable_extended_keys = (int)unibi_add_ext_str(ut, "ext.enable_extended_keys", - "\x1b[>4;2m"); - tui->unibi_ext.disable_extended_keys = (int)unibi_add_ext_str(ut, "ext.disable_extended_keys", - "\x1b[>4;0m"); + case kKeyEncodingXterm: + out(tui, S_LEN("\x1b[>4;2m")); break; - default: + case kKeyEncodingLegacy: break; } +} - unibi_out_ext(tui, tui->unibi_ext.enable_extended_keys); +static void tui_reset_key_encoding(TUIData *tui) + FUNC_ATTR_NONNULL_ALL +{ + switch (tui->input.key_encoding) { + case kKeyEncodingKitty: + out(tui, S_LEN("\x1b[<1u")); + break; + case kKeyEncodingXterm: + out(tui, S_LEN("\x1b[>4;0m")); + break; + case kKeyEncodingLegacy: + break; + } } /// Request the terminal's DEC mode (DECRQM). @@ -244,6 +247,21 @@ void tui_dec_report_mode(TUIData *tui, TerminalDecMode mode, TerminalModeState s } } +/// Query the terminal emulator to see if it supports Kitty's keyboard protocol. +/// +/// Write CSI ? u followed by a primary device attributes request (CSI c). If +/// a primary device attributes response is received without first receiving an +/// answer to the progressive enhancement query (CSI u), then the terminal does +/// not support the Kitty keyboard protocol. +/// +/// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#detection-of-support-for-this-protocol +static void tui_query_kitty_keyboard(TUIData *tui) + FUNC_ATTR_NONNULL_ALL +{ + tui->input.waiting_for_kkp_response = true; + out(tui, S_LEN("\x1b[?u\x1b[c")); +} + static void terminfo_start(TUIData *tui) { tui->scroll_region_is_full_screen = true; @@ -277,9 +295,6 @@ static void terminfo_start(TUIData *tui) tui->unibi_ext.set_cursor_style = -1; tui->unibi_ext.reset_cursor_style = -1; tui->unibi_ext.set_underline_color = -1; - tui->unibi_ext.enable_extended_keys = -1; - tui->unibi_ext.disable_extended_keys = -1; - tui->unibi_ext.get_extkeys = -1; tui->unibi_ext.sync = -1; tui->out_fd = STDOUT_FILENO; tui->out_isatty = os_isatty(tui->out_fd); @@ -358,9 +373,8 @@ static void terminfo_start(TUIData *tui) // mode 2026 tui_dec_request_mode(tui, kDecModeSynchronizedOutput); - // Query the terminal to see if it supports CSI u - tui->input.waiting_for_csiu_response = 5; - unibi_out_ext(tui, tui->unibi_ext.get_extkeys); + // Query the terminal to see if it supports Kitty's keyboard protocol + tui_query_kitty_keyboard(tui); int ret; uv_loop_init(&tui->write_loop); @@ -403,8 +417,10 @@ static void terminfo_stop(TUIData *tui) // Reset cursor to normal before exiting alternate screen. unibi_out(tui, unibi_cursor_normal); unibi_out(tui, unibi_keypad_local); - // Disable extended keys before exiting alternate screen. - unibi_out_ext(tui, tui->unibi_ext.disable_extended_keys); + + // Reset the key encoding + tui_reset_key_encoding(tui); + // May restore old title before exiting alternate screen. tui_set_title(tui, (String)STRING_INIT); if (ui_client_exit_status == 0) { @@ -1949,12 +1965,6 @@ static void patch_terminfo_bugs(TUIData *tui, const char *term, const char *colo #define XTERM_SETAB_16 \ "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e39%;m" - // Query the terminal to see if it supports CSI u key encoding by writing CSI - // ? u followed by a request for the primary device attributes (CSI c) - // See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#detection-of-support-for-this-protocol - tui->unibi_ext.get_extkeys = (int)unibi_add_ext_str(ut, "ext.get_extkeys", - "\x1b[?u\x1b[c"); - // Terminals with 256-colour SGR support despite what terminfo says. if (unibi_get_num(ut, unibi_max_colors) < 256) { // See http://fedoraproject.org/wiki/Features/256_Color_Terminals @@ -2247,8 +2257,9 @@ static void augment_terminfo(TUIData *tui, const char *term, int vte_version, in } if (!kitty && (vte_version == 0 || vte_version >= 5400)) { - // Fallback to Xterm's modifyOtherKeys if terminal does not support CSI u - tui->input.extkeys_type = kExtkeysXterm; + // Fallback to Xterm's modifyOtherKeys if terminal does not support the + // Kitty keyboard protocol + tui->input.key_encoding = kKeyEncodingXterm; } } -- cgit From e80b83bf567523d325c78c71fed04bec9492e07d Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Fri, 17 Nov 2023 12:15:16 -0600 Subject: refactor(tui): use termkey_interpret_modereport The sign extension issue has been fixed upstream, so we no longer need to use our own workaround. --- src/nvim/tui/tui.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index cdc8f769a1..93b891afff 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -211,10 +211,10 @@ static void tui_reset_key_encoding(TUIData *tui) } } -/// Request the terminal's DEC mode (DECRQM). +/// Request the terminal's mode (DECRQM). /// /// @see handle_modereport -static void tui_dec_request_mode(TUIData *tui, TerminalDecMode mode) +static void tui_request_term_mode(TUIData *tui, TermMode mode) FUNC_ATTR_NONNULL_ALL { // 5 bytes for \x1b[?$p, 1 byte for null terminator, 6 bytes for mode digits (more than enough) @@ -224,22 +224,22 @@ static void tui_dec_request_mode(TUIData *tui, TerminalDecMode mode) out(tui, buf, (size_t)len); } -/// Handle a DECRPM response from the terminal. -void tui_dec_report_mode(TUIData *tui, TerminalDecMode mode, TerminalModeState state) +/// Handle a mode report (DECRPM) from the terminal. +void tui_handle_term_mode(TUIData *tui, TermMode mode, TermModeState state) FUNC_ATTR_NONNULL_ALL { switch (state) { - case kTerminalModeNotRecognized: - case kTerminalModePermanentlySet: - case kTerminalModePermanentlyReset: + case kTermModeNotRecognized: + case kTermModePermanentlySet: + case kTermModePermanentlyReset: // If the mode is not recognized, or if the terminal emulator does not allow it to be changed, // then there is nothing to do break; - case kTerminalModeSet: - case kTerminalModeReset: + case kTermModeSet: + case kTermModeReset: // The terminal supports changing the given mode switch (mode) { - case kDecModeSynchronizedOutput: + case kTermModeSynchronizedOutput: // Ref: https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036 tui->unibi_ext.sync = (int)unibi_add_ext_str(tui->ut, "Sync", "\x1b[?2026%?%p1%{1}%-%tl%eh%;"); @@ -371,7 +371,7 @@ static void terminfo_start(TUIData *tui) // Query support for mode 2026 (Synchronized Output). Some terminals also // support an older DCS sequence for synchronized output, but we will only use // mode 2026 - tui_dec_request_mode(tui, kDecModeSynchronizedOutput); + tui_request_term_mode(tui, kTermModeSynchronizedOutput); // Query the terminal to see if it supports Kitty's keyboard protocol tui_query_kitty_keyboard(tui); -- cgit From 1798a4b5e9f0ae56cd800095f79423fea5cae8ca Mon Sep 17 00:00:00 2001 From: dundargoc Date: Thu, 16 Nov 2023 10:59:11 +0100 Subject: build: bump uncrustify version Biggest change is that uncrustify is silent during linting. --- src/nvim/tui/tui.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 93b891afff..21b820d71e 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -2226,9 +2226,12 @@ static void augment_terminfo(TUIData *tui, const char *term, int vte_version, in "\x1b[?2004l"); // For urxvt send BOTH xterm and old urxvt sequences. #8695 tui->unibi_ext.enable_focus_reporting = (int)unibi_add_ext_str(ut, "ext.enable_focus", - rxvt ? "\x1b[?1004h\x1b]777;focus;on\x7" : "\x1b[?1004h"); - tui->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(ut, "ext.disable_focus", - rxvt ? "\x1b[?1004l\x1b]777;focus;off\x7" : "\x1b[?1004l"); + rxvt ? + "\x1b[?1004h\x1b]777;focus;on\x7" : + "\x1b[?1004h"); + tui->unibi_ext.disable_focus_reporting = + (int)unibi_add_ext_str(ut, "ext.disable_focus", + rxvt ? "\x1b[?1004l\x1b]777;focus;off\x7" : "\x1b[?1004l"); tui->unibi_ext.enable_mouse = (int)unibi_add_ext_str(ut, "ext.enable_mouse", "\x1b[?1002h\x1b[?1006h"); tui->unibi_ext.disable_mouse = (int)unibi_add_ext_str(ut, "ext.disable_mouse", -- cgit From a6e3d93421ba13c407a96fac9cc01fa41ec7ad98 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Thu, 16 Nov 2023 10:59:11 +0100 Subject: refactor: enable formatting for ternaries This requires removing the "Inner expression should be aligned" rule from clint as it prevents essentially any formatting regarding ternary operators. --- src/nvim/tui/tui.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 21b820d71e..8e13ce0d1d 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -334,7 +334,7 @@ static void terminfo_start(TUIData *tui) || os_getenv("KONSOLE_DBUS_SESSION"); const char *konsolev_env = os_getenv("KONSOLE_VERSION"); int konsolev = konsolev_env ? (int)strtol(konsolev_env, NULL, 10) - : (konsole ? 1 : 0); + : (konsole ? 1 : 0); patch_terminfo_bugs(tui, term, colorterm, vtev, konsolev, iterm_env, nsterm); augment_terminfo(tui, term, vtev, konsolev, iterm_env, nsterm); @@ -792,11 +792,15 @@ static void cursor_goto(TUIData *tui, int row, int col) if (grid->row == -1) { goto safe_move; } - if (0 == col ? col != grid->col : - row != grid->row ? false : - 1 == col ? 2 < grid->col && cheap_to_print(tui, grid->row, 0, col) : - 2 == col ? 5 < grid->col && cheap_to_print(tui, grid->row, 0, col) : - false) { + if (0 == col + ? col != grid->col + : (row != grid->row + ? false + : (1 == col + ? (2 < grid->col && cheap_to_print(tui, grid->row, 0, col)) + : (2 == col + ? (5 < grid->col && cheap_to_print(tui, grid->row, 0, col)) + : false)))) { // Motion to left margin from anywhere else, or CR + printing chars is // even less expensive than using BSes or CUB. unibi_out(tui, unibi_carriage_return); @@ -2226,9 +2230,9 @@ static void augment_terminfo(TUIData *tui, const char *term, int vte_version, in "\x1b[?2004l"); // For urxvt send BOTH xterm and old urxvt sequences. #8695 tui->unibi_ext.enable_focus_reporting = (int)unibi_add_ext_str(ut, "ext.enable_focus", - rxvt ? - "\x1b[?1004h\x1b]777;focus;on\x7" : - "\x1b[?1004h"); + rxvt + ? "\x1b[?1004h\x1b]777;focus;on\x7" + : "\x1b[?1004h"); tui->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(ut, "ext.disable_focus", rxvt ? "\x1b[?1004l\x1b]777;focus;off\x7" : "\x1b[?1004l"); -- cgit From 488038580934f301c1528a14548ec0cabd16c2cd Mon Sep 17 00:00:00 2001 From: dundargoc Date: Fri, 10 Nov 2023 14:06:04 +0100 Subject: build: adjust clang-tidy warning exclusion logic Enable all clang-tidy warnings by default instead of disabling them. This ensures that we don't miss useful warnings on each clang-tidy version upgrade. A drawback of this is that it will force us to either fix or adjust the warnings as soon as possible. --- src/nvim/tui/tui.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 8e13ce0d1d..90309b6600 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1774,9 +1774,6 @@ static void patch_terminfo_bugs(TUIData *tui, const char *term, const char *colo { unibi_term *ut = tui->ut; const char *xterm_version = os_getenv("XTERM_VERSION"); -#if 0 // We don't need to identify this specifically, for now. - bool roxterm = !!os_getenv("ROXTERM_ID"); -#endif bool xterm = terminfo_is_term_family(term, "xterm") // Treat Terminal.app as generic xterm-like, for now. || nsterm; -- cgit From 53cc835b51546f9ff68facebab2e0c6e97585e5b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 24 Nov 2023 11:31:07 +0800 Subject: refactor(tui): remove unnecessary scheduling when suspending (#26190) Nvim no longer calls loop_poll_events() when suspending, so it isn't necessary to schedule suspend_event. --- src/nvim/tui/tui.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 90309b6600..323227d4c0 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -15,9 +15,7 @@ #include "nvim/api/private/helpers.h" #include "nvim/ascii.h" #include "nvim/cursor_shape.h" -#include "nvim/event/defs.h" #include "nvim/event/loop.h" -#include "nvim/event/multiqueue.h" #include "nvim/event/signal.h" #include "nvim/event/stream.h" #include "nvim/globals.h" @@ -36,7 +34,6 @@ #include "nvim/tui/tui.h" #include "nvim/types.h" #include "nvim/ugrid.h" -#include "nvim/ui.h" #include "nvim/ui_client.h" #ifdef MSWIN @@ -1424,10 +1421,10 @@ static void show_verbose_terminfo(TUIData *tui) api_free_array(args); } -#ifdef UNIX -static void suspend_event(void **argv) +void tui_suspend(TUIData *tui) { - TUIData *tui = argv[0]; +// on a non-UNIX system, this is a no-op +#ifdef UNIX ui_client_detach(); bool enable_mouse = tui->mouse_enabled; tui_terminal_stop(tui); @@ -1442,18 +1439,6 @@ static void suspend_event(void **argv) } stream_set_blocking(tui->input.in_fd, false); // libuv expects this ui_client_attach(tui->width, tui->height, tui->term); -} -#endif - -void tui_suspend(TUIData *tui) -{ -// on a non-UNIX system, this is a no-op -#ifdef UNIX - // kill(0, SIGTSTP) won't stop the UI thread, so we must poll for SIGCONT - // before continuing. This is done in another callback to avoid - // loop_poll_events recursion - multiqueue_put_event(resize_events, - event_create(suspend_event, 1, tui)); #endif } -- cgit From a827003e3052c6d9ee7bdb71518182e9bd76317d Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 25 Nov 2023 11:32:32 +0100 Subject: build: rework IWYU mapping files Create mapping to most of the C spec and some POSIX specific functions. This is more robust than relying files shipped with IWYU. --- src/nvim/tui/tui.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 323227d4c0..4bbdea8def 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -34,6 +34,7 @@ #include "nvim/tui/tui.h" #include "nvim/types.h" #include "nvim/ugrid.h" +#include "nvim/ui.h" #include "nvim/ui_client.h" #ifdef MSWIN -- cgit From 574d25642fc9ca65b396633aeab6e2d32778b642 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 Nov 2023 17:21:58 +0800 Subject: refactor: move Arena and ArenaMem to memory_defs.h (#26240) --- src/nvim/tui/tui.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 4bbdea8def..0272c974d5 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1051,7 +1051,7 @@ void tui_grid_cursor_goto(TUIData *tui, Integer grid, Integer row, Integer col) tui->col = (int)col; } -CursorShape tui_cursor_decode_shape(const char *shape_str) +static CursorShape tui_cursor_decode_shape(const char *shape_str) { CursorShape shape; if (strequal(shape_str, "block")) { @@ -1144,7 +1144,7 @@ void tui_mouse_off(TUIData *tui) } } -void tui_set_mode(TUIData *tui, ModeShape mode) +static void tui_set_mode(TUIData *tui, ModeShape mode) { if (!cursor_style_enabled) { return; -- cgit From 8b428ca8b79ebb7b36c3e403ff3bcb6924a635a6 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 16:00:21 +0100 Subject: build(IWYU): fix includes for func_attr.h --- src/nvim/tui/tui.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 0272c974d5..dbc1187273 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -18,6 +18,7 @@ #include "nvim/event/loop.h" #include "nvim/event/signal.h" #include "nvim/event/stream.h" +#include "nvim/func_attr.h" #include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/highlight_defs.h" -- cgit From 6c14ae6bfaf51415b555e9a6b85d1d280976358d Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 20:27:32 +0100 Subject: refactor: rename types.h to types_defs.h --- src/nvim/tui/tui.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index dbc1187273..3b00afed40 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -33,7 +33,7 @@ #include "nvim/tui/input.h" #include "nvim/tui/terminfo.h" #include "nvim/tui/tui.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" #include "nvim/ugrid.h" #include "nvim/ui.h" #include "nvim/ui_client.h" -- cgit From 79b6ff28ad1204fbb4199b9092f5c578d88cb28e Mon Sep 17 00:00:00 2001 From: dundargoc Date: Tue, 28 Nov 2023 20:31:00 +0100 Subject: refactor: fix headers with IWYU --- src/nvim/tui/tui.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/tui/tui.c') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 3b00afed40..197bbcabb5 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -13,7 +13,7 @@ #include "klib/kvec.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/cursor_shape.h" #include "nvim/event/loop.h" #include "nvim/event/signal.h" @@ -23,7 +23,7 @@ #include "nvim/grid.h" #include "nvim/highlight_defs.h" #include "nvim/log.h" -#include "nvim/macros.h" +#include "nvim/macros_defs.h" #include "nvim/main.h" #include "nvim/mbyte.h" #include "nvim/memory.h" -- cgit