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 30ff3710a0 (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 abd23d2a1b
(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 30ff3710a0); 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 623c14aed0 (Kitty keyboard
protocol is non-functional on old versions of Zellij, 2025-10-04).

(cherry picked from commit 6accc475c9)
This commit is contained in:
Johannes Altmanninger
2025-10-05 10:45:04 +02:00
parent 695f225cb4
commit 874fba1108
4 changed files with 13 additions and 38 deletions

View File

@@ -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 <cmds/fish_config>` would generate invalid configuration (:issue:`11861`).
- Fixed a case where upgrading fish would break old versions of fish that were still running.

View File

@@ -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<u8>) -> Option<u8> {
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,

View File

@@ -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<bool> = 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<u64> {
let number = xtversion.strip_prefix("Zellij(")?.strip_suffix(")")?;
fish_wcstoul(number).ok()
}

View File

@@ -297,14 +297,6 @@ fn ends_with<Suffix: IntoCharIter>(&self, suffix: Suffix) -> bool {
)
}
fn strip_suffix<Suffix: IntoCharIter>(&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();