mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-04-19 14:51:13 -03:00
Refresh TTY timestamps again in most cases
See commit081c3282b7(Refresh TTY timestamps also in some rare cases, 2025-01-15) and others. Fixesd27f5a5293(Adopt TtyHandoff in remaining places, 2025-06-21) Fixes #11671
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
use crate::fds::make_fd_blocking;
|
||||
use crate::proc::Pid;
|
||||
use crate::reader::reader_write_title;
|
||||
use crate::reader::{reader_save_screen_state, reader_write_title};
|
||||
use crate::tokenizer::tok_command;
|
||||
use crate::wutil::perror;
|
||||
use crate::{env::EnvMode, tty_handoff::TtyHandoff};
|
||||
@@ -139,7 +139,7 @@ pub fn fg(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Built
|
||||
|
||||
// Note if tty transfer fails, we still try running the job.
|
||||
parser.job_promote_at(job_pos);
|
||||
let mut handoff = TtyHandoff::new();
|
||||
let mut handoff = TtyHandoff::new(reader_save_screen_state);
|
||||
let _ = make_fd_blocking(STDIN_FILENO);
|
||||
{
|
||||
let job_group = job.group();
|
||||
|
||||
@@ -91,7 +91,7 @@ fn process_input(streams: &mut IoStreams, continuous_mode: bool, verbose: bool)
|
||||
let mut recent_chars = vec![];
|
||||
streams.err.appendln("Press a key:\n");
|
||||
|
||||
let mut handoff = TtyHandoff::new();
|
||||
let mut handoff = TtyHandoff::new(|| {});
|
||||
handoff.enable_tty_protocols();
|
||||
|
||||
while (!first_char_seen || continuous_mode) && !check_exit_loop_maybe_warning(None) {
|
||||
@@ -100,7 +100,7 @@ fn process_input(streams: &mut IoStreams, continuous_mode: bool, verbose: bool)
|
||||
CharEvent::Readline(_) | CharEvent::Command(_) | CharEvent::Implicit(_) => continue,
|
||||
CharEvent::QueryResponse(QueryResponseEvent::PrimaryDeviceAttribute) => {
|
||||
if get_kitty_keyboard_capability() == Capability::Unknown {
|
||||
set_kitty_keyboard_capability(Capability::NotSupported);
|
||||
set_kitty_keyboard_capability(|| {}, Capability::NotSupported);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
use crate::input_common::InvalidPolicy;
|
||||
use crate::nix::isatty;
|
||||
use crate::reader::commandline_set_buffer;
|
||||
use crate::reader::reader_save_screen_state;
|
||||
use crate::reader::ReaderConfig;
|
||||
use crate::reader::{reader_pop, reader_push, reader_readline};
|
||||
use crate::tokenizer::Tokenizer;
|
||||
@@ -244,7 +245,7 @@ fn read_interactive(
|
||||
|
||||
let mline = {
|
||||
let _interactive = parser.push_scope(|s| s.is_interactive = true);
|
||||
let mut scoped_handoff = TtyHandoff::new();
|
||||
let mut scoped_handoff = TtyHandoff::new(reader_save_screen_state);
|
||||
scoped_handoff.enable_tty_protocols();
|
||||
reader_readline(parser, NonZeroUsize::try_from(nchars).ok())
|
||||
};
|
||||
|
||||
@@ -110,7 +110,7 @@ pub fn exec_job(parser: &Parser, job: &Job, block_io: IoChain) -> bool {
|
||||
let deferred_process = get_deferred_process(job);
|
||||
|
||||
// We may want to transfer tty ownership to the pgroup leader.
|
||||
let mut handoff = TtyHandoff::new();
|
||||
let mut handoff = TtyHandoff::new(|| {});
|
||||
|
||||
// This loop loops over every process_t in the job, starting it as appropriate. This turns out
|
||||
// to be rather complex, since a process_t can be one of many rather different things.
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
self, alt, canonicalize_control_char, canonicalize_keyed_control_char, char_to_symbol, ctrl,
|
||||
function_key, shift, Key, Modifiers, ViewportPosition,
|
||||
};
|
||||
use crate::reader::reader_test_and_clear_interrupted;
|
||||
use crate::reader::{reader_save_screen_state, reader_test_and_clear_interrupted};
|
||||
use crate::terminal::{Capability, SCROLL_FORWARD_SUPPORTED, SCROLL_FORWARD_TERMINFO_CODE};
|
||||
use crate::threads::iothread_port;
|
||||
use crate::tty_handoff::set_kitty_keyboard_capability;
|
||||
@@ -1168,7 +1168,7 @@ fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<KeyEvent> {
|
||||
reader,
|
||||
"Received kitty progressive enhancement flags, marking as supported"
|
||||
);
|
||||
set_kitty_keyboard_capability(Capability::Supported);
|
||||
set_kitty_keyboard_capability(reader_save_screen_state, Capability::Supported);
|
||||
return None;
|
||||
}
|
||||
|
||||
|
||||
@@ -716,7 +716,7 @@ fn read_i(parser: &Parser) {
|
||||
// Set up tty protocols. These should be enabled while we're reading interactively,
|
||||
// and disabled before we run fish script, wildcards, or completions. This is scoped.
|
||||
// Note this may be disabled within the loop, e.g. when running fish script bound to keys.
|
||||
let mut tty = TtyHandoff::new();
|
||||
let mut tty = TtyHandoff::new(reader_save_screen_state);
|
||||
|
||||
while !check_exit_loop_maybe_warning(Some(&mut data)) {
|
||||
RUN_COUNT.fetch_add(1, Ordering::Relaxed);
|
||||
@@ -1484,6 +1484,10 @@ pub fn mouse_left_click(&mut self, cursor: ViewportPosition, click_position: Vie
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reader_save_screen_state() {
|
||||
current_data().map(|data| data.save_screen_state());
|
||||
}
|
||||
|
||||
/// Given a command line and an autosuggestion, return the string that gets shown to the user.
|
||||
/// Exposed for testing purposes only.
|
||||
pub fn combine_command_and_autosuggestion(
|
||||
@@ -2182,7 +2186,7 @@ impl<'a> Reader<'a> {
|
||||
/// Read a command to execute, respecting input bindings.
|
||||
/// Return the command, or none if we were asked to cancel (e.g. SIGHUP).
|
||||
fn readline(&mut self, nchars: Option<NonZeroUsize>) -> Option<WString> {
|
||||
let mut tty = TtyHandoff::new();
|
||||
let mut tty = TtyHandoff::new(reader_save_screen_state);
|
||||
|
||||
self.rls = Some(ReadlineLoopState::new());
|
||||
|
||||
@@ -2323,7 +2327,7 @@ fn eval_bind_cmd(&mut self, cmd: &wstr) {
|
||||
let last_statuses = self.parser.vars().get_last_statuses();
|
||||
let prev_exec_external_count = self.parser.libdata().exec_external_count;
|
||||
// Disable TTY protocols while we run a bind command, because it may call out.
|
||||
let mut scoped_tty = TtyHandoff::new();
|
||||
let mut scoped_tty = TtyHandoff::new(reader_save_screen_state);
|
||||
let mut modified_tty = scoped_tty.disable_tty_protocols();
|
||||
|
||||
self.parser.eval(cmd, &IoChain::new());
|
||||
@@ -2567,10 +2571,10 @@ fn handle_char_event(&mut self, injected_event: Option<CharEvent>) -> ControlFlo
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
if get_kitty_keyboard_capability() == Capability::Unknown {
|
||||
set_kitty_keyboard_capability(Capability::NotSupported);
|
||||
// We may have written to the tty, so save the screen state
|
||||
// so we don't repaint.
|
||||
self.screen.save_status();
|
||||
set_kitty_keyboard_capability(
|
||||
reader_save_screen_state,
|
||||
Capability::NotSupported,
|
||||
);
|
||||
}
|
||||
}
|
||||
QueryResponseEvent::CursorPositionReport(cursor_pos) => {
|
||||
@@ -2819,10 +2823,12 @@ fn handle_readline_command(&mut self, c: ReadlineCmd) {
|
||||
// Either the user hit tab only once, or we had no visible completion list.
|
||||
// Disable tty protocols while we compute completions, so that control-C
|
||||
// triggers SIGINT (suppressed by CSI-U).
|
||||
let mut tty = TtyHandoff::new();
|
||||
let mut tty = TtyHandoff::new(reader_save_screen_state);
|
||||
tty.disable_tty_protocols();
|
||||
self.compute_and_apply_completions(c);
|
||||
tty.reclaim();
|
||||
if tty.reclaim() {
|
||||
self.save_screen_state();
|
||||
}
|
||||
}
|
||||
}
|
||||
rl::PagerToggleSearch => {
|
||||
@@ -4614,7 +4620,7 @@ fn exec_prompt(&mut self, full_prompt: bool, final_prompt: bool) {
|
||||
let _noninteractive = self.parser.push_scope(|s| s.is_interactive = false);
|
||||
|
||||
// Suppress TTY protocols in a scoped way so that e.g. control-C can cancel the prompt.
|
||||
let mut scoped_tty = TtyHandoff::new();
|
||||
let mut scoped_tty = TtyHandoff::new(reader_save_screen_state);
|
||||
scoped_tty.disable_tty_protocols();
|
||||
|
||||
// Update the termsize now.
|
||||
|
||||
@@ -72,10 +72,10 @@ pub fn get_kitty_keyboard_capability() -> Capability {
|
||||
|
||||
// Set CSI-U ("Kitty") support capability.
|
||||
// This correctly handles the case where we think protocols are already enabled.
|
||||
pub fn set_kitty_keyboard_capability(cap: Capability) {
|
||||
pub fn set_kitty_keyboard_capability(on_write: fn(), cap: Capability) {
|
||||
assert_is_main_thread();
|
||||
// Disable and renable protocols around capabilities.
|
||||
let mut tty = TtyHandoff::new();
|
||||
let mut tty = TtyHandoff::new(on_write);
|
||||
tty.disable_tty_protocols();
|
||||
KITTY_KEYBOARD_SUPPORTED.store(cap as _, Ordering::Relaxed);
|
||||
FLOG!(
|
||||
@@ -252,7 +252,7 @@ pub fn initialize_tty_metadata() {
|
||||
// Enable or disable TTY protocols by writing the appropriate commands to the tty.
|
||||
// Return true if we emitted any bytes to the tty.
|
||||
// Note this does NOT intialize the TTY protocls if not already initialized.
|
||||
fn set_tty_protocols_active(enable: bool) -> bool {
|
||||
fn set_tty_protocols_active(on_write: fn(), enable: bool) -> bool {
|
||||
assert_is_main_thread();
|
||||
// Have protocols at all? We require someone else to have initialized them.
|
||||
let Some(protocols) = tty_protocols() else {
|
||||
@@ -287,6 +287,7 @@ fn set_tty_protocols_active(enable: bool) -> bool {
|
||||
ProtocolKind::Other => FLOG!(term_protocols, mode, "other extended keys"),
|
||||
ProtocolKind::None => (),
|
||||
};
|
||||
(on_write)();
|
||||
true
|
||||
}
|
||||
|
||||
@@ -347,16 +348,19 @@ pub struct TtyHandoff {
|
||||
tty_protocols_applied: bool,
|
||||
// Whether reclaim was called, restoring the tty to its pre-scoped value.
|
||||
reclaimed: bool,
|
||||
// Called after writing to the TTY.
|
||||
on_write: fn(),
|
||||
}
|
||||
|
||||
impl TtyHandoff {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(on_write: fn()) -> Self {
|
||||
let protocols_active = get_tty_protocols_active();
|
||||
TtyHandoff {
|
||||
owner: None,
|
||||
tty_protocols_initial: protocols_active,
|
||||
tty_protocols_applied: protocols_active,
|
||||
reclaimed: false,
|
||||
on_write,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,7 +371,7 @@ pub fn enable_tty_protocols(&mut self) -> bool {
|
||||
return false; // Already enabled.
|
||||
}
|
||||
self.tty_protocols_applied = true;
|
||||
set_tty_protocols_active(true)
|
||||
set_tty_protocols_active(self.on_write, true)
|
||||
}
|
||||
|
||||
/// Mark terminal modes as disabled.
|
||||
@@ -377,7 +381,7 @@ pub fn disable_tty_protocols(&mut self) -> bool {
|
||||
return false; // Already disabled.
|
||||
};
|
||||
self.tty_protocols_applied = false;
|
||||
set_tty_protocols_active(false)
|
||||
set_tty_protocols_active(self.on_write, false)
|
||||
}
|
||||
|
||||
/// Transfer to the given job group, if it wants to own the terminal.
|
||||
|
||||
Reference in New Issue
Block a user