Add Edit menu so ⌘V/dictation work in Settings text fields#514
Merged
Conversation
Settings text fields couldn't accept a paste — ⌘V did nothing and dictation/voice insertion failed. The app built a custom NSApp.mainMenu with only an App menu, so the standard cut:/copy:/paste:/selectAll:/undo selectors were never registered on the responder chain and ⌘V in plain SwiftUI TextField/TextEditor was silently dropped. Add a standard Edit menu (Undo/Redo/Cut/Copy/Paste/Select All) wired to the first responder in setupMenu(). This is an app-wide fix. The terminal is unaffected: GhosttySurfaceView.performKeyEquivalent intercepts ⌘V/⌘C at the view level before the main menu sees them. 🐦⬛ Generated with Claude Code, orchestrated by Crow Co-Authored-By: Claude <noreply@anthropic.com> Crow-Session: 8CC01877-519E-428E-90B8-63D473C0D838
dgershman
approved these changes
Jun 15, 2026
dgershman
left a comment
Collaborator
There was a problem hiding this comment.
Code & Security Review
Critical Issues
None.
Security Review
Strengths:
- Pure UI/menu wiring. No input handling, IPC, network, or persistence changes — no new attack surface.
- Menu items use
target = nil(viaaddItem(withTitle:action:keyEquivalent:)), which routes selectors through the first-responder chain. Standard Cocoa pattern; no privileged code paths added. - App-wide fix with minimal blast radius — only adds a submenu to
NSApp.mainMenu.
Concerns: None.
Code Quality
Strengths:
- Excellent in-code comment (
AppDelegate.swift:1083–1087) explains the root cause, the fix, and why the terminal is unaffected, citing #512. Future maintainers won't have to reverse-engineer this. - Verified the terminal-isn't-affected claim against
Packages/CrowTerminal/Sources/CrowTerminal/GhosttySurfaceView.swift:255:performKeyEquivalentreturnstruefor any Cmd/Ctrl keyDown while the surface is non-nil, so a focused terminal intercepts ⌘V/⌘C before the main menu sees them. ✅ - Redo correctly uses uppercase
"Z"as the key equivalent, which auto-adds the shift modifier — matches the macOS HIG. Selector(("undo:"))/Selector(("redo:"))as string-based selectors is the standard Cocoa pattern forundo:/redo:(they aren't@objcon a concrete class — they're routed through the responder chain to whichever responder implements them, e.g. NSTextView via its UndoManager). Same approach Interface Builder emits.#selector(NSText.cut(_:))/copy/paste/selectAllcorrectly target methods that any AppKit text responder implements; the responder chain handles dispatch.setupMenu()is invoked once fromapplicationDidFinishLaunching(AppDelegate.swift:1039), so no risk of duplicate menu items on re-entry.- Hard-coded English titles ("Undo", "Cut", etc.) are consistent with the existing App menu items in the same function ("Restart Manager", "Hide Crow", "Quit Crow") — no localization regression.
Consider (Green, non-blocking):
- The standard macOS Edit menu typically also offers "Paste and Match Style" (⌘⇧⌥V) and a Find submenu. The minimum viable set here is fine for fixing the Settings paste bug; richer items can land as a follow-up if a use case appears.
Summary Table
| Color | Meaning | Verdict effect |
|---|---|---|
| Red | Must fix | Request changes |
| Yellow | Should fix | Request changes |
| Green | Consider | Approve allowed |
Recommendation: Approve — driven by [0 Red, 0 Yellow, 1 Green] findings.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #512
Problem
Text fields across the Settings screens couldn't accept a paste —
⌘Vdid nothing and dictation/voice insertion failed.Root cause
setupMenu()inAppDelegate.swiftbuilt a customNSApp.mainMenucontaining only an App menu — no Edit menu. On macOS the standardcut:/copy:/paste:/selectAll:/undo selectors are registered and routed through the Edit menu's items; with no Edit menu,⌘Vin a plain SwiftUITextField/TextEditorwas silently dropped (dictation uses the same responder-chain path).Fix
Add a standard Edit menu (Undo/Redo/Cut/Copy/Paste/Select All) wired to the first responder in
setupMenu(). App-wide fix — restores cut/copy/paste/select-all/undo everywhere.The terminal is unaffected:
GhosttySurfaceView.performKeyEquivalentreturnstruefor any Cmd/Ctrl key when the surface is focused, and in macOS the key window's view hierarchy receivesperformKeyEquivalentbefore the main menu — so a focused terminal intercepts⌘V/⌘Cbefore the Edit-menu item can fire.Verification
make appbuilds clean; full test suite passes (226 tests).⌘Vpastes in Settings fields; terminal paste still works.🤖 Generated with Claude Code