mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 19:25:11 -07:00
tui: improve support for GNU Screen (#12098)
Wrapping it in DCS allows the following features to work with GNU Screen. - Changing the cursor style. - bracketed paste. - focus reporting.
This commit is contained in:
parent
3de9452abf
commit
f3ffe0b325
@ -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
|
||||
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user