From 874fba11086c477c024bc3c3fdef05ccba38d4d6 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sun, 5 Oct 2025 10:45:04 +0200 Subject: [PATCH] Don't use kitty keyboard protocol support to decide timeout As reported in https://github.com/fish-shell/fish-shell/discussions/11868, some terminals advertise support for the kitty keyboard protocol despite it not necessarily being enabled. We use this flag in 30ff3710a06 (Increase timeout when reading escape sequences inside paste/kitty kbd, 2025-07-24), to support the AutoHotKey scenario on terminals that support the kitty keyboard protocols. Let's move towards the more comprehensive fix mentioned in abd23d2a1b2 (Increase escape sequence timeout while waiting for query response, 2025-09-30), i.e. only apply a low timeout when necessary to actually distinguish legacy escape. Let's pick 30ms for now (which has been used successfully for similar things historically, see 30ff3710a06); a higher timeout let alone a warning on incomplete sequence seems risky for a patch relase, and it's also not 100% clear if this is actually a degraded state because in theory the user might legitimately type "escape [ 1" (while kitty keyboard protocol is turned off, e.g. before the shell regains control). This obsoletes and hence reverts commit 623c14aed0a (Kitty keyboard protocol is non-functional on old versions of Zellij, 2025-10-04). (cherry picked from commit 6accc475c9bdbe2db6f0de977cb5606ef2fe5145) --- CHANGELOG.rst | 2 +- src/input_common.rs | 21 +++++++++------------ src/tty_handoff.rs | 20 +++----------------- src/wchar_ext.rs | 8 -------- 4 files changed, 13 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bcfb71589..71e42d98e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,7 +6,7 @@ This release fixes the following regressions identified in 4.1.0: - Fixed spurious error output when completing remote file paths for ``scp`` (:issue:`11860`). - Fixed an issue where focus events (currently only enabled in ``tmux``) would cause multiline prompts to be redrawn in the wrong line (:issue:`11870`). - Stopped printing output that would cause a glitch on old versions of Midnight Commander (:issue:`11869`). -- Added a workaround for old versions of Zellij where :kbd:`escape` processing was delayed (:issue:`11868`). +- Added a fix for some configurations of Zellij where :kbd:`escape` key processing was delayed (:issue:`11868`). - Fixed a case where the :doc:`web-based configuration tool ` would generate invalid configuration (:issue:`11861`). - Fixed a case where upgrading fish would break old versions of fish that were still running. diff --git a/src/input_common.rs b/src/input_common.rs index 989a4cccc..3328849b8 100644 --- a/src/input_common.rs +++ b/src/input_common.rs @@ -12,8 +12,8 @@ use crate::reader::reader_test_and_clear_interrupted; use crate::threads::iothread_port; use crate::tty_handoff::{ - get_kitty_keyboard_capability, maybe_set_kitty_keyboard_capability, - maybe_set_scroll_content_up_capability, SCROLL_CONTENT_UP_TERMINFO_CODE, XTVERSION, + maybe_set_kitty_keyboard_capability, maybe_set_scroll_content_up_capability, + SCROLL_CONTENT_UP_TERMINFO_CODE, XTVERSION, }; use crate::universal_notifier::default_notifier; use crate::wchar::{encode_byte_to_char, prelude::*}; @@ -983,16 +983,13 @@ fn try_readb(&mut self, buffer: &mut Vec) -> Option { let fd = self.get_in_fd(); if !check_fd_readable( fd, - Duration::from_millis( - if self.paste_is_buffering() - || self.is_blocked_querying() - || get_kitty_keyboard_capability() == Some(&true) - { - 300 - } else { - 1 - }, - ), + Duration::from_millis(if self.paste_is_buffering() || self.is_blocked_querying() { + 300 + } else if buffer == b"\x1b" { + 1 // distinguish legacy escape + } else { + 30 + }), ) { FLOG!( reader, diff --git a/src/tty_handoff.rs b/src/tty_handoff.rs index 895788b5f..4ec231fbf 100644 --- a/src/tty_handoff.rs +++ b/src/tty_handoff.rs @@ -18,7 +18,7 @@ use crate::threads::assert_is_main_thread; use crate::wchar::prelude::*; use crate::wchar_ext::ToWString; -use crate::wutil::{fish_wcstoul, perror, wcstoi}; +use crate::wutil::{perror, wcstoi}; use libc::{EINVAL, ENOTTY, EPERM, STDIN_FILENO, WNOHANG}; use once_cell::sync::OnceCell; use std::mem::MaybeUninit; @@ -27,11 +27,6 @@ /// Whether kitty keyboard protocol support is present in the TTY. static KITTY_KEYBOARD_SUPPORTED: OnceCell = OnceCell::new(); -/// Get whether the TTY supports the kitty keyboard protocol. -pub fn get_kitty_keyboard_capability() -> Option<&'static bool> { - KITTY_KEYBOARD_SUPPORTED.get() -} - /// Set that the TTY supports the kitty keyboard protocol. pub fn maybe_set_kitty_keyboard_capability() { KITTY_KEYBOARD_SUPPORTED.get_or_init(|| true); @@ -66,8 +61,6 @@ pub enum TtyQuirks { PreCsiMidnightCommander, // Running in iTerm2 before 3.5.12, which causes issues when using the kitty keyboard protocol. PreKittyIterm2, - // Running in Zellij before 0.42.0 which fails to activate the kitty keyboard protocol. - PreKittyZellij, // Whether we are running under tmux. Tmux, // Whether we are running under WezTerm. @@ -84,8 +77,6 @@ fn detect(vars: &dyn Environment, xtversion: &wstr) -> Self { PreCsiMidnightCommander } else if get_iterm2_version(xtversion).is_some_and(|v| v < (3, 5, 12)) { PreKittyIterm2 - } else if get_zellij_version(xtversion).is_some_and(|v| v < 4200) { - PreKittyZellij } else if xtversion.starts_with(L!("tmux ")) { Tmux } else if xtversion.starts_with(L!("WezTerm ")) { @@ -160,11 +151,11 @@ impl TtyQuirks { // Determine which keyboard protocol. // This is used from a signal handler. fn safe_get_supported_protocol(&self) -> ProtocolKind { - use TtyQuirks::{PreCsiMidnightCommander, PreKittyIterm2, PreKittyZellij, Wezterm}; + use TtyQuirks::{PreCsiMidnightCommander, PreKittyIterm2, Wezterm}; if *self == PreCsiMidnightCommander { return ProtocolKind::None; } - if matches!(*self, PreKittyIterm2 | PreKittyZellij) { + if *self == PreKittyIterm2 { return ProtocolKind::Other; } match KITTY_KEYBOARD_SUPPORTED.get() { @@ -635,8 +626,3 @@ fn get_iterm2_version(xtversion: &wstr) -> Option<(u32, u32, u32)> { wcstoi(parts.next()?).ok()?, )) } - -fn get_zellij_version(xtversion: &wstr) -> Option { - let number = xtversion.strip_prefix("Zellij(")?.strip_suffix(")")?; - fish_wcstoul(number).ok() -} diff --git a/src/wchar_ext.rs b/src/wchar_ext.rs index 5484d1eb6..89c96254d 100644 --- a/src/wchar_ext.rs +++ b/src/wchar_ext.rs @@ -297,14 +297,6 @@ fn ends_with(&self, suffix: Suffix) -> bool { ) } - fn strip_suffix(&self, suffix: Suffix) -> Option<&wstr> { - // Note the above trait requires a double ended iterator. - let iter = suffix.chars().rev(); - let suffix_len = iter.clone().count(); - iter_prefixes_iter(iter, self.as_char_slice().iter().rev().copied()) - .then(|| self.slice_to(self.char_count() - suffix_len)) - } - fn trim_matches(&self, pat: char) -> &wstr { let slice = self.as_char_slice(); let leading_count = slice.chars().take_while(|&c| c == pat).count();