mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-22 03:51:15 -03:00
Kitty keyboard protocol is non-functional on old versions of Zellij
try_readb() uses a high timeout when the kitty keyboard protocol is
enabled, because in that case it should basically never be necessary
to interpret \e as escape key, see 30ff3710a0 (Increase timeout when
reading escape sequences inside paste/kitty kbd, 2025-07-24).
Zellij before commit 0075548a (fix(terminal): support kitty keyboard
protocol setting with "=" (#3942), 2025-01-17) fails to enable kitty
keyboard protocol, so it sends the raw escape bytes, causing us to
wait 300ms.
Closes #11868
This commit is contained in:
@@ -9,6 +9,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`).
|
||||
- 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.
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
use crate::threads::assert_is_main_thread;
|
||||
use crate::wchar::prelude::*;
|
||||
use crate::wchar_ext::ToWString;
|
||||
use crate::wutil::{perror, wcstoi};
|
||||
use crate::wutil::{fish_wcstoul, perror, wcstoi};
|
||||
use libc::{EINVAL, ENOTTY, EPERM, STDIN_FILENO, WNOHANG};
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::mem::MaybeUninit;
|
||||
@@ -62,10 +62,12 @@ pub fn xtversion() -> Option<&'static wstr> {
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum TtyQuirks {
|
||||
None,
|
||||
// Running Midnight Commander which can't parse CSI/OSC/DCS yet.
|
||||
MidnightCommander,
|
||||
// Running Midnight Commander which can't parse CSI yet.
|
||||
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.
|
||||
@@ -79,9 +81,11 @@ fn detect(vars: &dyn Environment, xtversion: &wstr) -> Self {
|
||||
if vars.get(MIDNIGHT_COMMANDER_SID).is_some()
|
||||
&& vars.get(L!("__mc_kitty_keyboard")).is_none()
|
||||
{
|
||||
MidnightCommander
|
||||
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 ")) {
|
||||
@@ -156,11 +160,11 @@ impl TtyQuirks {
|
||||
// Determine which keyboard protocol.
|
||||
// This is used from a signal handler.
|
||||
fn safe_get_supported_protocol(&self) -> ProtocolKind {
|
||||
use TtyQuirks::{MidnightCommander, PreKittyIterm2, Wezterm};
|
||||
if *self == MidnightCommander {
|
||||
use TtyQuirks::{PreCsiMidnightCommander, PreKittyIterm2, PreKittyZellij, Wezterm};
|
||||
if *self == PreCsiMidnightCommander {
|
||||
return ProtocolKind::None;
|
||||
}
|
||||
if *self == PreKittyIterm2 {
|
||||
if matches!(*self, PreKittyIterm2 | PreKittyZellij) {
|
||||
return ProtocolKind::Other;
|
||||
}
|
||||
match KITTY_KEYBOARD_SUPPORTED.get() {
|
||||
@@ -631,3 +635,8 @@ 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()
|
||||
}
|
||||
|
||||
@@ -297,6 +297,14 @@ 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();
|
||||
|
||||
Reference in New Issue
Block a user