diff --git a/src/bin/fish_key_reader.rs b/src/bin/fish_key_reader.rs index b401621b1..132e450ee 100644 --- a/src/bin/fish_key_reader.rs +++ b/src/bin/fish_key_reader.rs @@ -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"); diff --git a/src/input_common.rs b/src/input_common.rs index 1618d62b3..fe0f0e83a 100644 --- a/src/input_common.rs +++ b/src/input_common.rs @@ -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', diff --git a/src/reader.rs b/src/reader.rs index fe118ae6b..17b34499a 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -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.