#15016·warp

cmd+C does not copy inside alt-screen TUIs on macOS — the PTY fallback in copy() is Linux-gated

Author: LarryKongCreated Aug 12, 2026Updated Sep 17, 2026
Labelsbugtriagedrepro:highos:macarea:settings-keybindingsarea:terminal-inputwarp:auto-triage-reviewagent:bug

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

  1. Run Claude Code in fullscreen mode in Warp.
  2. Select text inside the TUI using its internal selection.
  3. 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:16520fn 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:copy is bound to cmd+C on macOS with predicate id!("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, or keybindings.yaml unbinding 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:

  1. Put it behind a setting — forward_copy_to_alt_screen_tui, defaulting off on macOS.
  2. Instead of 0x03, forward cmd+C as CSI 99;9u when 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