aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/tui/tui.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/tui/tui.c')
-rw-r--r--src/nvim/tui/tui.c157
1 files changed, 99 insertions, 58 deletions
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 7fae34d33f..2a9530defb 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -23,6 +23,7 @@
#include "nvim/globals.h"
#include "nvim/grid.h"
#include "nvim/grid_defs.h"
+#include "nvim/highlight.h"
#include "nvim/highlight_defs.h"
#include "nvim/log.h"
#include "nvim/macros_defs.h"
@@ -165,6 +166,15 @@ void tui_start(TUIData **tui_p, int *width, int *height, char **term, bool *rgb)
tui->seen_error_exit = 0;
tui->loop = &main_loop;
tui->url = -1;
+ // Because setting the default colors is delayed until after startup to avoid
+ // flickering with the default colorscheme background, any flush that happens
+ // during startup in turn would result in clearing invalidated regions with
+ // uninitialized attrs(black). Instead initialize clear_attrs with current
+ // terminal background so that it is at least not perceived as flickering, even
+ // though it may be different from the colorscheme that is set during startup.
+ tui->clear_attrs.rgb_bg_color = normal_bg;
+ tui->clear_attrs.cterm_bg_color = (int16_t)cterm_normal_bg_color;
+
kv_init(tui->invalid_regions);
kv_init(tui->urlbuf);
signal_watcher_init(tui->loop, &tui->winch_handle, tui);
@@ -189,36 +199,6 @@ void tui_start(TUIData **tui_p, int *width, int *height, char **term, bool *rgb)
*rgb = tui->rgb;
}
-void tui_set_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;2m"));
- break;
- case kKeyEncodingLegacy:
- break;
- }
-}
-
-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 mode (DECRQM).
///
/// @see handle_modereport
@@ -255,6 +235,26 @@ void tui_handle_term_mode(TUIData *tui, TermMode mode, TermModeState state)
}
}
+/// Query the terminal emulator to see if it supports extended underline.
+static void tui_query_extended_underline(TUIData *tui)
+{
+ // Try to set an undercurl using an SGR sequence, followed by a DECRQSS SGR query.
+ // Reset attributes first, as other code may have set attributes.
+ out(tui, S_LEN("\x1b[0m\x1b[4:3m\x1bP$qm\x1b\\"));
+ tui->print_attr_id = -1;
+}
+
+void tui_enable_extended_underline(TUIData *tui)
+{
+ if (tui->unibi_ext.set_underline_style == -1) {
+ tui->unibi_ext.set_underline_style = (int)unibi_add_ext_str(tui->ut, "ext.set_underline_style",
+ "\x1b[4:%p1%dm");
+ }
+ // Only support colon syntax. #9270
+ tui->unibi_ext.set_underline_color = (int)unibi_add_ext_str(tui->ut, "ext.set_underline_color",
+ "\x1b[58:2::%p1%d:%p2%d:%p3%dm");
+}
+
/// 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
@@ -270,6 +270,36 @@ static void tui_query_kitty_keyboard(TUIData *tui)
out(tui, S_LEN("\x1b[?u\x1b[c"));
}
+void tui_set_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;2m"));
+ break;
+ case kKeyEncodingLegacy:
+ break;
+ }
+}
+
+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;
+ }
+}
+
/// Enable the alternate screen and emit other control sequences to start the TUI.
///
/// This is also called when the TUI is resumed after being suspended. We reinitialize all state
@@ -306,6 +336,7 @@ 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.set_underline_style = -1;
tui->unibi_ext.set_underline_color = -1;
tui->unibi_ext.sync = -1;
tui->out_fd = STDOUT_FILENO;
@@ -347,12 +378,16 @@ static void terminfo_start(TUIData *tui)
const char *konsolev_env = os_getenv("KONSOLE_VERSION");
int konsolev = konsolev_env ? (int)strtol(konsolev_env, NULL, 10)
: (konsole ? 1 : 0);
+ bool wezterm = strequal(termprg, "WezTerm");
+ const char *weztermv = wezterm ? os_getenv("TERM_PROGRAM_VERSION") : NULL;
+ bool screen = terminfo_is_term_family(term, "screen");
+ bool tmux = terminfo_is_term_family(term, "tmux") || !!os_getenv("TMUX");
// truecolor support must be checked before patching/augmenting terminfo
tui->rgb = term_has_truecolor(tui, colorterm);
patch_terminfo_bugs(tui, term, colorterm, vtev, konsolev, iterm_env, nsterm);
- augment_terminfo(tui, term, vtev, konsolev, iterm_env, nsterm);
+ augment_terminfo(tui, term, vtev, konsolev, weztermv, iterm_env, nsterm);
tui->can_change_scroll_region =
!!unibi_get_str(tui->ut, unibi_change_scroll_region);
tui->can_set_lr_margin =
@@ -385,8 +420,18 @@ 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_request_term_mode(tui, kTermModeSynchronizedOutput);
+ // mode 2026.
+ // Some terminals (such as Terminal.app) do not support DECRQM, so skip the query.
+ if (!nsterm) {
+ tui_request_term_mode(tui, kTermModeSynchronizedOutput);
+ }
+
+ // Don't use DECRQSS in screen or tmux, as they behave strangely when receiving it.
+ // Terminal.app also doesn't support DECRQSS.
+ if (tui->unibi_ext.set_underline_style == -1 && !(screen || tmux || nsterm)) {
+ // Query the terminal to see if it supports extended underline.
+ tui_query_extended_underline(tui);
+ }
// Query the terminal to see if it supports Kitty's keyboard protocol
tui_query_kitty_keyboard(tui);
@@ -457,10 +502,6 @@ static void terminfo_stop(TUIData *tui)
// 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);
@@ -932,17 +973,17 @@ static void print_spaces(TUIData *tui, int width)
}
}
-/// Move cursor to the position given by `row` and `col` and print the character in `cell`.
-/// This allows the grid and the host terminal to assume different widths of ambiguous-width chars.
+/// Move cursor to the position given by `row` and `col` and print the char in `cell`.
+/// Allows grid and host terminal to assume different widths of ambiguous-width chars.
///
-/// @param is_doublewidth whether the character is double-width on the grid.
-/// If true and the character is ambiguous-width, clear two cells.
+/// @param is_doublewidth whether the char is double-width on the grid.
+/// If true and the char is ambiguous-width, clear two cells.
static void print_cell_at_pos(TUIData *tui, int row, int col, UCell *cell, bool is_doublewidth)
{
UGrid *grid = &tui->grid;
if (grid->row == -1 && cell->data == NUL) {
- // If cursor needs to repositioned and there is nothing to print, don't move cursor.
+ // If cursor needs repositioning and there is nothing to print, don't move cursor.
return;
}
@@ -950,10 +991,14 @@ static void print_cell_at_pos(TUIData *tui, int row, int col, UCell *cell, bool
char buf[MAX_SCHAR_SIZE];
schar_get(buf, cell->data);
- bool is_ambiwidth = utf_ambiguous_width(utf_ptr2char(buf));
- if (is_ambiwidth && is_doublewidth) {
+ int c = utf_ptr2char(buf);
+ bool is_ambiwidth = utf_ambiguous_width(c);
+ if (is_doublewidth && (is_ambiwidth || utf_char2cells(c) == 1)) {
+ // If the server used setcellwidths() to treat a single-width char as double-width,
+ // it needs to be treated like an ambiguous-width char.
+ is_ambiwidth = true;
// Clear the two screen cells.
- // If the character is single-width in the host terminal it won't change the second cell.
+ // If the char is single-width in host terminal it won't change the second cell.
update_attrs(tui, cell->attr);
print_spaces(tui, 2);
cursor_goto(tui, row, col);
@@ -962,7 +1007,7 @@ static void print_cell_at_pos(TUIData *tui, int row, int col, UCell *cell, bool
print_cell(tui, buf, cell->attr);
if (is_ambiwidth) {
- // Force repositioning cursor after printing an ambiguous-width character.
+ // Force repositioning cursor after printing an ambiguous-width char.
grid->row = -1;
}
}
@@ -1206,7 +1251,7 @@ static void tui_set_mode(TUIData *tui, ModeShape mode)
// 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);
- } else {
+ } else if (!tui->want_invisible && aep.rgb_bg_color >= 0) {
char hexbuf[8];
if (tui->set_cursor_color_as_str) {
snprintf(hexbuf, 7 + 1, "#%06x", aep.rgb_bg_color);
@@ -1643,7 +1688,7 @@ static void invalidate(TUIData *tui, int top, int bot, int left, int right)
static void ensure_space_buf_size(TUIData *tui, size_t len)
{
if (len > tui->space_buf_len) {
- tui->space_buf = xrealloc(tui->space_buf, len * sizeof *tui->space_buf);
+ tui->space_buf = xrealloc(tui->space_buf, len);
memset(tui->space_buf + tui->space_buf_len, ' ', len - tui->space_buf_len);
tui->space_buf_len = len;
}
@@ -2168,7 +2213,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, int vte_version, int konsolev,
- bool iterm_env, bool nsterm)
+ const char *weztermv, bool iterm_env, bool nsterm)
{
unibi_term *ut = tui->ut;
bool xterm = terminfo_is_term_family(term, "xterm")
@@ -2327,16 +2372,12 @@ static void augment_terminfo(TUIData *tui, const char *term, int vte_version, in
if (tui->unibi_ext.set_underline_style == -1) {
int ext_bool_Su = unibi_find_ext_bool(ut, "Su"); // used by kitty
if (vte_version >= 5102 || konsolev >= 221170
- || (ext_bool_Su != -1
- && unibi_get_ext_bool(ut, (size_t)ext_bool_Su))) {
- tui->unibi_ext.set_underline_style = (int)unibi_add_ext_str(ut, "ext.set_underline_style",
- "\x1b[4:%p1%dm");
+ || (ext_bool_Su != -1 && unibi_get_ext_bool(ut, (size_t)ext_bool_Su))
+ || (weztermv != NULL && strcmp(weztermv, "20210203-095643") > 0)) {
+ tui_enable_extended_underline(tui);
}
- }
- if (tui->unibi_ext.set_underline_style != -1) {
- // Only support colon syntax. #9270
- tui->unibi_ext.set_underline_color = (int)unibi_add_ext_str(ut, "ext.set_underline_color",
- "\x1b[58:2::%p1%d:%p2%d:%p3%dm");
+ } else {
+ tui_enable_extended_underline(tui);
}
if (!kitty && (vte_version == 0 || vte_version >= 5400)) {