Skip to content

feat: copy text from panels [2] and [3] by selecting it with the mouse - #69

Merged
stanlyzoolo merged 1 commit into
mainfrom
mouse-selection-copy
Aug 23, 2026
Merged

feat: copy text from panels [2] and [3] by selecting it with the mouse#69
stanlyzoolo merged 1 commit into
mainfrom
mouse-selection-copy

Conversation

@stanlyzoolo

Copy link
Copy Markdown
Owner

Text in [2] and [3] was on screen but unreachable: the terminal's own selection is gone under the alt screen with mouse reporting on, so a version string, a command from a README fence or a release note could only be retyped by hand.

Drag with the left button in the brief card or the docs panel to select, release to copy the plain text to the system clipboard. The status bar reports copied N characters, or copy failed: <err> when the clipboard write fails.

How it works

  • handleSelectableMouse (render.go) is the shared driver for both panels: Press anchors, Motion extends, Release copies. A drag belongs to the panel it was anchored in, so a release over [1] or outside the viewport still finalizes instead of stranding selActive with the highlight frozen on screen.
  • Coordinates are content coordinates (selPos{line, col}), not screen ones — YOffset is added when mapping a row back to a line and never stored, so the selection survives scrolling. paintSelection auto-scrolls at the window edges so a drag can extend past what is visible.
  • beginSelection snapshots the panel's rendered lines (styled + ANSI-stripped) at press time, so a motion event repaints without re-rendering the card or the README.
  • The highlight is ansi.Cut + reverse video, applied per whole line — the codebase's strip-then-repaint rule, so a cut can never land inside an escape sequence.
  • Copy runs off the Update thread (copyCmd): clipboard.WriteAll shells out to pbcopy/xclip/wl-clipboard/PowerShell and can block.

Behavior changes

  • A card link now opens on Release, not on Press — the press anchors a drag, and a drag starting on the repo line must copy rather than open the browser. Only a motion-less release opens the link.
  • Any keystroke abandons an in-flight drag: a release is not always delivered (the button can be let go over another window), and a key must never act on content still wearing the highlight.
  • Selection is gated exactly like every other click: modeNormal only, nothing while an overlay is up.
  • github.com/atotto/clipboard moves from indirect to a direct dependency.

Tests

selection_test.go covers copy on release, a drag starting on a link not opening it, an empty click copying nothing, a release outside the panel finalizing, and the overlay/non-normal gate. textutil_test.go covers highlightLine, selectedText and highlightSelection as pure functions; commands_test.go drives the copyDoneMsg handler through the writeClipboard seam.

Preflight green: build, vet, test -race, golangci-lint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@stanlyzoolo
stanlyzoolo merged commit 577ad3c into main Aug 23, 2026
3 checks passed
@stanlyzoolo
stanlyzoolo deleted the mouse-selection-copy branch August 23, 2026 17:24
stanlyzoolo added a commit that referenced this pull request Aug 23, 2026
Follow-up to #69, which added drag-to-copy in [2]/[3] but left four claims
stale and one dependency undocumented:

- README Stack was missing atotto/clipboard, now a direct dependency
- README's mouse bullet said "selection", ambiguous between the tool cursor
  and text selection
- ARCHITECTURE still said a card link opens on click; it opens on Release
  without motion, never on Press, because the press anchors a drag
- ARCHITECTURE had no drag-selection invariant at all
- neither document listed the new writeClipboard test seam

CLAUDE.md edits kept minimal: the file is at 147k of the 150k harness limit.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant