From 8a7c3ceec37dd891d39beb7f48c9c236a190c907 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sat, 6 Apr 2024 15:44:12 +0200 Subject: [PATCH] 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 --- src/input_common.rs | 4 +++- src/reader.rs | 25 +++++-------------------- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/src/input_common.rs b/src/input_common.rs index 6b18441c1..6d17f5dec 100644 --- a/src/input_common.rs +++ b/src/input_common.rs @@ -452,7 +452,8 @@ pub fn terminal_protocols_disable_scoped() -> impl ScopeGuarding { ScopeGuard::new((), |()| { // If a child is stopped, this will already be enabled. 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 { term_protocols.focus_events = true; let _ = write_to_fd("\x1b[?1004h".as_bytes(), STDOUT_FILENO); + reader_current_data().unwrap().save_screen_state(); } } diff --git a/src/reader.rs b/src/reader.rs index e3cc4b419..00ab9b427 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -1142,9 +1142,11 @@ impl ReaderData { &self.parser_ref } - /// Convenience cover over exec_count. - fn exec_count(&self) -> u64 { - self.parser().libdata().pods.exec_count + // 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. + pub(crate) fn save_screen_state(&mut self) { + self.screen.save_status(); } /// Do what we need to do whenever our command line changes. @@ -2037,10 +2039,6 @@ impl ReaderData { 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(); while accumulated_chars.len() < limit { @@ -2067,11 +2065,6 @@ impl ReaderData { } else { continue; }; - - if last_exec_count != self.exec_count() { - last_exec_count = self.exec_count(); - self.screen.save_status(); - } } if !accumulated_chars.is_empty() { @@ -2087,14 +2080,6 @@ impl ReaderData { 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 } }