Skip to content

feat(tui): add selection to prompt as quoted context - #44443

Open
AdityaTeltia wants to merge 4 commits into
anomalyco:devfrom
AdityaTeltia:quote-selection
Open

feat(tui): add selection to prompt as quoted context#44443
AdityaTeltia wants to merge 4 commits into
anomalyco:devfrom
AdityaTeltia:quote-selection

Conversation

@AdityaTeltia

@AdityaTeltia AdityaTeltia commented Aug 23, 2026

Copy link
Copy Markdown

Issue for this PR

Related to #21025. That issue was closed as not planned and the earlier attempt in #21026 was closed by automated PR cleanup rather than review, so the feature is still missing.

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Selecting text in the transcript copies it, but there is no way to carry that text into the next message short of pasting it back by hand.

Adds prompt.add_selection (<leader>p, and "Add selection to chat" in the palette). It takes the selection, prefixes each line with > , and inserts it at the cursor as a collapsed chip via the existing pasted-text part machinery, so it stashes, restores and expands on submit like any other pasted block. Blockquote rather than a wrapper tag is deliberate: there is no closing delimiter for selected text to break out of.

The catch is that copy-on-select called clearSelection() on mouse release, so a command running afterwards saw nothing selected. Selection.copy now takes { retain: true } on that path. Three things depended on selections being short-lived:

  • A key:after intercept dismisses the retained highlight on the first key no binding consumed. It skips while pendingSequence is non-empty, otherwise <leader> would clear the selection before the second key lands, and skips while a dialog is open, otherwise typing to filter the palette would drop it.
  • Clicking something non-selectable left the old highlight alive, and several mouse-up handlers bail out when a selection exists, so the click was swallowed. The root onMouseDown now clears a leftover highlight. Drag-to-select is unaffected because opentui's startSelection clears first, so the selection is empty at mouse-down time.
  • The dialog escape binding was disabled whenever a selection had text, which would have left escape dead while a highlight was up. Its command already clears the selection before closing, so that guard is dropped and escape closes in one press.

How did you verify your code works?

bun typecheck across the monorepo (30/30) and bun test in packages/tui (200 pass, 0 fail).

  • test/selection-retention.test.ts drives a real createTestRenderer plus the actual opencode keymap: ctrl+x retains the selection, p dispatches the command, an unbound key dismisses, palette-filter keys do not.
  • test/selection.test.ts covers retain vs clear, and that take reads only the live selection so no stale text can be added.
  • A keymap test asserts prompt_add_selection resolves through CommandMap to <leader>p. I also checked <leader>p is unused across every other default binding.

Screenshots / recordings

Screen_Recording_2026-08-23_compressed.mp4

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Selecting text in the transcript copies it, but there was no way to carry it
into the next message. Add a prompt.add_selection command, bound to <leader>p,
that inserts the selection at the cursor as a blockquote chip that expands on
submit.

Copy-on-select previously cleared the highlight on mouse release, so any command
running afterwards saw nothing selected. It is now retained and dismissed by the
next click, or by the first key no binding consumed. Leader sequences and open
dialogs are exempt so the keybind and the command palette can both read it.
@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

@Enough1122

Copy link
Copy Markdown

AI code review — automated review for reference, author can ignore or act on any point.

Nice, well-tested feature — the retention lifecycle (retain on copy-on-select, dismiss on unconsumed key or click, exempt dialogs) is thoughtfully handled, tests cover both the keymap plumbing and the selection helpers, and <leader>p doesn't collide with any existing default leader binding. A few refinements:

  1. Quote prefix can compoundpackages/tui/src/component/prompt/index.tsx:384-386 prefixes every line with > . Selecting an already-quoted region yields > > ..., and blank lines become " > "-style lines with trailing whitespace (an empty line maps to "> "). Consider skipping/folding empty lines, or detecting an existing > prefix per line so re-quoting stays idempotent.

  2. Dialog-binding change is broader than the palettepackages/tui/src/ui/dialog.tsx:106 re-enables all dialog bindings whenever a selection exists, not just during command-palette filtering. Previously any active selection suppressed dialog keys entirely; now e.g. Escape will dismiss any open dialog while the user happens to have text highlighted behind it. If the intent is only "the palette must stay usable," scoping the exemption to the command palette dialog would keep other dialogs' old semantics.

  3. Retained highlight survives scroll — the dismiss intercept at packages/tui/src/app.tsx:432-440 skips keys that were handled, and scrolling keys are typically bound, so the highlight lingers over scrolled/stale content until an unbound key or click arrives. That may be intended (it keeps the quote target visible), but consider also clearing on viewport scroll so users don't quote text they're no longer looking at.

Minor:

  • Selection.take() clearing before validating the paste path is fine given the toast fallback, but note it means a failed pasteText still loses the user's highlight (prompt/index.tsx:377-388) — capturing the string first and clearing only after success would be slightly safer.

Blank and padded lines no longer carry trailing whitespace into the quote.
The highlight is cleared only after the quote reaches the prompt. Dialog
escape and ctrl+c dismiss a retained highlight before closing, restoring the
old two-step behaviour for every dialog rather than only the palette.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants