mirror of
https://github.com/openai/codex.git
synced 2026-05-17 17:53:06 +00:00
fix(tui): preserve Shift+Enter in tmux csi-u panes
This commit is contained in:
@@ -125,16 +125,81 @@ pub(super) fn enable_keyboard_enhancement() {
|
||||
|
||||
let _ = execute!(
|
||||
stdout(),
|
||||
DisableModifyOtherKeys,
|
||||
PushKeyboardEnhancementFlags(
|
||||
KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
|
||||
| KeyboardEnhancementFlags::REPORT_EVENT_TYPES
|
||||
| KeyboardEnhancementFlags::REPORT_ALTERNATE_KEYS
|
||||
)
|
||||
);
|
||||
|
||||
if tmux_should_enable_modify_other_keys() {
|
||||
let _ = execute!(stdout(), EnableModifyOtherKeys);
|
||||
}
|
||||
}
|
||||
|
||||
fn running_in_tmux_session() -> bool {
|
||||
tmux_session_detected(
|
||||
std::env::var("TMUX").ok().as_deref(),
|
||||
std::env::var("TMUX_PANE").ok().as_deref(),
|
||||
)
|
||||
}
|
||||
|
||||
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>,
|
||||
) -> bool {
|
||||
// If tmux cannot be queried, still request mode 2; otherwise csi-u panes
|
||||
// can stay in VT10x. Explicit xterm format is avoided because crossterm
|
||||
// does not parse tmux's xterm-style extended-key sequences as Enter.
|
||||
running_in_tmux_session && matches!(extended_keys_format, Some("csi-u") | None)
|
||||
}
|
||||
|
||||
fn read_tmux_extended_keys_format() -> Option<String> {
|
||||
for args in [
|
||||
["display-message", "-p", "#{extended-keys-format}"],
|
||||
["show-options", "-gqv", "extended-keys-format"],
|
||||
] {
|
||||
let output = std::process::Command::new("tmux")
|
||||
.args(args)
|
||||
.stdin(std::process::Stdio::null())
|
||||
.stderr(std::process::Stdio::null())
|
||||
.output()
|
||||
.ok()?;
|
||||
|
||||
if !output.status.success() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(value) = String::from_utf8(output.stdout)
|
||||
.ok()
|
||||
.map(|value| value.trim().to_string())
|
||||
.filter(|value| !value.is_empty())
|
||||
{
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub(super) fn restore_keyboard_enhancement_stack() {
|
||||
let _ = execute!(stdout(), PopKeyboardEnhancementFlags);
|
||||
let _ = execute!(
|
||||
stdout(),
|
||||
PopKeyboardEnhancementFlags,
|
||||
DisableModifyOtherKeys
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn reset_keyboard_reporting_after_exit() {
|
||||
@@ -168,6 +233,28 @@ impl Command for ResetKeyboardEnhancementFlags {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
struct EnableModifyOtherKeys;
|
||||
|
||||
impl Command for EnableModifyOtherKeys {
|
||||
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||
f.write_str("\x1b[>4;2m")
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute_winapi(&self) -> std::io::Result<()> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Unsupported,
|
||||
"modifyOtherKeys enable is not implemented for the legacy Windows API",
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn is_ansi_code_supported(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
struct DisableModifyOtherKeys;
|
||||
|
||||
@@ -193,9 +280,12 @@ impl Command for DisableModifyOtherKeys {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DisableModifyOtherKeys;
|
||||
use super::EnableModifyOtherKeys;
|
||||
use super::ResetKeyboardEnhancementFlags;
|
||||
use super::keyboard_enhancement_disabled_for;
|
||||
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 crossterm::Command;
|
||||
use pretty_assertions::assert_eq;
|
||||
@@ -268,11 +358,51 @@ mod tests {
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tmux_session_detection_accepts_tmux_or_tmux_pane() {
|
||||
assert!(tmux_session_detected(
|
||||
Some("/tmp/tmux-501/default,1,0"),
|
||||
/*tmux_pane*/ None
|
||||
));
|
||||
assert!(tmux_session_detected(/*tmux*/ None, Some("%0")));
|
||||
assert!(!tmux_session_detected(
|
||||
/*tmux*/ None, /*tmux_pane*/ None
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tmux_modify_other_keys_requests_csi_u_or_unknown_format() {
|
||||
assert!(tmux_should_enable_modify_other_keys_for(
|
||||
/*running_in_tmux_session*/ true,
|
||||
Some("csi-u")
|
||||
));
|
||||
assert!(tmux_should_enable_modify_other_keys_for(
|
||||
/*running_in_tmux_session*/ true, /*extended_keys_format*/ None
|
||||
));
|
||||
assert!(!tmux_should_enable_modify_other_keys_for(
|
||||
/*running_in_tmux_session*/ true,
|
||||
Some("xterm")
|
||||
));
|
||||
assert!(!tmux_should_enable_modify_other_keys_for(
|
||||
/*running_in_tmux_session*/ true,
|
||||
Some("")
|
||||
));
|
||||
assert!(!tmux_should_enable_modify_other_keys_for(
|
||||
/*running_in_tmux_session*/ false,
|
||||
Some("csi-u")
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_keyboard_enhancement_flags_clears_all_pushed_levels() {
|
||||
assert_eq!(ansi_for(ResetKeyboardEnhancementFlags), "\x1b[<u");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enable_modify_other_keys_requests_xterm_keyboard_reporting() {
|
||||
assert_eq!(ansi_for(EnableModifyOtherKeys), "\x1b[>4;2m");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disable_modify_other_keys_resets_xterm_keyboard_reporting() {
|
||||
assert_eq!(ansi_for(DisableModifyOtherKeys), "\x1b[>4;0m");
|
||||
|
||||
Reference in New Issue
Block a user