Repository navigation
Terminal: mouse text selection and copy - #21
Merged
Merged
Conversation
The grid painted output but never let you take it back out — no way to highlight anything, so nothing could be copied. This adds drag-to-select, double-click word, triple-click line, shift-click extend, and Cmd+C. `Term` already owns a selection and knows how to keep its anchors on their text as output scrolls the grid, so the emulator layer is a thin translation: viewport rows in, grid points out, `selection_to_string` for the copy. Cells carry a `selected` flag and the view merges selected runs into wash quads, painted over the cell background but under the glyphs so highlighted text stays readable. Two details from reading zed's terminal (which embeds the same alacritty_terminal) that are not obvious until they bite: Overshoot has to force the selection *side*, not just clamp the cell. Drag past the bottom edge and drift left of where you started, and a side derived from x stops the selection mid-row instead of taking the last line whole. Clamping alone leaves that bug; alacritty and zed both force Right past the right/bottom edge and Left above the top. A press must not select on its own. Without a travel threshold the click that focuses the panel leaves a one-cell selection behind whenever the hand moves a pixel — harmless today, but it is the exact thing that clobbers the clipboard the moment anything copies on selection change. 2px, matching zed's SELECTION_DRAG_THRESHOLD and gpui's own div threshold. Not implemented: mouse *reporting*. Programs that ask for the mouse (vim, htop) still do not receive events — that was already true, and selection now owns the mouse unconditionally rather than going dead inside those programs. When reporting lands, `mouse_mode(shift)` is the gate it has to go behind, the way zed does it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
It was borrowing Theme::selection — the composer's blue. That is the right tone over prose, and the wrong one over a terminal: a saturated veil sits on top of sixteen ANSI hues and drags every one toward itself, so red output reads purple under selection and green reads teal. It undoes the per-hue tuning the palette work exists to provide. Neutral instead — white at 22% on dark, black at 16% on light. Lightness moves, hue does not, so selected text keeps the colors the program asked for. Light carries a little more ink because an equal alpha of black on near-white reads fainter than white on near-black. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
wingleeio
force-pushed
the
feat/terminal-selection
branch
from
August 6, 2026 07:35
d645210 to
d3b26ad
Compare
wingleeio
approved these changes
Aug 6, 2026
wingleeio
left a comment
Contributor
There was a problem hiding this comment.
Reviewed both commits line-by-line and verified locally after rebasing onto main: no network/filesystem/process/unsafe code, no dependency changes; the only clipboard interaction is a write on an explicit copy keystroke (no copy-on-select). Scanned the full diff for hidden/invisible Unicode (bidi overrides, zero-width) — none; only em-dashes/arrows in doc comments. 376/376 tests pass, zero clippy warnings in the changed files, fmt clean. Rebased the branch onto main (dropping the stacked #20 commit) via maintainer edit — content is byte-identical to the reviewed diff. Safe to merge.
guilhermexp
referenced
this pull request
in guilhermexp/comet
Aug 30, 2026
* Terminal: mouse text selection and copy The grid painted output but never let you take it back out — no way to highlight anything, so nothing could be copied. This adds drag-to-select, double-click word, triple-click line, shift-click extend, and Cmd+C. `Term` already owns a selection and knows how to keep its anchors on their text as output scrolls the grid, so the emulator layer is a thin translation: viewport rows in, grid points out, `selection_to_string` for the copy. Cells carry a `selected` flag and the view merges selected runs into wash quads, painted over the cell background but under the glyphs so highlighted text stays readable. Two details from reading zed's terminal (which embeds the same alacritty_terminal) that are not obvious until they bite: Overshoot has to force the selection *side*, not just clamp the cell. Drag past the bottom edge and drift left of where you started, and a side derived from x stops the selection mid-row instead of taking the last line whole. Clamping alone leaves that bug; alacritty and zed both force Right past the right/bottom edge and Left above the top. A press must not select on its own. Without a travel threshold the click that focuses the panel leaves a one-cell selection behind whenever the hand moves a pixel — harmless today, but it is the exact thing that clobbers the clipboard the moment anything copies on selection change. 2px, matching zed's SELECTION_DRAG_THRESHOLD and gpui's own div threshold. Not implemented: mouse *reporting*. Programs that ask for the mouse (vim, htop) still do not receive events — that was already true, and selection now owns the mouse unconditionally rather than going dead inside those programs. When reporting lands, `mouse_mode(shift)` is the gate it has to go behind, the way zed does it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Terminal: give the selection its own achromatic wash It was borrowing Theme::selection — the composer's blue. That is the right tone over prose, and the wrong one over a terminal: a saturated veil sits on top of sixteen ANSI hues and drags every one toward itself, so red output reads purple under selection and green reads teal. It undoes the per-hue tuning the palette work exists to provide. Neutral instead — white at 22% on dark, black at 16% on light. Lightness moves, hue does not, so selected text keeps the colors the program asked for. Light carries a little more ink because an equal alpha of black on near-white reads fainter than white on near-black. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
The terminal grid painted output but never let you take it back out — there was no way to highlight anything, so nothing could be copied.
What works now
How
Termalready owns a selection and already knows how to keep its anchors on their text as output scrolls the grid underneath. So the emulator layer is a thin translation: viewport rows in, grid points out,selection_to_stringfor the copy. Cells carry aselectedflag; the view merges selected runs into wash quads, painted over the cell background but under the glyphs so highlighted text stays readable.Two details from reading zed's terminal
Zed embeds the same
alacritty_terminal, and their mouse layer handles two things that are not obvious until they bite:Overshoot has to force the selection side, not just clamp the cell. Drag past the bottom edge and drift left of where you started, and a side derived from x stops the selection mid-row instead of taking the last line whole. Clamping alone leaves that bug. Alacritty and zed both force
Rightpast the right/bottom edge andLeftabove the top; so does this.A press must not select on its own. Without a travel threshold, the click that focuses the panel leaves a one-cell selection behind whenever the hand moves a pixel. Harmless today, but it is exactly what clobbers the clipboard the moment anything copies on selection change. 2px, matching zed's
SELECTION_DRAG_THRESHOLDand gpui's owndivthreshold.Selection color
Deliberately achromatic — white at 22% on dark, black at 16% on light — rather than reusing
Theme::selection, which is the composer's blue. A saturated veil sits on top of sixteen ANSI hues and drags every one toward itself: red output reads purple under selection, green reads teal. Neutral moves lightness only, so selected text keeps the colors the program asked for.Not implemented: mouse reporting
Programs that ask for the mouse (vim, htop) still do not receive events. That was already true before this change — but it means selection now owns the mouse unconditionally instead of going dead inside those programs, which is the more useful behaviour while reporting is missing. Zed gates all of this behind
mouse_mode(shift); when reporting lands here, that is the gate it has to go behind, and the check belongs inTerminalPanel::on_mouse_down.Tests
12 new. Pointer hit-testing including overshoot sides and degenerate metrics; word and line granularity; a selection surviving the output that scrolls it; a click without a drag reporting no selection; the wash staying achromatic in both appearances.
comet-uiis 375/375 green, clippy and fmt clean. Verified by hand in the running app.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.