mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-11 20:48:49 +00:00
Probe for kitty keyboard protocol support
We unconditionally request kitty keyboard protocol's progressive
enhancements.
It seems that a lot of terminals fail to parse CSI commands that
contain '=' such as \x1b[=5u.
1. [Midnight Commander](0ea77d2ec7
)
2. Prompt 3 App (private bug tracker)
3. JetBrains IDEs https://youtrack.jetbrains.com/issue/IJPL-166234
4. Termux https://github.com/termux/termux-app/issues/4338
5. Amazon Linux Web Console https://github.com/amazonlinux/amazon-linux-2023/issues/871
It is difficult to fix the four remaining ones in a
timely manner, so let's query for support as described in
https://sw.kovidgoyal.net/kitty/keyboard-protocol/#detection-of-support-for-this-protocol
This uses CSI 5 n (device status report), which is the older brother
of CSI 6 n (cursor position report) we use as of recently.
Query asynchronously and enable progressive enhancements as soon
as we get a response. In theory this allow `cat malicious-file.txt`
leading us to believe the protocol is supported.
See #10994
This commit is contained in:
parent
edfdf210c4
commit
e49dde87cc
1 changed files with 46 additions and 11 deletions
|
@ -24,7 +24,7 @@ use std::ops::ControlFlow;
|
|||
use std::os::fd::RawFd;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::ptr;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering, Ordering::Relaxed};
|
||||
|
||||
// The range of key codes for inputrc-style keyboard functions.
|
||||
pub const R_END_INPUT_FUNCTIONS: usize = (ReadlineCmd::ReverseRepeatJump as usize) + 1;
|
||||
|
@ -436,10 +436,23 @@ pub fn update_wait_on_sequence_key_ms(vars: &EnvStack) {
|
|||
|
||||
static TERMINAL_PROTOCOLS: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
#[repr(u8)]
|
||||
enum Capability {
|
||||
Unknown,
|
||||
Supported,
|
||||
NotSupported,
|
||||
}
|
||||
static KITTY_KEYBOARD_SUPPORTED: AtomicU8 = AtomicU8::new(Capability::Unknown as _);
|
||||
|
||||
macro_rules! kitty_progressive_enhancements {
|
||||
() => {
|
||||
"\x1b[=5u"
|
||||
};
|
||||
}
|
||||
|
||||
static IS_TMUX: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
||||
pub static IN_MIDNIGHT_COMMANDER_PRE_CSI_U: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
||||
static IN_ITERM_PRE_CSI_U: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
||||
static IN_JETBRAINS: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
||||
|
||||
pub fn terminal_protocol_hacks() {
|
||||
use std::env::var_os;
|
||||
|
@ -454,10 +467,8 @@ pub fn terminal_protocol_hacks() {
|
|||
version < (3, 5, 6)
|
||||
}),
|
||||
);
|
||||
IN_JETBRAINS.store(
|
||||
var_os("TERMINAL_EMULATOR")
|
||||
.is_some_and(|term| term.as_os_str().as_bytes() == b"JetBrains-JediTerm"),
|
||||
);
|
||||
// Request kitty progressive enhancement value and primary device attribute.
|
||||
let _ = write_loop(&STDOUT_FILENO, b"\x1b[?u\x1b[5n");
|
||||
}
|
||||
|
||||
fn parse_version(version: &wstr) -> Option<(i64, i64, i64)> {
|
||||
|
@ -488,14 +499,13 @@ pub fn terminal_protocols_enable_ifn() {
|
|||
"\x1b[?2004h"
|
||||
} else if IN_ITERM_PRE_CSI_U.load() {
|
||||
concat!("\x1b[?2004h", "\x1b[>4;1m", "\x1b[>5u", "\x1b=",)
|
||||
} else if IN_JETBRAINS.load() {
|
||||
// Jetbrains IDE terminals vomit CSI u
|
||||
} else if KITTY_KEYBOARD_SUPPORTED.load(Relaxed) != Capability::Supported as _ {
|
||||
concat!("\x1b[?2004h", "\x1b[>4;1m", "\x1b=",)
|
||||
} else {
|
||||
concat!(
|
||||
"\x1b[?2004h", // Bracketed paste
|
||||
"\x1b[>4;1m", // XTerm's modifyOtherKeys
|
||||
"\x1b[=5u", // CSI u with kitty progressive enhancement
|
||||
kitty_progressive_enhancements!(),
|
||||
"\x1b=", // set application keypad mode, so the keypad keys send unique codes
|
||||
)
|
||||
};
|
||||
|
@ -513,7 +523,7 @@ pub(crate) fn terminal_protocols_disable_ifn() {
|
|||
}
|
||||
let sequences = if IN_ITERM_PRE_CSI_U.load() {
|
||||
concat!("\x1b[?2004l", "\x1b[>4;0m", "\x1b[<1u", "\x1b>",)
|
||||
} else if IN_JETBRAINS.load() {
|
||||
} else if KITTY_KEYBOARD_SUPPORTED.load(Relaxed) != Capability::Supported as _ {
|
||||
concat!("\x1b[?2004l", "\x1b[>4;0m", "\x1b>",)
|
||||
} else {
|
||||
concat!(
|
||||
|
@ -1086,6 +1096,21 @@ pub trait InputEventQueuer {
|
|||
_ => return None,
|
||||
},
|
||||
b'u' => {
|
||||
if private_mode == Some(b'?') {
|
||||
FLOG!(
|
||||
reader,
|
||||
"Received kitty progressive enhancement flags, marking as supported"
|
||||
);
|
||||
KITTY_KEYBOARD_SUPPORTED.store(Capability::Supported as _, Relaxed);
|
||||
if !IN_MIDNIGHT_COMMANDER_PRE_CSI_U.load() && !IN_ITERM_PRE_CSI_U.load() {
|
||||
let _ = write_loop(
|
||||
&STDOUT_FILENO,
|
||||
kitty_progressive_enhancements!().as_bytes(),
|
||||
);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
// Treat numpad keys the same as their non-numpad counterparts. Could add a numpad modifier here.
|
||||
let key = match params[0][0] {
|
||||
57399 => '0',
|
||||
|
@ -1133,6 +1158,16 @@ pub trait InputEventQueuer {
|
|||
self.push_front(CharEvent::Implicit(ImplicitEvent::FocusOut));
|
||||
return None;
|
||||
}
|
||||
b'n' => {
|
||||
if KITTY_KEYBOARD_SUPPORTED.load(Relaxed) == Capability::Unknown as _ {
|
||||
FLOG!(
|
||||
reader,
|
||||
"Did not receive kitty progressive enhancement flags, marking as unsupported"
|
||||
);
|
||||
KITTY_KEYBOARD_SUPPORTED.store(Capability::NotSupported as _, Relaxed);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
Some(key)
|
||||
|
|
Loading…
Reference in a new issue