Repository navigation
fix: resolve the terminal Copy guard through the Command-aware keyboard layout (#10872) - #13015
Conversation
|
All contributors have signed the CLA ✍️ ✅ |
|
Warning Review limit reachedNext included review available in 18 minutes. View limit detailsLimit details: You’ve used all 10 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Repository: manaflow-ai/cmux/.coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (2)
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: manaflow-ai/cmux/.coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthroughThe Copy menu guard now uses Command-aware keyboard layout resolution. Regression tests cover Dvorak-QWERTY, Dvorak, US-QWERTY, non-Latin input, non-Copy keys, and extra modifiers. ChangesCopy key equivalent resolution
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~25 minutes Change: Bug fix · Severity of issue fixed: Medium Suggested reviewers: 🚥 Pre-merge checks | ✅ 24 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (24 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 41.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 functions across 1 files. (1 skipped: 1 too large.) ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Merged, thank you @aliyansajid! Cmd+C on Command-swapped layouts like Dvorak no longer types a stray "j" into the terminal :D |
|
Merge receipt for |
60d8ac1 Land ejc3's isolated defaults test from manaflow-ai#12598 (manaflow-ai#14504) e926f24 fix: resolve the terminal Copy guard through the Command-aware keyboard layout (manaflow-ai#10872) (manaflow-ai#13015) 0df2946 Fix startup-race crash in v2RefreshKnownRefs against a half-restored session (manaflow-ai#2751) (manaflow-ai#9627) 611eeac ci(e2e): queue E2E runs for the owned pool within CI_PR_POOL_QUEUE_ROUNDS (manaflow-ai#14640) 27b8cbc ci: seed the Swift package cache from main pushes (manaflow-ai#14638) be46dba ci: stop E2E from saving an unresolved Swift package cache (manaflow-ai#14632) 2486e99 ci: run-e2e.sh --wait asks glaeda-gh instead of polling GitHub (manaflow-ai#14622) 088034b ci(ios): queue test-ios runs for the owned pool within CI_PR_POOL_QUEUE_ROUNDS (manaflow-ai#14630) # Conflicts: # .github/workflows/main-regression-bisect.yml # .github/workflows/perf-activation.yml # .github/workflows/seed-derived-data.yml # .github/workflows/test-e2e.yml # .github/workflows/test-ios.yml # .github/workflows/test-macos-suite.yml
Fixes #10872.
Problem
On the macOS Dvorak - QWERTY ⌘ layout, pressing ⌘C in a terminal pane with no selection types a stray
jinto the pty instead of doing nothing.consumeUnavailableCopyMenuActionexists to swallow exactly this: when nothing is selected AppKit disables Edit ▸ Copy, the main menu declines the chord, and the guard keeps it a native no-op so the failed Copy binding never reaches Ghostty's terminal-input path.The guard resolved the pressed character with
KeyboardLayout.normalizedCharacters(for:), which returnscharactersIgnoringModifiers— the character the key produces with no modifiers. AppKit matches menu key equivalents through the layout's Command table instead. On a Command-swapped layout the two disagree:charactersIgnoringModifiersjc→ CopyciSo the guard missed the real ⌘C (the
jleaks into the pty — the reported bug), and it also fired on ⌘I, silently swallowing that chord. Both directions come from the same comparison.Fix
Resolve the guard the same way AppKit resolved the menu: ask the layout for the character with the event's Command flag applied, via
KeyboardLayout.character(forKeyCode:modifierFlags:), which already translates in shortcut mode and is documented to preserve command-aware layouts. The previouscharactersIgnoringModifierspath stays as the fallback when the layout has no mapping, so behavior is unchanged on US-QWERTY and on the non-Latin input sourcesnormalizedCharacterswas added for.Plain Dvorak (no Command table swap) keeps matching Copy on the physical I key, which is correct — that really is where ⌘C lives on that layout, and it is what the menu matched.
Tests
Per
CLAUDE.md, split into two commits so CI shows the test catching the bug:test:— adds coverage; the two Dvorak-QWERTY ⌘ cases fail.fix:— the one-branch behavior change; all cases pass.The character check had to move into
GhosttyNSView.isStandardCopyMenuKeyEquivalent(_:layoutCharacterProvider:)to be testable, becauseconsumeUnavailableCopyMenuActionreturns early without a live Ghostty surface, so the gate can't be observed through it headlessly. The injectable provider mirrors the existingKeyboardShortcutSettings.matches(event:layoutCharacterProvider:)pattern and means no keyboard layout has to be installed on the test host. Commit 1 keeps the extracted logic byte-for-byte equivalent to the old inline check, so the behavior change is isolated to commit 2.Seven cases in
WindowKeyDownReplayGuardTests: both Dvorak-QWERTY ⌘ directions, plain Dvorak, US-QWERTY, a non-Latin (Hangul) input source, ⌘V, and ⌘⇧C.No user-facing strings changed, so no localization audit was required.
Two unrelated problems I hit on
main, not touched hereBoth reproduce on
e87efeafecwith no local changes, and I left both alone to keep this PR to one concern — happy to open issues or follow-up PRs:cmuxTestsbundle does not compile:cmuxTests/CLISSHPTYAttachProbeReplyRegressionTests.swift:140fails with "the compiler is unable to type-check this expression in reasonable time" on a six-way string concatenation. I broke that expression up locally (uncommitted, reverted) purely to run the suite. This looks related to main: cmuxTests bundle fails to compile (MobilePairingConnectionTransitionTests vs MobilePairingModel after #12754) #12827.terminalHostedEditableResponderKeepsLocalUndofails onundoCallCount == 1. It fails identically before and after this change and never reaches the Copy guard.Summary by cubic
Fixes the terminal Copy guard on the macOS Dvorak - QWERTY ⌘ layout so pressing ⌘C with no selection no longer types a stray "j" into the pty. The guard previously compared
charactersIgnoringModifiers, which disagrees with the character AppKit's menu matched on Command-swapped layouts; it now resolves the key through the layout's Command table, matching how AppKit declined the Copy chord.Written for commit d8d1f72. Summary will update on new commits.
Summary by CodeRabbit
Bug Fixes
Tests