mirror of
https://github.com/openai/codex.git
synced 2026-10-14 16:38:43 +00:00
Default to copying transcript selections in more terminals (#48469)
## What changed
Make `tui.copy_on_select = "auto"` copy on mouse release unless a direct terminal is known to forward its native copy shortcut: Ghostty with a parsed version at least `1.2.0`, Kitty on macOS, Windows Terminal, or VS Code on Windows.
Unknown terminals and Ghostty with older, missing, or unrecognized versions now default to copying. Keep copying enabled under tmux/Zellij and preserve explicit `always` and `never` overrides. Update the configuration documentation and schema to describe these defaults.
## Testing
Expand the existing configuration test matrix to cover more terminals, Ghostty versions (including `1.2.0-dev`), platform-specific defaults, and multiplexer behavior alongside configuration and launch overrides.
GitOrigin-RevId: 410abfa580156454b0f88e0bf4ed977fb8c81b1e
(cherry picked from commit b334d5b3f2)
This commit is contained in:
committed by
Ian MacLeod
parent
3e1ab64168
commit
5a7bb4dac9
@@ -865,8 +865,9 @@ pub struct Tui {
|
||||
pub fullscreen_transcript: bool,
|
||||
|
||||
/// Copy selected transcript text when the mouse button is released.
|
||||
/// Defaults to `auto`: enabled in tmux/Zellij and in direct macOS terminals except Ghostty/Kitty.
|
||||
/// On other platforms, direct terminals default off except iTerm2/Terminal.app.
|
||||
/// Defaults to `auto`: enabled except in direct terminals known to forward their native
|
||||
/// copy shortcut (Ghostty 1.2+, Kitty on macOS, Windows Terminal, and VS Code on Windows).
|
||||
/// Unknown terminals, Ghostty without a recognized version, and tmux/Zellij default to copying.
|
||||
#[serde(default)]
|
||||
pub copy_on_select: CopyOnSelect,
|
||||
|
||||
|
||||
@@ -4359,7 +4359,7 @@
|
||||
}
|
||||
],
|
||||
"default": "auto",
|
||||
"description": "Copy selected transcript text when the mouse button is released. Defaults to `auto`: enabled in tmux/Zellij and in direct macOS terminals except Ghostty/Kitty. On other platforms, direct terminals default off except iTerm2/Terminal.app."
|
||||
"description": "Copy selected transcript text when the mouse button is released. Defaults to `auto`: enabled except in direct terminals known to forward their native copy shortcut (Ghostty 1.2+, Kitty on macOS, Windows Terminal, and VS Code on Windows). Unknown terminals, Ghostty without a recognized version, and tmux/Zellij default to copying."
|
||||
},
|
||||
"disable_paste_burst": {
|
||||
"description": "When true, disables burst-paste detection for typed input entirely. All characters are inserted as they are received, and no buffering or placeholder replacement will occur for fast keypress bursts. Overrides the legacy top-level `disable_paste_burst` setting. Defaults to `false`.",
|
||||
|
||||
@@ -14,7 +14,6 @@ use codex_config::types::CopyOnSelect;
|
||||
use codex_config::types::History;
|
||||
use codex_config::types::Notice;
|
||||
use codex_config::types::Tui;
|
||||
use codex_terminal_detection::Multiplexer;
|
||||
use codex_terminal_detection::TerminalInfo;
|
||||
use codex_terminal_detection::TerminalName;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
@@ -129,22 +128,47 @@ impl LocalSettings {
|
||||
settings
|
||||
}
|
||||
|
||||
/// Prefer explicit overrides; tmux/Zellij always default to copying on release.
|
||||
/// Direct macOS terminals default on except Ghostty/Kitty, which forward Cmd-C.
|
||||
/// Copy on release unless a direct terminal is known to forward its default copy shortcut.
|
||||
/// Multiplexers, unknown terminals and Ghostty without a recognized version default to copying.
|
||||
pub(crate) fn copy_on_select(&self, terminal: &TerminalInfo) -> bool {
|
||||
match self.tui.copy_on_select {
|
||||
CopyOnSelect::Always => true,
|
||||
CopyOnSelect::Never => false,
|
||||
CopyOnSelect::Auto => match terminal.multiplexer {
|
||||
Some(Multiplexer::Tmux { .. } | Multiplexer::Zellij { .. }) => true,
|
||||
None if cfg!(target_os = "macos") => {
|
||||
!matches!(terminal.name, TerminalName::Ghostty | TerminalName::Kitty)
|
||||
}
|
||||
None => matches!(
|
||||
terminal.name,
|
||||
TerminalName::Iterm2 | TerminalName::AppleTerminal
|
||||
),
|
||||
},
|
||||
CopyOnSelect::Auto => {
|
||||
terminal.multiplexer.is_some()
|
||||
|| match terminal.name {
|
||||
// Since 1.2, both Ghostty's Cmd-C and Ctrl-Shift-C bindings are
|
||||
// "performable": they forward the key if Ghostty has no selection.
|
||||
TerminalName::Ghostty => !terminal
|
||||
.version
|
||||
.as_deref()
|
||||
.and_then(|version| semver::Version::parse(version).ok())
|
||||
.is_some_and(|version| {
|
||||
version
|
||||
>= semver::Version::new(
|
||||
/*major*/ 1, /*minor*/ 2, /*patch*/ 0,
|
||||
)
|
||||
}),
|
||||
// Kitty's Cmd-C uses copy_or_noop. Its Ctrl-Shift-C consumes the key.
|
||||
TerminalName::Kitty => !cfg!(target_os = "macos"),
|
||||
// Windows Terminal's Copy action forwards its key when unselected,
|
||||
// including when the CLI runs in WSL.
|
||||
TerminalName::WindowsTerminal => false,
|
||||
// VS Code gates Copy on native selection. Only Windows' default
|
||||
// (plain Ctrl-C) is also forwarded by the legacy xterm.js encoder.
|
||||
TerminalName::VsCode => !cfg!(target_os = "windows"),
|
||||
TerminalName::AppleTerminal
|
||||
| TerminalName::Iterm2
|
||||
| TerminalName::WarpTerminal
|
||||
| TerminalName::WezTerm
|
||||
| TerminalName::Alacritty
|
||||
| TerminalName::Konsole
|
||||
| TerminalName::GnomeTerminal
|
||||
| TerminalName::Vte
|
||||
| TerminalName::Dumb
|
||||
| TerminalName::Unknown => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -231,28 +231,55 @@ async fn copy_on_select_respects_terminal_defaults_and_config_overrides() -> any
|
||||
(config.tui_copy_on_select, local.tui.copy_on_select),
|
||||
(expected, expected),
|
||||
);
|
||||
for (name, multiplexer, default_enabled) in [
|
||||
(TerminalName::Iterm2, None, true),
|
||||
(TerminalName::AppleTerminal, None, true),
|
||||
(TerminalName::Ghostty, None, false),
|
||||
(TerminalName::Kitty, None, false),
|
||||
(TerminalName::Unknown, None, cfg!(target_os = "macos")),
|
||||
for (name, version, multiplexer, default_enabled) in [
|
||||
(TerminalName::Iterm2, None, None, true),
|
||||
(TerminalName::AppleTerminal, None, None, true),
|
||||
(TerminalName::Ghostty, Some("1.2.0"), None, false),
|
||||
(TerminalName::Ghostty, Some("1.3.0"), None, false),
|
||||
(TerminalName::Ghostty, Some("1.1.3"), None, true),
|
||||
(TerminalName::Ghostty, Some("1.2.0-dev"), None, true),
|
||||
(TerminalName::Ghostty, Some("invalid"), None, true),
|
||||
(TerminalName::Ghostty, None, None, true),
|
||||
(TerminalName::Kitty, None, None, !cfg!(target_os = "macos")),
|
||||
(TerminalName::WindowsTerminal, None, None, false),
|
||||
(
|
||||
TerminalName::VsCode,
|
||||
None,
|
||||
None,
|
||||
!cfg!(target_os = "windows"),
|
||||
),
|
||||
(TerminalName::Alacritty, None, None, true),
|
||||
(TerminalName::GnomeTerminal, None, None, true),
|
||||
(TerminalName::Konsole, None, None, true),
|
||||
(TerminalName::Vte, None, None, true),
|
||||
(TerminalName::WarpTerminal, None, None, true),
|
||||
(TerminalName::WezTerm, None, None, true),
|
||||
(TerminalName::Dumb, None, None, true),
|
||||
(TerminalName::Unknown, None, None, true),
|
||||
(
|
||||
TerminalName::Ghostty,
|
||||
Some("1.3.0"),
|
||||
Some(Multiplexer::Tmux { version: None }),
|
||||
true,
|
||||
),
|
||||
(
|
||||
TerminalName::Kitty,
|
||||
None,
|
||||
Some(Multiplexer::Zellij { version: None }),
|
||||
true,
|
||||
),
|
||||
(
|
||||
TerminalName::WindowsTerminal,
|
||||
None,
|
||||
Some(Multiplexer::Tmux { version: None }),
|
||||
true,
|
||||
),
|
||||
] {
|
||||
let terminal = TerminalInfo {
|
||||
name,
|
||||
multiplexer,
|
||||
term_program: None,
|
||||
version: None,
|
||||
version: version.map(str::to_owned),
|
||||
term: None,
|
||||
};
|
||||
assert_eq!(
|
||||
|
||||
Reference in New Issue
Block a user