diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f1d59275c..bcfb71589 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +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`). - 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/tty_handoff.rs b/src/tty_handoff.rs index 59fe388b8..895788b5f 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::{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 { + 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 89c96254d..5484d1eb6 100644 --- a/src/wchar_ext.rs +++ b/src/wchar_ext.rs @@ -297,6 +297,14 @@ 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();