cmd+C does not copy inside alt-screen TUIs on macOS — the PTY fallback in copy() is Linux-gated
Summary
Warp already has the fix for this — it's just gated to Linux.
#13988 (Linux, ctrl+shift+c swallowed while Claude Code owns an internal selection) was fixed in #14046 by appending a fallback to TerminalView::copy(): if nothing of Warp's own was copied and the alt screen is active, forward the copy intent to the PTY so the TUI can copy its own selection. On macOS, cmd+C dispatches to that same copy() — but the fallback is wrapped in cfg!(target_os = "linux"), so it never fires and cmd+C silently does nothing.
This is the second half of #9159. #14012 (merged, thank you) fixed the encoder so cmd+Backspace / cmd+arrows now reach the TUI correctly. The copy path is a separate, app-level interception that #14012 does not touch, so #9159 closed with cmd+C still broken.
Environment
- Warp
0.2026.08.05.09.03.01(includes #14012) - macOS 26.5.1, arm64
- Claude Code 2.1.228 with
"tui": "fullscreen"(any alt-screen TUI with its own selection reproduces — opencode behaves the same)
Repro
- Run Claude Code in fullscreen mode in Warp.
- Select text inside the TUI using its internal selection.
- Press
cmd+C.
Expected: the selection lands on the macOS clipboard, matching ctrl+C (which Claude Code repurposes as copy while a selection is active) and matching what ctrl+shift+c now does on Linux after #14046.
Actual: nothing is copied. Warp consumes the keystroke, finds no selection of its own, and stops. The clipboard is unchanged.
Root cause
app/src/terminal/view.rs:16520 — fn copy(). The final fallback, added by #14046:
// If nothing was copied and a fullscreen TUI (alt screen) is managing its own selection,
// forward the copy intent to the foreground TUI so it can copy its own selection.
if cfg!(target_os = "linux")
&& self.selected_blocks.is_empty()
&& self.model.lock().is_alt_screen_active()
{
self.user_write_ctrl_c_to_pty(ctx);
}
cfg!(target_os = "linux") at view.rs:16575 is the whole problem. Everything else in the guard is platform-neutral and already correct for macOS:
terminal:copyis bound tocmd+Con macOS with predicateid!("Terminal") & !id!("IMEOpen")(app/src/terminal/view/init.rs:376), which is always true in a terminal pane — so Warp wins the keystroke before the encoder ever sees it. No user-side keybinding, setting, orkeybindings.yamlunbinding changes this, and no encoder fix can reach it.- Every earlier branch of
copy()has already returned by the time the fallback is reached, so the fallback only runs when Warp genuinely had nothing to copy. user_write_ctrl_c_to_pty()(view.rs:8758) is platform-independent.
Proposed fix
Drop the platform gate:
if self.selected_blocks.is_empty() && self.model.lock().is_alt_screen_active() {
self.user_write_ctrl_c_to_pty(ctx);
}
This is the same behavior #14046 already shipped, validated, and regression-tested on Linux — just no longer restricted to one platform. Konsole parity was the argument there; iTerm2 and Ghostty parity is the argument here.
The obvious objection, and why I think it's manageable
cmd+C is pressed reflexively on macOS, so the failure mode is louder than on Linux: press it with nothing selected anywhere while an alt-screen TUI is running, and you now send 0x03 and interrupt the program instead of doing nothing.
That risk is identical in kind to the one already accepted for ctrl+shift+c on Linux, and the existing guard (alt screen active AND no Warp selection AND no selected blocks) means it never fires at a shell prompt. If it's still too sharp for the default cmd+C, two smaller options that would both fix my case:
- Put it behind a setting —
forward_copy_to_alt_screen_tui, defaulting off on macOS. - Instead of
0x03, forwardcmd+CasCSI 99;9uwhen the TUI has enabled the Kitty keyboard protocol, and let the TUI decide what to do with Super+C. Cleaner separation of concerns, but it only helps once TUIs add a binding for it, whereas option 1 and the straight ungating work today with Claude Code as shipped.
Happy to open the PR for whichever shape you prefer.
Related
- #9159 — parent issue, closed by #14012 (encoder half only)
- #13988 / #14046 — the Linux equivalent and the fix this issue asks to extend
- #14012 — Cmd/Option encoding under KKP, merged 2026-08-04
Source: warpdotdev/warp