Skip to content

chat: a click away from selected text clears it - #9

Merged
foxnne merged 1 commit into
mainfrom
chat/select-clear
Oct 16, 2026
Merged

foxnne merged 1 commit into
mainfrom
chat/select-clear

Conversation

@foxnne

@foxnne foxnne commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

A selection in the transcript stayed when the person clicked empty space, another message or the message box, so several messages could show a selection at once and none went away. Now a selection goes when the person presses anywhere outside the text it is in: another message, empty space, the message box, elsewhere in fizzy. Copy (⌘C) of a selection still works.

How

dvui keeps a TextLayoutWidget's selection after it loses focus. The chat tracks which widget inside the transcript holds focus (dvui.lastFocusedIdInFrameSince around the scroll area: a text the person pressed in, or the scroll area after a click on empty space). When that changes, it tells the old text to select nothing with Window.addEventTextSelect(.{ .start = 0, .end = 0, .target_id = old }) at the top of the next frame. That is the plugin's beginFrame, before any widget runs, which is when dvui asks for added events. A text given a selection scrolls its cursor into view, so on that frame the chat puts the viewport back where it set it. drawTranscript's height and scroll code is otherwise unchanged: one call before the scroll area, one after.

Selection across messages: what's missing

A selection that spans several messages, the way a document's does, isn't possible from the plugin:

  • dvui: a selection belongs to one TextLayoutWidget, as byte offsets into its own text, and a drag is captured by the layout it started in. Nothing lets a drag continue into a sibling layout, and nothing asks a layout which byte is under a point without capturing (findPoint is private). A multi-layout selection needs a selection owned above the layouts (anchor and focus as layout + byte), handed to each layout through InitOptions.selection (already public), plus a public point-to-byte query and a way to keep a drag going across layouts.
  • markdown service: even with that, a message's text is laid out by the markdown plugin (markdown.Api.renderInline), one layout per paragraph, and InlineOptions has only width, image_base_dir and id_extra. The service can't take a selection, report the selected text, or clear it. The seam is an InlineOptions field for a caller-owned selection (or selectedText(id_extra) / clearSelection(id_extra) on the service). That's an SDK change in fizzy, and once it exists this PR's focus tracking becomes a direct clear.

Within one paragraph, selecting, double/triple-click and copy are dvui's, as before.

Seen

macOS, in a sandbox profile with a seeded sample transcript, driven by a demo tape (no OS events), with captures before and after:

  • Before: text selected in one message stays when a second message's text is selected (both highlighted), and stays after a click on empty space.
  • After: selecting in the second message clears the first. A click on empty space clears the second. A click in the message box clears it too. ⌘C, then ⌘V into the message box, pastes the selected words.
  • I couldn't scroll the transcript from a tape (wheel ticks didn't move it), so the "keeps the viewport" path, where a selection sits half off screen when cleared, wasn't seen.

zig fmt --check src plugin.zig clean; built against the fizzy main SDK (--fork).

🤖 Generated with Claude Code

@foxnne
foxnne marked this pull request as ready for review October 16, 2026 14:53
@foxnne
foxnne added this pull request to stack #13 October 16, 2026 14:53
A selection in the transcript stayed when the person clicked empty space,
another message or the message box, so two or three messages could show a
selection at once and none went away. Now the selection goes when focus
leaves the text it is in, as in a document.

dvui keeps a text layout's selection after it loses focus. The chat tracks
which widget inside the transcript holds focus (`lastFocusedIdInFrameSince`
around the scroll area) and, when that changes, tells the old text to select
nothing with `Window.addEventTextSelect` at the top of the next frame (the
plugin's `beginFrame`, before any widget runs, as dvui asks of added events).
dvui scrolls a text's cursor into view when it is given a selection, so that
frame keeps the viewport where it was put.
@foxnne
foxnne force-pushed the chat/select-clear branch from fa4b851 to a70b523 Compare October 16, 2026 15:37
@foxnne
foxnne merged commit 04349c1 into main Oct 16, 2026
6 checks passed
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