Probe for kitty keyboard protocol support
Some checks are pending
make test / ubuntu (push) Waiting to run
make test / ubuntu-32bit-static-pcre2 (push) Waiting to run
make test / ubuntu-asan (push) Waiting to run
make test / macos (push) Waiting to run
Rust checks / rustfmt (push) Waiting to run
Rust checks / clippy (push) Waiting to run

I believe this fixes more cases than it breaks.  For example
this should fix Termux which seems to be popular among fish
users. Unfortunately I haven't yet managed to test that one.

Cherry-pick of all of
- e49dde87cc (Probe for kitty keyboard protocol support, 2025-01-03)
- 10f1f21a4f (Don't send kitty kbd protocol probe until ECHO is disabled, 2025-01-05)
- dda4371679 (Stop sending CSI 5n when querying for kitty keyboard support, 2025-01-05)
This commit is contained in:
Johannes Altmanninger 2025-01-03 22:19:41 +01:00
parent 620eed466b
commit 4decacb933
3 changed files with 41 additions and 13 deletions

View File

@ -9,19 +9,19 @@
use std::{ops::ControlFlow, os::unix::prelude::OsStrExt};
use libc::{STDIN_FILENO, TCSANOW, VEOF, VINTR};
use libc::{STDIN_FILENO, STDOUT_FILENO, TCSANOW, VEOF, VINTR};
#[allow(unused_imports)]
use fish::future::IsSomeAnd;
use fish::{
builtins::shared::BUILTIN_ERR_UNKNOWN,
common::{shell_modes, str2wcstring, PROGRAM_NAME},
common::{shell_modes, str2wcstring, write_loop, PROGRAM_NAME},
env::env_init,
eprintf, fprintf,
input::input_terminfo_get_name,
input_common::{
terminal_protocol_hacks, terminal_protocols_enable_ifn, CharEvent, InputEventQueue,
InputEventQueuer,
InputEventQueuer, KITTY_PROGRESSIVE_ENHANCEMENTS_QUERY,
},
key::{self, char_to_symbol, Key},
panic::panic_handler,
@ -140,6 +140,7 @@ fn setup_and_process_keys(continuous_mode: bool, verbose: bool) -> i32 {
unsafe { libc::tcsetattr(STDIN_FILENO, TCSANOW, &*shell_modes()) };
terminal_protocol_hacks();
let _ = write_loop(&STDOUT_FILENO, KITTY_PROGRESSIVE_ENHANCEMENTS_QUERY);
if continuous_mode {
eprintf!("\n");

View File

@ -431,10 +431,19 @@ pub fn update_wait_on_sequence_key_ms(vars: &EnvStack) {
static TERMINAL_PROTOCOLS: AtomicBool = AtomicBool::new(false);
static KITTY_KEYBOARD_SUPPORTED: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
macro_rules! kitty_progressive_enhancements {
() => {
"\x1b[=5u"
};
}
pub const KITTY_PROGRESSIVE_ENHANCEMENTS_QUERY: &[u8] = b"\x1b[?u";
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;
@ -449,10 +458,6 @@ 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"),
);
}
fn parse_version(version: &wstr) -> Option<(i64, i64, i64)> {
@ -483,15 +488,14 @@ 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() {
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
"\x1b=", // set application keypad mode, so the keypad keys send unique codes
kitty_progressive_enhancements!(),
"\x1b=", // set application keypad mode, so the keypad keys send unique codes
)
};
FLOG!(term_protocols, "Enabling extended keys and bracketed paste");
@ -508,7 +512,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() {
concat!("\x1b[?2004l", "\x1b[>4;0m", "\x1b>",)
} else {
concat!(
@ -989,6 +993,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(true);
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',

View File

@ -78,6 +78,7 @@ use crate::history::{
use crate::input::init_input;
use crate::input_common::terminal_protocols_disable_ifn;
use crate::input_common::IN_MIDNIGHT_COMMANDER_PRE_CSI_U;
use crate::input_common::KITTY_PROGRESSIVE_ENHANCEMENTS_QUERY;
use crate::input_common::{
terminal_protocol_hacks, terminal_protocols_enable_ifn, CharEvent, CharInputStyle, InputData,
ReadlineCmd,
@ -1932,6 +1933,13 @@ impl<'a> Reader<'a> {
}
}
static queried: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
if !queried.load() {
queried.store(true);
// Query for kitty keyboard protocol support.
let _ = write_loop(&STDOUT_FILENO, KITTY_PROGRESSIVE_ENHANCEMENTS_QUERY);
}
// HACK: Don't abandon line for the first prompt, because
// if we're started with the terminal it might not have settled,
// so the width is quite likely to be in flight.