mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-04-27 23:11:15 -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::fds::make_fd_blocking;
|
||||||
use crate::proc::Pid;
|
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::tokenizer::tok_command;
|
||||||
use crate::wutil::perror;
|
use crate::wutil::perror;
|
||||||
use crate::{env::EnvMode, tty_handoff::TtyHandoff};
|
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.
|
// Note if tty transfer fails, we still try running the job.
|
||||||
parser.job_promote_at(job_pos);
|
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 _ = make_fd_blocking(STDIN_FILENO);
|
||||||
{
|
{
|
||||||
let job_group = job.group();
|
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![];
|
let mut recent_chars = vec![];
|
||||||
streams.err.appendln("Press a key:\n");
|
streams.err.appendln("Press a key:\n");
|
||||||
|
|
||||||
let mut handoff = TtyHandoff::new();
|
let mut handoff = TtyHandoff::new(|| {});
|
||||||
handoff.enable_tty_protocols();
|
handoff.enable_tty_protocols();
|
||||||
|
|
||||||
while (!first_char_seen || continuous_mode) && !check_exit_loop_maybe_warning(None) {
|
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::Readline(_) | CharEvent::Command(_) | CharEvent::Implicit(_) => continue,
|
||||||
CharEvent::QueryResponse(QueryResponseEvent::PrimaryDeviceAttribute) => {
|
CharEvent::QueryResponse(QueryResponseEvent::PrimaryDeviceAttribute) => {
|
||||||
if get_kitty_keyboard_capability() == Capability::Unknown {
|
if get_kitty_keyboard_capability() == Capability::Unknown {
|
||||||
set_kitty_keyboard_capability(Capability::NotSupported);
|
set_kitty_keyboard_capability(|| {}, Capability::NotSupported);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
use crate::input_common::InvalidPolicy;
|
use crate::input_common::InvalidPolicy;
|
||||||
use crate::nix::isatty;
|
use crate::nix::isatty;
|
||||||
use crate::reader::commandline_set_buffer;
|
use crate::reader::commandline_set_buffer;
|
||||||
|
use crate::reader::reader_save_screen_state;
|
||||||
use crate::reader::ReaderConfig;
|
use crate::reader::ReaderConfig;
|
||||||
use crate::reader::{reader_pop, reader_push, reader_readline};
|
use crate::reader::{reader_pop, reader_push, reader_readline};
|
||||||
use crate::tokenizer::Tokenizer;
|
use crate::tokenizer::Tokenizer;
|
||||||
@@ -244,7 +245,7 @@ fn read_interactive(
|
|||||||
|
|
||||||
let mline = {
|
let mline = {
|
||||||
let _interactive = parser.push_scope(|s| s.is_interactive = true);
|
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();
|
scoped_handoff.enable_tty_protocols();
|
||||||
reader_readline(parser, NonZeroUsize::try_from(nchars).ok())
|
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);
|
let deferred_process = get_deferred_process(job);
|
||||||
|
|
||||||
// We may want to transfer tty ownership to the pgroup leader.
|
// 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
|
// 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.
|
// 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,
|
self, alt, canonicalize_control_char, canonicalize_keyed_control_char, char_to_symbol, ctrl,
|
||||||
function_key, shift, Key, Modifiers, ViewportPosition,
|
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::terminal::{Capability, SCROLL_FORWARD_SUPPORTED, SCROLL_FORWARD_TERMINFO_CODE};
|
||||||
use crate::threads::iothread_port;
|
use crate::threads::iothread_port;
|
||||||
use crate::tty_handoff::set_kitty_keyboard_capability;
|
use crate::tty_handoff::set_kitty_keyboard_capability;
|
||||||
@@ -1168,7 +1168,7 @@ fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<KeyEvent> {
|
|||||||
reader,
|
reader,
|
||||||
"Received kitty progressive enhancement flags, marking as supported"
|
"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;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -716,7 +716,7 @@ fn read_i(parser: &Parser) {
|
|||||||
// Set up tty protocols. These should be enabled while we're reading interactively,
|
// 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.
|
// 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.
|
// 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)) {
|
while !check_exit_loop_maybe_warning(Some(&mut data)) {
|
||||||
RUN_COUNT.fetch_add(1, Ordering::Relaxed);
|
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.
|
/// Given a command line and an autosuggestion, return the string that gets shown to the user.
|
||||||
/// Exposed for testing purposes only.
|
/// Exposed for testing purposes only.
|
||||||
pub fn combine_command_and_autosuggestion(
|
pub fn combine_command_and_autosuggestion(
|
||||||
@@ -2182,7 +2186,7 @@ impl<'a> Reader<'a> {
|
|||||||
/// Read a command to execute, respecting input bindings.
|
/// Read a command to execute, respecting input bindings.
|
||||||
/// Return the command, or none if we were asked to cancel (e.g. SIGHUP).
|
/// Return the command, or none if we were asked to cancel (e.g. SIGHUP).
|
||||||
fn readline(&mut self, nchars: Option<NonZeroUsize>) -> Option<WString> {
|
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());
|
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 last_statuses = self.parser.vars().get_last_statuses();
|
||||||
let prev_exec_external_count = self.parser.libdata().exec_external_count;
|
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.
|
// 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();
|
let mut modified_tty = scoped_tty.disable_tty_protocols();
|
||||||
|
|
||||||
self.parser.eval(cmd, &IoChain::new());
|
self.parser.eval(cmd, &IoChain::new());
|
||||||
@@ -2567,10 +2571,10 @@ fn handle_char_event(&mut self, injected_event: Option<CharEvent>) -> ControlFlo
|
|||||||
return ControlFlow::Continue(());
|
return ControlFlow::Continue(());
|
||||||
}
|
}
|
||||||
if get_kitty_keyboard_capability() == Capability::Unknown {
|
if get_kitty_keyboard_capability() == Capability::Unknown {
|
||||||
set_kitty_keyboard_capability(Capability::NotSupported);
|
set_kitty_keyboard_capability(
|
||||||
// We may have written to the tty, so save the screen state
|
reader_save_screen_state,
|
||||||
// so we don't repaint.
|
Capability::NotSupported,
|
||||||
self.screen.save_status();
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueryResponseEvent::CursorPositionReport(cursor_pos) => {
|
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.
|
// 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
|
// Disable tty protocols while we compute completions, so that control-C
|
||||||
// triggers SIGINT (suppressed by CSI-U).
|
// triggers SIGINT (suppressed by CSI-U).
|
||||||
let mut tty = TtyHandoff::new();
|
let mut tty = TtyHandoff::new(reader_save_screen_state);
|
||||||
tty.disable_tty_protocols();
|
tty.disable_tty_protocols();
|
||||||
self.compute_and_apply_completions(c);
|
self.compute_and_apply_completions(c);
|
||||||
tty.reclaim();
|
if tty.reclaim() {
|
||||||
|
self.save_screen_state();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rl::PagerToggleSearch => {
|
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);
|
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.
|
// 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();
|
scoped_tty.disable_tty_protocols();
|
||||||
|
|
||||||
// Update the termsize now.
|
// Update the termsize now.
|
||||||
|
|||||||
@@ -72,10 +72,10 @@ pub fn get_kitty_keyboard_capability() -> Capability {
|
|||||||
|
|
||||||
// Set CSI-U ("Kitty") support capability.
|
// Set CSI-U ("Kitty") support capability.
|
||||||
// This correctly handles the case where we think protocols are already enabled.
|
// 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();
|
assert_is_main_thread();
|
||||||
// Disable and renable protocols around capabilities.
|
// Disable and renable protocols around capabilities.
|
||||||
let mut tty = TtyHandoff::new();
|
let mut tty = TtyHandoff::new(on_write);
|
||||||
tty.disable_tty_protocols();
|
tty.disable_tty_protocols();
|
||||||
KITTY_KEYBOARD_SUPPORTED.store(cap as _, Ordering::Relaxed);
|
KITTY_KEYBOARD_SUPPORTED.store(cap as _, Ordering::Relaxed);
|
||||||
FLOG!(
|
FLOG!(
|
||||||
@@ -252,7 +252,7 @@ pub fn initialize_tty_metadata() {
|
|||||||
// Enable or disable TTY protocols by writing the appropriate commands to the tty.
|
// Enable or disable TTY protocols by writing the appropriate commands to the tty.
|
||||||
// Return true if we emitted any bytes 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.
|
// 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();
|
assert_is_main_thread();
|
||||||
// Have protocols at all? We require someone else to have initialized them.
|
// Have protocols at all? We require someone else to have initialized them.
|
||||||
let Some(protocols) = tty_protocols() else {
|
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::Other => FLOG!(term_protocols, mode, "other extended keys"),
|
||||||
ProtocolKind::None => (),
|
ProtocolKind::None => (),
|
||||||
};
|
};
|
||||||
|
(on_write)();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,16 +348,19 @@ pub struct TtyHandoff {
|
|||||||
tty_protocols_applied: bool,
|
tty_protocols_applied: bool,
|
||||||
// Whether reclaim was called, restoring the tty to its pre-scoped value.
|
// Whether reclaim was called, restoring the tty to its pre-scoped value.
|
||||||
reclaimed: bool,
|
reclaimed: bool,
|
||||||
|
// Called after writing to the TTY.
|
||||||
|
on_write: fn(),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TtyHandoff {
|
impl TtyHandoff {
|
||||||
pub fn new() -> Self {
|
pub fn new(on_write: fn()) -> Self {
|
||||||
let protocols_active = get_tty_protocols_active();
|
let protocols_active = get_tty_protocols_active();
|
||||||
TtyHandoff {
|
TtyHandoff {
|
||||||
owner: None,
|
owner: None,
|
||||||
tty_protocols_initial: protocols_active,
|
tty_protocols_initial: protocols_active,
|
||||||
tty_protocols_applied: protocols_active,
|
tty_protocols_applied: protocols_active,
|
||||||
reclaimed: false,
|
reclaimed: false,
|
||||||
|
on_write,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,7 +371,7 @@ pub fn enable_tty_protocols(&mut self) -> bool {
|
|||||||
return false; // Already enabled.
|
return false; // Already enabled.
|
||||||
}
|
}
|
||||||
self.tty_protocols_applied = true;
|
self.tty_protocols_applied = true;
|
||||||
set_tty_protocols_active(true)
|
set_tty_protocols_active(self.on_write, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mark terminal modes as disabled.
|
/// Mark terminal modes as disabled.
|
||||||
@@ -377,7 +381,7 @@ pub fn disable_tty_protocols(&mut self) -> bool {
|
|||||||
return false; // Already disabled.
|
return false; // Already disabled.
|
||||||
};
|
};
|
||||||
self.tty_protocols_applied = false;
|
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.
|
/// Transfer to the given job group, if it wants to own the terminal.
|
||||||
|
|||||||
Reference in New Issue
Block a user