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.c210
1 files changed, 97 insertions, 113 deletions
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index bfd9435c49..62d7dc8b18 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -52,15 +52,10 @@
#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 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 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 LINUXSET0C "\x1b[?0c"
#define LINUXSET1C "\x1b[?1c"
@@ -113,6 +108,7 @@ typedef struct {
bool cork, overflow;
bool cursor_color_changed;
bool is_starting;
+ FILE *screenshot;
cursorentry_T cursor_shapes[SHAPE_IDX_COUNT];
HlAttrs clear_attrs;
kvec_t(HlAttrs) attrs;
@@ -172,6 +168,7 @@ UI *tui_start(void)
ui->suspend = tui_suspend;
ui->set_title = tui_set_title;
ui->set_icon = tui_set_icon;
+ ui->screenshot = tui_screenshot;
ui->option_set= tui_option_set;
ui->raw_line = tui_raw_line;
@@ -319,7 +316,13 @@ static void terminfo_start(UI *ui)
#ifdef WIN32
uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_RAW);
#else
- uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO);
+ int retry_count = 10;
+ // A signal may cause uv_tty_set_mode() to fail (e.g., SIGCONT). Retry a
+ // few times. #12322
+ while (uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO) == UV_EINTR
+ && retry_count > 0) {
+ retry_count--;
+ }
#endif
} else {
uv_pipe_init(&data->write_loop, &data->output_handle.pipe, 0);
@@ -417,6 +420,7 @@ static void tui_main(UIBridgeData *bridge, UI *ui)
data->bridge = bridge;
data->loop = &tui_loop;
data->is_starting = true;
+ data->screenshot = NULL;
kv_init(data->invalid_regions);
signal_watcher_init(data->loop, &data->winch_handle, ui);
signal_watcher_init(data->loop, &data->cont_handle, data);
@@ -1085,6 +1089,7 @@ static void tui_set_mode(UI *ui, ModeShape mode)
}
} else if (c.id == 0) {
// No cursor color for this mode; reset to default.
+ data->want_invisible = false;
unibi_out_ext(ui, data->unibi_ext.reset_cursor_color);
}
@@ -1103,6 +1108,15 @@ static void tui_set_mode(UI *ui, ModeShape mode)
static void tui_mode_change(UI *ui, String mode, Integer mode_idx)
{
TUIData *data = ui->data;
+#ifdef UNIX
+ // 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 (data->is_starting && data->input.in_fd == STDERR_FILENO) {
+ uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_NORMAL);
+ uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO);
+ }
+#endif
tui_set_mode(ui, (ModeShape)mode_idx);
data->is_starting = false; // mode entered, no longer starting
data->showing_mode = (ModeShape)mode_idx;
@@ -1322,6 +1336,31 @@ static void tui_set_icon(UI *ui, String icon)
{
}
+static void tui_screenshot(UI *ui, String path)
+{
+ TUIData *data = ui->data;
+ UGrid *grid = &data->grid;
+ flush_buf(ui);
+ grid->row = 0;
+ grid->col = 0;
+
+ FILE *f = fopen(path.data, "w");
+ data->screenshot = f;
+ fprintf(f, "%d,%d\n", grid->height, grid->width);
+ unibi_out(ui, unibi_clear_screen);
+ for (int i = 0; i < grid->height; i++) {
+ cursor_goto(ui, i, 0);
+ for (int j = 0; j < grid->width; j++) {
+ print_cell(ui, &grid->cells[i][j]);
+ }
+ }
+ flush_buf(ui);
+ data->screenshot = NULL;
+
+ fclose(f);
+}
+
+
static void tui_option_set(UI *ui, String name, Object value)
{
TUIData *data = ui->data;
@@ -1591,10 +1630,6 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
bool mate_pretending_xterm = xterm && colorterm
&& strstr(colorterm, "mate-terminal");
bool true_xterm = xterm && !!xterm_version && !bsdvt;
- bool true_screen = screen && !os_getenv("TMUX");
- bool screen_host_linuxvt =
- terminfo_is_term_family(true_screen && term[6] == '.'
- ? term + 7 : NULL, "linux");
bool cygwin = terminfo_is_term_family(term, "cygwin");
char *fix_normal = (char *)unibi_get_str(ut, unibi_cursor_normal);
@@ -1737,10 +1772,8 @@ 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",
- SCREEN_TMUX_WRAP(true_screen,
- tmux, "\x1b]11;?\x07"));
+ data->unibi_ext.get_bg = (int)unibi_add_ext_str(ut, "ext.get_bg",
+ "\x1b]11;?\x07");
// Terminals with 256-colour SGR support despite what terminfo says.
if (unibi_get_num(ut, unibi_max_colors) < 256) {
@@ -1775,32 +1808,6 @@ 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 (true_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.
@@ -1816,12 +1823,7 @@ 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
- || (true_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.
+ || screen
|| st // #7641
|| rxvt // per command.C
// per analysis of VT100Terminal.m
@@ -1834,72 +1836,58 @@ 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",
- SCREEN_WRAP(true_screen, "\x1b[%p1%d q"));
+ (int)unibi_add_ext_str(ut, "Ss", "\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,
- SCREEN_WRAP(true_screen, "\x1b[ q"));
- } else if (linuxvt || screen_host_linuxvt) {
+ "\x1b[ q");
+ } else if (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
- //
- // 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(true_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"));
+ 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");
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,
- SCREEN_WRAP(true_screen, "\x1b[?c"));
+ "\x1b[?c");
} 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",
- SCREEN_TMUX_WRAP(true_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"));
+ 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"));
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,
- SCREEN_TMUX_WRAP(true_screen, tmux, "\x1b]50;\x07"));
+ "\x1b]50;\x07");
}
}
}
@@ -1931,10 +1919,6 @@ static void augment_terminfo(TUIData *data, const char *term,
const char *xterm_version = os_getenv("XTERM_VERSION");
bool true_xterm = xterm && !!xterm_version && !bsdvt;
- bool true_screen = screen && !os_getenv("TMUX");
- bool screen_host_rxvt =
- terminfo_is_term_family(true_screen
- && term[6] == '.' ? term + 7 : NULL, "rxvt");
// Only define this capability for terminal types that we know understand it.
if (dtterm // originated this extension
@@ -2001,7 +1985,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, SCREEN_TMUX_WRAP(true_screen, tmux, "\033]Pl%p1%06x\033\\"));
+ ut, NULL, TMUX_WRAP(tmux, "\033]Pl%p1%06x\033\\"));
} else if ((xterm || rxvt || tmux || alacritty)
&& (vte_version == 0 || vte_version >= 3900)) {
// Supported in urxvt, newer VTE.
@@ -2021,27 +2005,21 @@ 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", SCREEN_WRAP(true_screen, "\x1b[?2004h"));
+ ut, "ext.enable_bpaste", "\x1b[?2004h");
data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str(
- ut, "ext.disable_bpaste", SCREEN_WRAP(true_screen, "\x1b[?2004l"));
+ ut, "ext.disable_bpaste", "\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 || screen_host_rxvt)
- ? SCREEN_WRAP(true_screen, "\x1b[?1004h\x1b]777;focus;on\x7")
- : SCREEN_WRAP(true_screen, "\x1b[?1004h"));
+ rxvt ? "\x1b[?1004h\x1b]777;focus;on\x7" : "\x1b[?1004h");
data->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(
ut, "ext.disable_focus",
- (rxvt || screen_host_rxvt)
- ? SCREEN_WRAP(true_screen, "\x1b[?1004l\x1b]777;focus;off\x7")
- : SCREEN_WRAP(true_screen, "\x1b[?1004l"));
+ rxvt ? "\x1b[?1004l\x1b]777;focus;off\x7" : "\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(
@@ -2120,9 +2098,15 @@ static void flush_buf(UI *ui)
}
}
- uv_write(&req, STRUCT_CAST(uv_stream_t, &data->output_handle),
- bufs, (unsigned)(bufp - bufs), NULL);
- uv_run(&data->write_loop, UV_RUN_DEFAULT);
+ if (data->screenshot) {
+ for (size_t i = 0; i < (size_t)(bufp - bufs); i++) {
+ fwrite(bufs[i].base, bufs[i].len, 1, data->screenshot);
+ }
+ } else {
+ uv_write(&req, STRUCT_CAST(uv_stream_t, &data->output_handle),
+ bufs, (unsigned)(bufp - bufs), NULL);
+ uv_run(&data->write_loop, UV_RUN_DEFAULT);
+ }
data->bufpos = 0;
data->overflow = false;
}