Repository navigation
Prompt-aware text selection at the shell prompt (terminal.promptSelection) - #14856
teamleaderleo wants to merge 39 commits into
Conversation
Pure decision logic for Layer 2 of manaflow-ai#13915: given the shell input under the cursor (caret stops, caret, input selection) it resolves Select All, Shift/Cmd+Shift+arrow extension, Cut, Delete and typed text into a select, clear, or arrow+backspace edit, and passes everything through when there is no prompt state. Wiring waits on the Ghostty prompt-input export. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 8 minutes. View limit detailsLimit details: You’ve used all 10 included reviews currently available. Review configuration: ⚙️ Run configurationConfiguration used: Repository: manaflow-ai/cmux/.coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (28)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 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 |
|
All contributors have signed the CLA ✍️ ✅ |
At the end of a zsh buffer Right accepts an autosuggestion, and the suggestion's cells read as input, so Cmd+A there selects it too. Collapsing now moves the caret left onto the edge when needed but never right. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…nal view Off by default. At a shell prompt, Cmd+A selects only the command being typed, Shift+Left/Right and Cmd+Shift+Left/Right extend, Cmd+X cuts through the normal copy path, and typing, Backspace, or Delete replace the selection by replaying arrow and Backspace keys through Ghostty's key path. Without a held selection only Shift+arrows reach the resolver, so ordinary typing pays one nil check. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…mpt-aware-selection # Conflicts: # Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/TerminalSection.swift # Sources/CmuxSettingsFileStore+SupportedPaths.swift # skills/cmux-settings/references/all-keys.md # web/data/cmux.schema.json
manaflow-ai/ghostty#235 adds ghostty_surface_prompt_input and ghostty_surface_select_prompt_input. build-ghosttykit.yml runs their Zig tests before packaging, and docs/ghostty-fork.md records the change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tions, non-Latin layouts Cut writes the selection's exact untrimmed text, so a whitespace-only selection no longer copies an empty string and pasting restores what was deleted. Cmd+A/Cmd+X wait behind an in-flight clipboard read, Shift-arrows leave a selection outside the input to Ghostty's adjust_selection, and the key match uses the layout-normalized characters. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
manaflow-ai/ghostty#237 ends the prompt input at the first empty cell at or after the cursor, so RPROMPT cells are no longer caret stops that an edit could delete past. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
manaflow-ai/ghostty#238 drops a run of spaces at or after the cursor that reaches the end of the input. With RPROMPT shown zle erases deleted text by writing spaces, which counted as caret stops past the buffer. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
CI failure attributionCI failed on
Matched log linesNot re-run automatically: Written by |
|
/catch-up |
|
Catch-up only runs on branches in this repository for now, so I left this one alone. A maintainer can merge main in by hand. |
Catch-up merge by scripts/ci/catch_up_pr.py (RFC manaflow-ai#14631). Merged by scripts/merge-main.sh: origin/main at e1f1cb2, the newest commit with green CI fast guards (2 newer skipped). Resolved generated files: - Resources/Localizable.xcstrings: xcstrings key-level union Catch-up-previous-head: f195582 Catch-up-base: e1f1cb2
…odule The app target sees Ghostty's C API through the ghostty.h bridging header, whose precompiled header CI reuses from a seeded DerivedData even after the submodule header changes, so the new declarations were missing there. The CmuxTerminalCore wrappers compile against GhosttyKit's own module and keep the C calls behind the terminal core's interop seam. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
83876e9 to
7762400
Compare
Catch-up merge by scripts/ci/catch_up_pr.py (RFC manaflow-ai#14631). Merged by scripts/merge-main.sh: origin/main at de22b47, the newest commit with green CI fast guards (1 newer skipped). Resolved generated files: - Resources/Localizable.xcstrings: xcstrings key-level union - Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/ConfigValidation/CmuxConfigSchema.generated.swift: generate-cmux-config-schema.py, regenerated from the merged schema Catch-up-previous-head: 7762400 Catch-up-base: de22b47
Catch-up merge by scripts/ci/catch_up_pr.py (RFC manaflow-ai#14631). Merged by scripts/merge-main.sh: origin/main at badf9f6. Resolved conflicts: - Resources/Localizable.xcstrings: xcstrings key-level union Catch-up-previous-head: 94e3c29 Catch-up-base: badf9f6
SwiftPM cannot link GhosttyKit, so the package tests satisfy the link with weak stubs; CmuxTerminalCore now references ghostty_surface_prompt_input, ghostty_surface_select_prompt_input and ghostty_surface_has_selection. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Cross-model review (Codex gpt-5.6-sol)
|
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Deployment failed for project cmux with the following error: |
|
Review: stale tracked prompt-selection anchors survived collapse followed by paste or surface replacement. Fixed: 70c339a. Left: prompt-input symbol stubs remain test-only link stubs; Ghostty points at e1b8bf5f4, which includes the merged Ghostty changes. |
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Catch-up merge by scripts/ci/catch_up_pr.py (RFC manaflow-ai#14631). Merged by scripts/merge-main.sh: origin/main at ecba57a. Catch-up-previous-head: 9fff5d7 Catch-up-base: ecba57a
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Catch-up merge by scripts/ci/catch_up_pr.py (RFC manaflow-ai#14631). Merged by scripts/merge-main.sh: origin/main at 40a636e. Resolved conflicts: - Resources/Localizable.xcstrings: xcstrings key-level union Catch-up-previous-head: ea178e7 Catch-up-base: 40a636e Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Auto-merge is off for now: copy and paste at the prompt can't be shown in a screenshot, so this waits for a hands-on check on a dev build before it merges. |
Merge-main commit by scripts/merge-main.sh.\nMerged by scripts/merge-main.sh: origin/main at e709b69.\n\nResolved conflicts:\n- Resources/Localizable.xcstrings: xcstrings key-level union\n- Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/ConfigValidation/CmuxConfigSchema.generated.swift: generate-cmux-config-schema.py, regenerated from the merged schema (both sides changed the schema)\n\nMerge-main-previous-head: 1cf4acb\nMerge-main-base: e709b69\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Resolved docs/ghostty-fork.md by preserving the prompt-input selection history and current main Ghostty history.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Merge-main commit by scripts/merge-main.sh. Merged by scripts/merge-main.sh: origin/main at b3d644b. Resolved conflicts: - Resources/Localizable.xcstrings: xcstrings key-level union Merge-main-previous-head: 342613a Merge-main-base: b3d644b Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Merge-main commit by scripts/merge-main.sh. Merged by scripts/merge-main.sh: origin/main at ea6e02b. Resolved conflicts: - Resources/Localizable.xcstrings: xcstrings key-level union - Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/ConfigValidation/CmuxConfigSchema.generated.swift: generate-cmux-config-schema.py, regenerated from the merged schema (both sides changed the schema) Merge-main-previous-head: e406d4d Merge-main-base: ea6e02b
Keep the Ghostty submodule at the prompt-selection fork commit while retaining main for the unchanged Bonsplit gitlink.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Pending Ghostty dependency confirmation and hands-on prompt copy/paste dogfood before merging. — Oolong g1 🌾 |
Layer 2 of #13915: text-field selection at a shell prompt, behind a new setting
terminal.promptSelection(off by default, next toterminal.textEditingGestures). With it on, at a prompt with shell integration:Inside vim, less or any alternate-screen app, while a command runs, or without shell integration, every key behaves exactly as it does today.
How it works
The Ghostty fork now exports where the input is (manaflow-ai/ghostty#235, with #237 and #238 so a right prompt and the spaces zle writes to erase text don't count; all merged, submodule at
e1b8bf5f478c6aadbf70e51cdbb41930e92fda10, which also includes merged manaflow-ai/ghostty#236 and #239):Offsets are caret stops:
.inputcells holding text, wide spacers skipped, so one stop is one arrow press for zle or readline. The export refuses the alternate screen, a running command, a line with no prompt before its input (fzf--heightand completion menus draw in input mode), and a line with a multi-codepoint grapheme. The input ends at the first empty cell at or after the cursor, because zle draws RPROMPT after OSC 133 B by moving across the gap, so a right prompt is.inputtext. Spaces after the cursor that run into that end are dropped too, since with RPROMPT shown zle erases deleted text by writing spaces.The pure resolver (
TerminalPromptSelection.swift, 25 tests) turns a gesture plus that snapshot into pass-through, consume, select, clear, or an arrow+Backspace edit.GhosttyNSViewcalls it from two places:performKeyEquivalentmatches Cmd+A and Cmd+X (layout-normalized) ahead of Ghostty'sselect_allbinding. It waits behind an in-flight clipboard read.keyDown, ahead of the text-editing gestures, handles Shift+arrows, and while cmux holds a prompt selection, the keys that collapse or replace it. With no held selection, ordinary typing pays one nil check and a key-code compare; the defaults read and the Ghostty call happen only for gestures.Edits are replayed as Left/Right/Backspace presses through
sendGhosttyKey, so Ghostty encodes them for whatever keyboard protocol is active (same reasoning as #13921). The two C calls live in CmuxTerminalCore (TerminalPromptInputSnapshot.read(from:),TerminalPromptSelection.select(on:)), which compiles against GhosttyKit's own module; the package test runners get weak stubs for them.Decided defaults and known limits
.inputcells, and Ghostty can't tell it apart cheaply, so Cmd+A at the end of a line selects the suggestion too. Right never accepts it while a selection is active, because collapsing never presses Right. An edit that reaches into the suggestion (Shift+Right past the buffer, then Backspace) presses Right once, which accepts the whole suggestion first.^Xin two cells, so an edit across it sends one Backspace too many.adjust_selection, and typing never replaces a selection cmux didn't make.Settings: catalog,
cmux.jsonpath, schema (docs page renders from it), Settings row, search index and aliases,all-keys.md, and the three new strings in all nine macOS locales (localization_catalog.py check: 0 parity errors).Catch-up and review fix
Merged main at
478e3232b0991564a380a4d67b5e55c60dc2aa3busing the repository merge helper. Selection anchors now clear on non-selection input and terminal surface replacement, so Shift+Left after collapse and paste starts at the current caret rather than a stale offset. Regression tests were committed inbca0fc73b1f9a497e4b461d76c6a810a059962e7, followed by the fix in70c339a9848da78137ad16e6d4a5421bb59969c4.On that head,
macOS compile admissionandswift-package-testspassed in CI run 36689103816. Both new tracker tests executed and passed. The pre-fix test commit was not executed, so no red-before result is claimed. App-host tests are still running. The CLI lane failed only in the unchanged Codex monitor memory test at its five-second parser-checkpoint deadline; a rerun will follow when the workflow finishes. Vercel previews failed before building because the repository did not contain the requested fork reference.A review subagent found no confirmed correctness defect. The remaining coverage limitation is that tracker tests do not drive the AppKit paste or surface-attach methods directly. The prompt-input stubs stay in package test targets only; they are needed to link tests without starting Ghostty and are not a runtime workaround.
Changelog
Added: optional shell-prompt selection with keyboard gestures, copy, cut, and selection replacement.
Validation (earlier head)
promptInputZig tests ran inbuild-ghosttykit.ymlbefore packaging atb93ab4222(run 36319683313: 84/84 with the filter vs 74 for the single-test pacer filter), which also published the xcframework; its checksum is pinned. This PR adds that test step to the workflow.e8af053:macOS compile admission,app-host unit tests (changed suites)andCLI product testspassed.swift-package-testspassed every package includingCmuxTerminalCore(the "Terminal prompt selection resolver" suite, 23 tests),CmuxTerminalandCmuxCloudTui. The first attempt failed only inCmuxSimulator("Closing the parent pipe writer delivers output through EOF", a package this PR doesn't touch); the rerun passed.GhosttyTerminalViewcompiled on some runners and failed on others with the new declarations missing. The app sees Ghostty's C API through theghostty.hbridging header, and a seeded DerivedData's bridging PCH (regenerated in 0.06 s) predates the submodule bump. Moving the calls into CmuxTerminalCore fixed it; the seeding gap itself will bite the next Ghostty header change that app code uses directly.scripts/ci/guards-local.sh, 66 steps) pass on the head.Dogfood
CI dogfood tour run 36736813041 passed on the pre-catch-up head 1cf4acb. The tour shows typed prompt input, Shift+Left selecting
world, Cmd+A selecting only the input, and typing replacing the selection. The latest catch-up merges main through b3d644b; the prompt-selection code and tour are unchanged. The package tests exercise tracker invalidation, not the AppKit paste or attach paths. Checks to run in zsh with shell integration and the setting on:echo hello world, Cmd+A: only the input highlights, not the prompt or output.pbpasteunchanged.worldhighlights; Shift+Right ×2 shrinks it; Cmd+Shift+Left extends to the start.pbpasteshows exactly the highlighted text.pbpastehas it; select one space and Cmd+X: the clipboard holds a space, never empty.x: the selection is replaced; Backspace and Delete remove a selection.RPROMPT='%~': Cmd+A and Cmd+Shift+Right never select the right prompt; typegit status, Backspace togit, Shift+Right selects nothing pastgit, and no edit deletes unselected characters.vimandless: Cmd+A, Shift+arrows, typing behave exactly as with the setting off.🤖 Generated with Claude Code
Screenshots
The cropped frames below come from the passing CI dogfood tour run 36736813041.
Please check copy/paste on the dev-build link. This PR is from
teamleaderleo/cmux, so a dev-build link is unavailable because that label only works for branches inmanaflow-ai/cmux.The PR is caught up through main at
b3d644ba87324ef330080fda68db5b7f61b6fcc8; the final branch head ise406d4d8009cd17c022d3ed90825e4bc4e47e278.