mirror of
https://github.com/openai/codex.git
synced 2026-10-19 17:28:46 +00:00
Adapt keyboard event reporting to the terminal (#35021)
## Why Reporting key event types can leak an exit-shortcut release into the parent shell in iTerm2 and can cause tmux's `xterm` extended-key format to lose Shift+Enter. ## What changed - Select keyboard enhancement flags using the detected terminal and tmux extended-key format. - Disable event-type reporting for iTerm2 and tmux's `xterm` format while retaining alternate-key reporting. - Preserve event-type reporting for other terminals and tmux's `csi-u` format so repeat events remain distinguishable. ## Testing Added unit coverage for iTerm2, Kitty, unknown terminals, and both tmux extended-key formats. GitOrigin-RevId: 03a6b9d5443f626da5279413a14933af2a0ec3e5
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
use std::fmt;
|
||||
use std::io::stdout;
|
||||
|
||||
use codex_terminal_detection::TerminalName;
|
||||
use codex_terminal_detection::terminal_info;
|
||||
use crossterm::Command;
|
||||
use crossterm::event::KeyboardEnhancementFlags;
|
||||
use crossterm::event::PopKeyboardEnhancementFlags;
|
||||
@@ -123,21 +125,47 @@ pub(super) fn enable_keyboard_enhancement() {
|
||||
return;
|
||||
}
|
||||
|
||||
let running_in_tmux_session = running_in_tmux_session();
|
||||
let tmux_extended_keys_format = if running_in_tmux_session {
|
||||
read_tmux_extended_keys_format()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let _ = execute!(
|
||||
stdout(),
|
||||
DisableModifyOtherKeys,
|
||||
PushKeyboardEnhancementFlags(
|
||||
KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
|
||||
| KeyboardEnhancementFlags::REPORT_EVENT_TYPES
|
||||
| KeyboardEnhancementFlags::REPORT_ALTERNATE_KEYS
|
||||
)
|
||||
PushKeyboardEnhancementFlags(keyboard_enhancement_flags(
|
||||
terminal_info().name,
|
||||
tmux_extended_keys_format.as_deref()
|
||||
))
|
||||
);
|
||||
|
||||
if tmux_should_enable_modify_other_keys() {
|
||||
if tmux_should_enable_modify_other_keys_for(
|
||||
running_in_tmux_session,
|
||||
tmux_extended_keys_format.as_deref(),
|
||||
) {
|
||||
let _ = execute!(stdout(), EnableModifyOtherKeys);
|
||||
}
|
||||
}
|
||||
|
||||
fn keyboard_enhancement_flags(
|
||||
terminal_name: TerminalName,
|
||||
tmux_extended_keys_format: Option<&str>,
|
||||
) -> KeyboardEnhancementFlags {
|
||||
let flags = KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
|
||||
| KeyboardEnhancementFlags::REPORT_ALTERNATE_KEYS;
|
||||
|
||||
// iTerm can leak the release of an exit shortcut into the parent shell.
|
||||
// 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")) {
|
||||
flags
|
||||
} else {
|
||||
flags | KeyboardEnhancementFlags::REPORT_EVENT_TYPES
|
||||
}
|
||||
}
|
||||
|
||||
fn running_in_tmux_session() -> bool {
|
||||
tmux_session_detected(
|
||||
std::env::var("TMUX").ok().as_deref(),
|
||||
@@ -149,13 +177,6 @@ fn tmux_session_detected(tmux: Option<&str>, tmux_pane: Option<&str>) -> bool {
|
||||
tmux.is_some() || tmux_pane.is_some()
|
||||
}
|
||||
|
||||
fn tmux_should_enable_modify_other_keys() -> bool {
|
||||
tmux_should_enable_modify_other_keys_for(
|
||||
running_in_tmux_session(),
|
||||
read_tmux_extended_keys_format().as_deref(),
|
||||
)
|
||||
}
|
||||
|
||||
fn tmux_should_enable_modify_other_keys_for(
|
||||
running_in_tmux_session: bool,
|
||||
extended_keys_format: Option<&str>,
|
||||
@@ -283,11 +304,14 @@ mod tests {
|
||||
use super::EnableModifyOtherKeys;
|
||||
use super::ResetKeyboardEnhancementFlags;
|
||||
use super::keyboard_enhancement_disabled_for;
|
||||
use super::keyboard_enhancement_flags;
|
||||
use super::parse_bool_env;
|
||||
use super::tmux_session_detected;
|
||||
use super::tmux_should_enable_modify_other_keys_for;
|
||||
use super::vscode_terminal_detected;
|
||||
use codex_terminal_detection::TerminalName;
|
||||
use crossterm::Command;
|
||||
use crossterm::event::PushKeyboardEnhancementFlags;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
fn ansi_for(command: impl Command) -> String {
|
||||
@@ -296,6 +320,61 @@ mod tests {
|
||||
out
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyboard_enhancement_suppresses_release_reporting_for_iterm() {
|
||||
assert_eq!(
|
||||
ansi_for(PushKeyboardEnhancementFlags(keyboard_enhancement_flags(
|
||||
TerminalName::Iterm2,
|
||||
/*tmux_extended_keys_format*/ None
|
||||
))),
|
||||
"\x1b[>5u"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyboard_enhancement_preserves_repeat_reporting_for_kitty() {
|
||||
assert_eq!(
|
||||
ansi_for(PushKeyboardEnhancementFlags(keyboard_enhancement_flags(
|
||||
TerminalName::Kitty,
|
||||
/*tmux_extended_keys_format*/ None
|
||||
))),
|
||||
"\x1b[>7u"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyboard_enhancement_preserves_repeat_reporting_for_csi_u_tmux() {
|
||||
assert_eq!(
|
||||
ansi_for(PushKeyboardEnhancementFlags(keyboard_enhancement_flags(
|
||||
TerminalName::Kitty,
|
||||
Some("csi-u")
|
||||
))),
|
||||
"\x1b[>7u"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyboard_enhancement_preserves_shift_enter_for_xterm_tmux() {
|
||||
assert_eq!(
|
||||
ansi_for(PushKeyboardEnhancementFlags(keyboard_enhancement_flags(
|
||||
TerminalName::Kitty,
|
||||
Some("xterm")
|
||||
))),
|
||||
"\x1b[>5u"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyboard_enhancement_preserves_repeat_reporting_for_unknown_terminals() {
|
||||
assert_eq!(
|
||||
ansi_for(PushKeyboardEnhancementFlags(keyboard_enhancement_flags(
|
||||
TerminalName::Unknown,
|
||||
/*tmux_extended_keys_format*/ None
|
||||
))),
|
||||
"\x1b[>7u"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyboard_enhancement_env_flag_parses_common_values() {
|
||||
assert_eq!(parse_bool_env(Some("1")), Some(true));
|
||||
|
||||
Reference in New Issue
Block a user