Force some terminal modes even for external commands

In #7133, neovim crashing caused "OPOST" to be turned off, which
caused a weird staircase display.

So we just force a set of settings that don't seem useful to change to
avoid breaking the terminal with something like that.

Fixes #7133.
This commit is contained in:
Fabian Homborg 2020-06-19 21:03:40 +02:00
parent 56a9e698d0
commit e9e23a8333

View file

@ -647,6 +647,8 @@ static void term_fix_modes(struct termios *modes) {
modes->c_lflag &= ~ICANON; // turn off canonical mode modes->c_lflag &= ~ICANON; // turn off canonical mode
modes->c_lflag &= ~ECHO; // turn off echo mode modes->c_lflag &= ~ECHO; // turn off echo mode
modes->c_lflag &= ~IEXTEN; // turn off handling of discard and lnext characters modes->c_lflag &= ~IEXTEN; // turn off handling of discard and lnext characters
modes->c_lflag &= ~IEXTEN; // turn off handling of discard and lnext characters
modes->c_oflag |= OPOST; // turn on "implementation-defined post processing" - this often changes how line breaks work.
} }
/// Tracks a currently pending exit. This may be manipulated from a signal handler. /// Tracks a currently pending exit. This may be manipulated from a signal handler.
@ -680,13 +682,19 @@ static void term_donate(outputter_t &outp) {
/// Grab control of terminal. /// Grab control of terminal.
static void term_steal() { static void term_steal() {
// Copy the (potentially changed) terminal modes and use them from now on. // Copy the (potentially changed) terminal modes and use them from now on.
// This is where we could check them for obvious problems,
// but we haven't really done so - we use the modes fish is started with for
// external commands.
struct termios modes; struct termios modes;
tcgetattr(STDIN_FILENO, &modes); tcgetattr(STDIN_FILENO, &modes);
std::memcpy(&tty_modes_for_external_cmds, &modes, std::memcpy(&tty_modes_for_external_cmds, &modes,
sizeof tty_modes_for_external_cmds); sizeof tty_modes_for_external_cmds);
// Turning off OPOST breaks output (staircase effect), we don't allow it.
// See #7133.
tty_modes_for_external_cmds.c_oflag |= OPOST;
// These cause other ridiculous behaviors like input not being shown.
tty_modes_for_external_cmds.c_lflag |= ICANON;
tty_modes_for_external_cmds.c_lflag |= IEXTEN;
tty_modes_for_external_cmds.c_lflag |= ECHO;
while (true) { while (true) {
if (tcsetattr(STDIN_FILENO, TCSANOW, &shell_modes) == -1) { if (tcsetattr(STDIN_FILENO, TCSANOW, &shell_modes) == -1) {
if (errno == EIO) redirect_tty_output(); if (errno == EIO) redirect_tty_output();
@ -1111,6 +1119,7 @@ void reader_init() {
// Disable flow control for external commands by default. // Disable flow control for external commands by default.
tty_modes_for_external_cmds.c_iflag &= ~IXON; tty_modes_for_external_cmds.c_iflag &= ~IXON;
tty_modes_for_external_cmds.c_iflag &= ~IXOFF; tty_modes_for_external_cmds.c_iflag &= ~IXOFF;
tty_modes_for_external_cmds.c_oflag |= OPOST;
// Set the mode used for the terminal, initialized to the current mode. // Set the mode used for the terminal, initialized to the current mode.
std::memcpy(&shell_modes, &terminal_mode_on_startup, sizeof shell_modes); std::memcpy(&shell_modes, &terminal_mode_on_startup, sizeof shell_modes);