Don't abandon line after writing control sequences

Commit 8164855b7 (Disable terminal protocols throughout evaluation, 2024-04-02)
changed where we output control sequences (to enable bracketed paste and CSI).
Likewise, f285e85b0 (Enable focus reporting only just before reading from
stdin, 2024-04-06) added control sequence output just before we read().

This output causes problems because it invalidates our stdout/stderr
timestamps, which causes us to think that a rogue background process wrote
to the terminal; we react by abandoning the current line and redrawing the
prompt below. Our fix was to refresh the TTY timestamps after we run a bind
command that might add stdout (#3481).

Since commit c3cd68dda (Process shell commands from bindings like regular
char events, 2024-03-02), this timestamp refresh logic is in the wrong place;
shell commands are run later now; we could move it but wait -

... we also need to make sure to refresh timestamps after outputting control
sequences.  Since bracketed paste is enabled after CSI u, we can skip the
latter.  Additionally, since we currently output control sequences before
every single top-level interactive command, we no longer need to separately
refresh timestamps in between commands.

Fixes #10409
This commit is contained in:
Johannes Altmanninger 2024-04-06 15:44:12 +02:00
parent de730b7885
commit 8a7c3ceec3
2 changed files with 8 additions and 21 deletions

View file

@ -452,7 +452,8 @@ pub fn terminal_protocols_disable_scoped() -> impl ScopeGuarding<Target = ()> {
ScopeGuard::new((), |()| { ScopeGuard::new((), |()| {
// If a child is stopped, this will already be enabled. // If a child is stopped, this will already be enabled.
if TERMINAL_PROTOCOLS.get().borrow().is_none() { if TERMINAL_PROTOCOLS.get().borrow().is_none() {
terminal_protocols_enable() terminal_protocols_enable();
reader_current_data().unwrap().save_screen_state();
} }
}) })
} }
@ -527,6 +528,7 @@ pub(crate) fn focus_events_enable_ifn() {
if !term_protocols.focus_events { if !term_protocols.focus_events {
term_protocols.focus_events = true; term_protocols.focus_events = true;
let _ = write_to_fd("\x1b[?1004h".as_bytes(), STDOUT_FILENO); let _ = write_to_fd("\x1b[?1004h".as_bytes(), STDOUT_FILENO);
reader_current_data().unwrap().save_screen_state();
} }
} }

View file

@ -1142,9 +1142,11 @@ impl ReaderData {
&self.parser_ref &self.parser_ref
} }
/// Convenience cover over exec_count. // We repaint our prompt if fstat reports the tty as having changed.
fn exec_count(&self) -> u64 { // But don't react to tty changes that we initiated, because of commands or
self.parser().libdata().pods.exec_count // on-variable events (e.g. for fish_bind_mode). See #3481.
pub(crate) fn save_screen_state(&mut self) {
self.screen.save_status();
} }
/// Do what we need to do whenever our command line changes. /// Do what we need to do whenever our command line changes.
@ -2037,10 +2039,6 @@ impl ReaderData {
READAHEAD_MAX, READAHEAD_MAX,
); );
// We repaint our prompt if fstat reports the tty as having changed.
// But don't react to tty changes that we initiated, because of commands or
// on-variable events (e.g. for fish_bind_mode). See #3481.
let mut last_exec_count = self.exec_count();
let mut accumulated_chars = WString::new(); let mut accumulated_chars = WString::new();
while accumulated_chars.len() < limit { while accumulated_chars.len() < limit {
@ -2067,11 +2065,6 @@ impl ReaderData {
} else { } else {
continue; continue;
}; };
if last_exec_count != self.exec_count() {
last_exec_count = self.exec_count();
self.screen.save_status();
}
} }
if !accumulated_chars.is_empty() { if !accumulated_chars.is_empty() {
@ -2087,14 +2080,6 @@ impl ReaderData {
rls.last_cmd = None; rls.last_cmd = None;
} }
if last_exec_count != self.exec_count() {
#[allow(unused_assignments)]
{
last_exec_count = self.exec_count();
}
self.screen.save_status();
}
event_needing_handling event_needing_handling
} }
} }