From db1a4145692fcfc88fb354f478b0019ca0d2ef9d Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Tue, 4 Aug 2026 03:44:23 +0000 Subject: [PATCH] Avoid requesting key-release events in Ghostty (#36834) ## Why Ghostty can leak release events for shortcuts that the terminal consumes. ## What changed - Detect Ghostty when `TERM` is `xterm-ghostty`, including when `TERM_PROGRAM` is unavailable. - Omit `REPORT_EVENT_TYPES` from keyboard enhancement flags for Ghostty while retaining alternate-key and escape-code disambiguation reporting. ## Testing - Cover Ghostty detection through `TERM` and its keyboard enhancement flags. GitOrigin-RevId: d865a6cdd1373aad4b78099e821d1ebaeb6cfdff --- codex-rs/terminal-detection/src/lib.rs | 3 ++- .../terminal-detection/src/terminal_tests.rs | 19 +++++++++++++++++++ codex-rs/tui/src/tui/keyboard_modes.rs | 17 +++++++++++++++-- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/codex-rs/terminal-detection/src/lib.rs b/codex-rs/terminal-detection/src/lib.rs index c42733380d..5e9b197138 100644 --- a/codex-rs/terminal-detection/src/lib.rs +++ b/codex-rs/terminal-detection/src/lib.rs @@ -150,6 +150,7 @@ impl TerminalInfo { fn from_term(term: String, multiplexer: Option) -> Self { let name = match term.as_str() { "dumb" => TerminalName::Dumb, + "xterm-ghostty" => TerminalName::Ghostty, "wezterm" | "wezterm-mux" => TerminalName::WezTerm, _ => TerminalName::Unknown, }; @@ -293,7 +294,7 @@ pub fn terminal_info() -> TerminalInfo { /// - Otherwise, `TERM_PROGRAM` (plus `TERM_PROGRAM_VERSION`) drives the detected terminal name. /// This means `TERM_PROGRAM` can mask later probes (for example `WT_SESSION`). /// - Next, terminal-specific variables (WEZTERM, iTerm2, Apple Terminal, kitty, etc.) are checked. -/// - Finally, `TERM` is used as the capability fallback with `TerminalName::Unknown`. +/// - Finally, `TERM` is used as the capability fallback. /// /// tmux client term info is only consulted when a tmux multiplexer is detected, and it is /// derived from `tmux display-message` to surface the underlying terminal program instead of diff --git a/codex-rs/terminal-detection/src/terminal_tests.rs b/codex-rs/terminal-detection/src/terminal_tests.rs index 54f0a7a5a9..06f41090ab 100644 --- a/codex-rs/terminal-detection/src/terminal_tests.rs +++ b/codex-rs/terminal-detection/src/terminal_tests.rs @@ -239,6 +239,25 @@ fn detects_ghostty() { "Ghostty", "ghostty_term_program_user_agent" ); + + let env = FakeEnvironment::new().with_var("TERM", "xterm-ghostty"); + let terminal = detect_terminal_info_from_env(&env); + assert_eq!( + terminal, + terminal_info( + TerminalName::Ghostty, + /*term_program*/ None, + /*version*/ None, + Some("xterm-ghostty"), + /*multiplexer*/ None + ), + "ghostty_term_info" + ); + assert_eq!( + terminal.user_agent_token(), + "xterm-ghostty", + "ghostty_term_user_agent" + ); } #[test] diff --git a/codex-rs/tui/src/tui/keyboard_modes.rs b/codex-rs/tui/src/tui/keyboard_modes.rs index 28db590a3b..f6c08fcbb0 100644 --- a/codex-rs/tui/src/tui/keyboard_modes.rs +++ b/codex-rs/tui/src/tui/keyboard_modes.rs @@ -156,10 +156,12 @@ fn keyboard_enhancement_flags( let flags = KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES | KeyboardEnhancementFlags::REPORT_ALTERNATE_KEYS; - // iTerm can leak the release of an exit shortcut into the parent shell. + // iTerm and Ghostty can leak shortcut release events that the terminal consumes. // tmux's xterm key format also loses Shift-Enter when event types are // reported. Preserve repeat classification on transports that support it. - if terminal_name == TerminalName::Iterm2 || matches!(tmux_extended_keys_format, Some("xterm")) { + if matches!(terminal_name, TerminalName::Ghostty | TerminalName::Iterm2) + || matches!(tmux_extended_keys_format, Some("xterm")) + { flags } else { flags | KeyboardEnhancementFlags::REPORT_EVENT_TYPES @@ -331,6 +333,17 @@ mod tests { ); } + #[test] + fn keyboard_enhancement_suppresses_release_reporting_for_ghostty() { + assert_eq!( + ansi_for(PushKeyboardEnhancementFlags(keyboard_enhancement_flags( + TerminalName::Ghostty, + /*tmux_extended_keys_format*/ None + ))), + "\x1b[>5u" + ); + } + #[test] fn keyboard_enhancement_preserves_repeat_reporting_for_kitty() { assert_eq!(