diff options
Diffstat (limited to 'src/nvim/tui/tui.c')
| -rw-r--r-- | src/nvim/tui/tui.c | 78 |
1 files changed, 46 insertions, 32 deletions
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index a1f56d2695..57a2b896f7 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -57,14 +57,17 @@ typedef struct { bool busy; HlAttrs attrs, print_attrs; Cell **screen; + int showing_mode; struct { int enable_mouse, disable_mouse; int enable_bracketed_paste, disable_bracketed_paste; - int enter_insert_mode, exit_insert_mode; + int enter_insert_mode, enter_replace_mode, exit_insert_mode; int set_rgb_foreground, set_rgb_background; } unibi_ext; } TUIData; +static bool volatile got_winch = false; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "tui/tui.c.generated.h" #endif @@ -98,11 +101,13 @@ UI *tui_start(void) data->can_use_terminal_scroll = true; data->bufpos = 0; data->bufsize = sizeof(data->buf) - CNORM_COMMAND_MAX_SIZE; + data->showing_mode = 0; data->unibi_ext.enable_mouse = -1; data->unibi_ext.disable_mouse = -1; data->unibi_ext.enable_bracketed_paste = -1; data->unibi_ext.disable_bracketed_paste = -1; data->unibi_ext.enter_insert_mode = -1; + data->unibi_ext.enter_replace_mode = -1; data->unibi_ext.exit_insert_mode = -1; // write output to stderr if stdout is not a tty @@ -148,8 +153,7 @@ UI *tui_start(void) ui->busy_stop = tui_busy_stop; ui->mouse_on = tui_mouse_on; ui->mouse_off = tui_mouse_off; - ui->insert_mode = tui_insert_mode; - ui->normal_mode = tui_normal_mode; + ui->mode_change = tui_mode_change; ui->set_scroll_region = tui_set_scroll_region; ui->scroll = tui_scroll; ui->highlight_set = tui_highlight_set; @@ -178,7 +182,7 @@ static void tui_stop(UI *ui) // Destroy input stuff term_input_destroy(data->input); // Destroy output stuff - tui_normal_mode(ui); + tui_mode_change(ui, NORMAL); tui_mouse_off(ui); unibi_out(ui, unibi_exit_attribute_mode); // cursor should be set to normal before exiting alternate screen @@ -201,23 +205,14 @@ static void tui_stop(UI *ui) xfree(ui); } -static void try_resize(Event ev) +static void sigwinch_cb(SignalWatcher *watcher, int signum, void *data) { - UI *ui = ev.data; + got_winch = true; + UI *ui = data; update_size(ui); ui_refresh(); } -static void sigwinch_cb(SignalWatcher *watcher, int signum, void *data) -{ - // Queue the event because resizing can result in recursive event_poll calls - // FIXME(blueyed): TUI does not resize properly when not deferred. Why? #2322 - loop_push_event(&loop, (Event) { - .data = data, - .handler = try_resize - }, true); -} - static bool attrs_differ(HlAttrs a1, HlAttrs a2) { return a1.foreground != a2.foreground || a1.background != a2.background @@ -352,10 +347,13 @@ static void tui_resize(UI *ui, int width, int height) data->scroll_region.right = width - 1; data->row = data->col = 0; - // try to resize the terminal window - char r[16]; // enough for 9999x9999 - snprintf(r, sizeof(r), "\x1b[8;%d;%dt", height, width); - out(ui, r, strlen(r)); + if (!got_winch) { // Try to resize the terminal window. + char r[16]; // enough for 9999x9999 + snprintf(r, sizeof(r), "\x1b[8;%d;%dt", height, width); + out(ui, r, strlen(r)); + } else { // Already handled the SIGWINCH signal; avoid double-resize. + got_winch = false; + } } static void tui_clear(UI *ui) @@ -404,16 +402,25 @@ static void tui_mouse_off(UI *ui) data->mouse_enabled = false; } -static void tui_insert_mode(UI *ui) +static void tui_mode_change(UI *ui, int mode) { TUIData *data = ui->data; - unibi_out(ui, data->unibi_ext.enter_insert_mode); -} -static void tui_normal_mode(UI *ui) -{ - TUIData *data = ui->data; - unibi_out(ui, data->unibi_ext.exit_insert_mode); + if (mode == INSERT) { + if (data->showing_mode != INSERT) { + unibi_out(ui, data->unibi_ext.enter_insert_mode); + } + } else if (mode == REPLACE) { + if (data->showing_mode != REPLACE) { + unibi_out(ui, data->unibi_ext.enter_replace_mode); + } + } else { + assert(mode == NORMAL); + if (data->showing_mode != NORMAL) { + unibi_out(ui, data->unibi_ext.exit_insert_mode); + } + } + data->showing_mode = mode; } static void tui_set_scroll_region(UI *ui, int top, int bot, int left, @@ -798,18 +805,25 @@ static void fix_terminfo(TUIData *data) #define TMUX_WRAP(seq) (inside_tmux ? "\x1bPtmux;\x1b" seq "\x1b\\" : seq) // Support changing cursor shape on some popular terminals. const char *term_prog = os_getenv("TERM_PROGRAM"); + const char *vte_version = os_getenv("VTE_VERSION"); - if ((term_prog && !strcmp(term_prog, "iTerm.app")) - || os_getenv("ITERM_SESSION_ID") != NULL) { - // iterm + if ((term_prog && !strcmp(term_prog, "Konsole")) + || os_getenv("KONSOLE_DBUS_SESSION") != NULL) { + // Konsole uses a proprietary escape code to set the cursor shape + // and does not suppport DECSCUSR. data->unibi_ext.enter_insert_mode = (int)unibi_add_ext_str(ut, NULL, TMUX_WRAP("\x1b]50;CursorShape=1;BlinkingCursorEnabled=1\x07")); + data->unibi_ext.enter_replace_mode = (int)unibi_add_ext_str(ut, NULL, + TMUX_WRAP("\x1b]50;CursorShape=2;BlinkingCursorEnabled=1\x07")); data->unibi_ext.exit_insert_mode = (int)unibi_add_ext_str(ut, NULL, TMUX_WRAP("\x1b]50;CursorShape=0;BlinkingCursorEnabled=0\x07")); - } else { - // xterm-like sequences for blinking bar and solid block + } else if (!vte_version || atoi(vte_version) >= 3900) { + // Assume that the terminal supports DECSCUSR unless it is an + // old VTE based terminal data->unibi_ext.enter_insert_mode = (int)unibi_add_ext_str(ut, NULL, TMUX_WRAP("\x1b[5 q")); + data->unibi_ext.enter_replace_mode = (int)unibi_add_ext_str(ut, NULL, + TMUX_WRAP("\x1b[3 q")); data->unibi_ext.exit_insert_mode = (int)unibi_add_ext_str(ut, NULL, TMUX_WRAP("\x1b[2 q")); } |