diff options
-rw-r--r-- | src/nvim/ascii.h | 2 | ||||
-rw-r--r-- | src/nvim/tui/tui.c | 147 |
2 files changed, 106 insertions, 43 deletions
diff --git a/src/nvim/ascii.h b/src/nvim/ascii.h index 2397af27cc..31423e79af 100644 --- a/src/nvim/ascii.h +++ b/src/nvim/ascii.h @@ -31,7 +31,9 @@ #define CSI 0x9b // Control Sequence Introducer #define CSI_STR "\233" #define DCS 0x90 // Device Control String +#define DCS_STR "\033P" #define STERM 0x9c // String Terminator +#define STERM_STR "\033\\" #define POUND 0xA3 diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 1aa8df905e..228545a844 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -49,10 +49,15 @@ #define OUTBUF_SIZE 0xffff #define TOO_MANY_EVENTS 1000000 -#define STARTS_WITH(str, prefix) (strlen(str) >= (sizeof(prefix) - 1) \ - && 0 == memcmp((str), (prefix), sizeof(prefix) - 1)) -#define TMUX_WRAP(is_tmux, seq) ((is_tmux) \ - ? "\x1bPtmux;\x1b" seq "\x1b\\" : seq) +#define STARTS_WITH(str, prefix) \ + (strlen(str) >= (sizeof(prefix) - 1) && 0 == memcmp((str), (prefix), \ + sizeof(prefix) - 1)) +#define SCREEN_WRAP(is_screen, seq) ((is_screen) \ + ? DCS_STR seq STERM_STR : seq) +#define SCREEN_TMUX_WRAP(is_screen, is_tmux, seq) \ + ((is_screen) \ + ? DCS_STR seq STERM_STR : (is_tmux) \ + ? DCS_STR "tmux;\x1b" seq STERM_STR : seq) #define LINUXSET0C "\x1b[?0c" #define LINUXSET1C "\x1b[?1c" @@ -1538,7 +1543,10 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, bool rxvt = terminfo_is_term_family(term, "rxvt"); bool teraterm = terminfo_is_term_family(term, "teraterm"); bool putty = terminfo_is_term_family(term, "putty"); - bool screen = terminfo_is_term_family(term, "screen"); + bool screen = terminfo_is_term_family(term, "screen") && !os_getenv("TMUX"); + bool screen_host_linuxvt = + terminfo_is_term_family(screen && term[6] == '.' + ? term + 7 : NULL, "linux"); bool tmux = terminfo_is_term_family(term, "tmux") || !!os_getenv("TMUX"); bool st = terminfo_is_term_family(term, "st"); bool gnome = terminfo_is_term_family(term, "gnome") @@ -1697,8 +1705,9 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, #define XTERM_SETAB_16 \ "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e39%;m" - data->unibi_ext.get_bg = (int)unibi_add_ext_str(ut, "ext.get_bg", - "\x1b]11;?\x07"); + data->unibi_ext.get_bg = + (int)unibi_add_ext_str(ut, "ext.get_bg", + SCREEN_TMUX_WRAP(screen, tmux, "\x1b]11;?\x07")); // Terminals with 256-colour SGR support despite what terminfo says. if (unibi_get_num(ut, unibi_max_colors) < 256) { @@ -1733,6 +1742,32 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, data->unibi_ext.set_cursor_style = unibi_find_ext_str(ut, "Ss"); } + // GNU Screen does not have Ss/Se. When terminfo has Ss/Se, it is wrapped with + // DCS because it is inherited from the host terminal. + if (screen) { + size_t len; + size_t dcs_st_len = strlen(DCS_STR) + strlen(STERM_STR); + if (-1 != data->unibi_ext.set_cursor_style) { + const char *orig_ss = + unibi_get_ext_str(data->ut, (size_t)data->unibi_ext.reset_cursor_style); + len = STRLEN(orig_ss) + dcs_st_len + 1; + char *ss = xmalloc(len); + snprintf(ss, len, "%s%s%s", DCS_STR, orig_ss, STERM_STR); + unibi_set_ext_str(data->ut, (size_t)data->unibi_ext.set_cursor_style, ss); + xfree(ss); + } + if (-1 != data->unibi_ext.reset_cursor_style) { + const char *orig_se = + unibi_get_ext_str(data->ut, (size_t)data->unibi_ext.reset_cursor_style); + len = strlen(orig_se) + dcs_st_len + 1; + char *se = xmalloc(len); + snprintf(se, len, "%s%s%s", DCS_STR, orig_se, STERM_STR); + unibi_set_ext_str(data->ut, + (size_t)data->unibi_ext.reset_cursor_style, se); + xfree(se); + } + } + // Dickey ncurses terminfo includes Ss/Se capabilities since 2011-07-14. So // adding them to terminal types, that have such control sequences but lack // the correct terminfo entries, is a fixup, not an augmentation. @@ -1748,7 +1783,12 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, || (konsolev >= 180770) // #9364 || tmux // per tmux manual page // https://lists.gnu.org/archive/html/screen-devel/2013-03/msg00000.html - || screen + || (screen + && (!screen_host_linuxvt + || (screen_host_linuxvt + && (xterm_version || (vte_version > 0) || colorterm)))) + // Since GNU Screen does not support DECSCUSR, DECSCUSR is wrapped + // in DCS and output to the host terminal. || st // #7641 || rxvt // per command.C // per analysis of VT100Terminal.m @@ -1761,34 +1801,43 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, || (linuxvt && (xterm_version || (vte_version > 0) || colorterm)))) { data->unibi_ext.set_cursor_style = - (int)unibi_add_ext_str(ut, "Ss", "\x1b[%p1%d q"); + (int)unibi_add_ext_str(ut, "Ss", SCREEN_WRAP(screen, "\x1b[%p1%d q")); if (-1 == data->unibi_ext.reset_cursor_style) { data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se", ""); } unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style, - "\x1b[ q"); - } else if (linuxvt) { + SCREEN_WRAP(screen, "\x1b[ q")); + } else if (linuxvt || screen_host_linuxvt) { // Linux uses an idiosyncratic escape code to set the cursor shape and // does not support DECSCUSR. // See http://linuxgazette.net/137/anonymous.html for more info - data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss", - "\x1b[?" - "%?" - // The parameter passed to Ss is the DECSCUSR parameter, so the - // terminal capability has to translate into the Linux idiosyncratic - // parameter. - // - // linuxvt only supports block and underline. It is also only - // possible to have a steady block (no steady underline) - "%p1%{2}%<" "%t%{8}" // blink block - "%e%p1%{2}%=" "%t%{112}" // steady block - "%e%p1%{3}%=" "%t%{4}" // blink underline (set to half block) - "%e%p1%{4}%=" "%t%{4}" // steady underline - "%e%p1%{5}%=" "%t%{2}" // blink bar (set to underline) - "%e%p1%{6}%=" "%t%{2}" // steady bar - "%e%{0}" // anything else - "%;" "%dc"); + // + // Since gnu Screen does not have Ss/Se, if the host terminal is a linux + // console that does not support xterm extensions, it will wraps the + // linux-specific sequence in DCS and outputs it. + data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str( + ut, "Ss", + SCREEN_WRAP(screen, + "\x1b[?" + "%?" + // The parameter passed to Ss is the DECSCUSR parameter, + // so the + // terminal capability has to translate into the Linux + // idiosyncratic parameter. + // + // linuxvt only supports block and underline. It is also + // only possible to have a steady block (no steady + // underline) + "%p1%{2}%<" "%t%{8}" // blink block + "%e%p1%{2}%=" "%t%{112}" // steady block + "%e%p1%{3}%=" "%t%{4}" // blink underline (set to half + // block) + "%e%p1%{4}%=" "%t%{4}" // steady underline + "%e%p1%{5}%=" "%t%{2}" // blink bar (set to underline) + "%e%p1%{6}%=" "%t%{2}" // steady bar + "%e%{0}" // anything else + "%;" "%dc")); if (-1 == data->unibi_ext.reset_cursor_style) { data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se", ""); @@ -1798,21 +1847,25 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, } else if (konsolev > 0 && konsolev < 180770) { // Konsole before version 18.07.70: set up a nonce profile. This has // side-effects on temporary font resizing. #6798 - data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss", - TMUX_WRAP(tmux, "\x1b]50;CursorShape=%?" - "%p1%{3}%<" "%t%{0}" // block - "%e%p1%{5}%<" "%t%{2}" // underline - "%e%{1}" // everything else is bar - "%;%d;BlinkingCursorEnabled=%?" - "%p1%{1}%<" "%t%{1}" // Fortunately if we exclude zero as special, - "%e%p1%{1}%&" // in all other cases we can treat bit #0 as a flag. - "%;%d\x07")); + data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str( + ut, "Ss", + SCREEN_TMUX_WRAP(screen, tmux, + "\x1b]50;CursorShape=%?" + "%p1%{3}%<" "%t%{0}" // block + "%e%p1%{5}%<" "%t%{2}" // underline + "%e%{1}" // everything else is bar + "%;%d;BlinkingCursorEnabled=%?" + "%p1%{1}%<" "%t%{1}" // Fortunately if we exclude + // zero as special, + "%e%p1%{1}%&" // in all other c2ses we can treat bit + // #0 as a flag. + "%;%d\x07")); if (-1 == data->unibi_ext.reset_cursor_style) { data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se", ""); } unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style, - "\x1b]50;\x07"); + SCREEN_TMUX_WRAP(screen, tmux, "\x1b]50;\x07")); } } } @@ -1841,6 +1894,8 @@ static void augment_terminfo(TUIData *data, const char *term, bool alacritty = terminfo_is_term_family(term, "alacritty"); // None of the following work over SSH; see :help TERM . bool iterm_pretending_xterm = xterm && iterm_env; + bool screen_host_rxvt = + terminfo_is_term_family(screen && term[6] == '.' ? term + 7 : NULL, "rxvt"); const char *xterm_version = os_getenv("XTERM_VERSION"); bool true_xterm = xterm && !!xterm_version && !bsdvt; @@ -1910,7 +1965,7 @@ static void augment_terminfo(TUIData *data, const char *term, // all panes, which is not particularly desirable. A better approach // would use a tmux control sequence and an extra if(screen) test. data->unibi_ext.set_cursor_color = (int)unibi_add_ext_str( - ut, NULL, TMUX_WRAP(tmux, "\033]Pl%p1%06x\033\\")); + ut, NULL, SCREEN_TMUX_WRAP(screen, tmux, "\033]Pl%p1%06x\033\\")); } else if ((xterm || rxvt || tmux || alacritty) && (vte_version == 0 || vte_version >= 3900)) { // Supported in urxvt, newer VTE. @@ -1930,21 +1985,27 @@ static void augment_terminfo(TUIData *data, const char *term, /// Terminals usually ignore unrecognized private modes, and there is no /// known ambiguity with these. So we just set them unconditionally. + /// If the DECSET is not supported by GNU Screen, it is wrapped with DCS and + /// sent to the host terminal. data->unibi_ext.enable_lr_margin = (int)unibi_add_ext_str( ut, "ext.enable_lr_margin", "\x1b[?69h"); data->unibi_ext.disable_lr_margin = (int)unibi_add_ext_str( ut, "ext.disable_lr_margin", "\x1b[?69l"); data->unibi_ext.enable_bracketed_paste = (int)unibi_add_ext_str( - ut, "ext.enable_bpaste", "\x1b[?2004h"); + ut, "ext.enable_bpaste", SCREEN_WRAP(screen, "\x1b[?2004h")); data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str( - ut, "ext.disable_bpaste", "\x1b[?2004l"); + ut, "ext.disable_bpaste", SCREEN_WRAP(screen, "\x1b[?2004l")); // For urxvt send BOTH xterm and old urxvt sequences. #8695 data->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 || screen_host_rxvt) + ? SCREEN_WRAP(screen, "\x1b[?1004h\x1b]777;focus;on\x7") + : SCREEN_WRAP(screen, "\x1b[?1004h")); data->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 || screen_host_rxvt) + ? SCREEN_WRAP(screen, "\x1b[?1004l\x1b]777;focus;off\x7") + : SCREEN_WRAP(screen, "\x1b[?1004l")); data->unibi_ext.enable_mouse = (int)unibi_add_ext_str( ut, "ext.enable_mouse", "\x1b[?1002h\x1b[?1006h"); data->unibi_ext.disable_mouse = (int)unibi_add_ext_str( |