mirror of
https://github.com/anomalyco/opentui.git
synced 2026-04-24 20:45:56 +03:00
[GH-ISSUE #735] Hyperlinks spanning wrapped lines are not grouped (missing 'id' parameter in OSC 8) #968
Labels
No labels
bug
core
documentation
feature
good first issue
help wanted
pull-request
question
react
solid
tmux
windows
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/opentui#968
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @mugnimaestra on GitHub (Feb 24, 2026).
Original GitHub issue: https://github.com/anomalyco/opentui/issues/735
Bug Description
When a hyperlink wraps across multiple terminal lines, Cmd/Ctrl+Click only selects the portion on the clicked line instead of the full URL. This happens because the OSC 8 hyperlink escape sequences emitted by the renderer are missing the
idparameter, so the terminal treats the link segments on each row as separate hyperlinks rather than one continuous link.Video Demonstration
https://github.com/user-attachments/assets/697edfef-6e11-4147-93fa-f7ae1d6f3441
Root Cause
In
packages/core/src/zig/renderer.zigat line 670, the OSC 8 open sequence does not include anidparameter:Per the OSC 8 hyperlink spec, when a hyperlink is split across multiple rows (e.g., link text ends at end of row N, padding spaces close it, then it reopens on row N+1), the terminal needs the
idparameter to recognize that both segments belong to the same logical hyperlink.Proposed Fix
Add the link ID to the OSC 8 open sequence:
currentLinkIdis already tracked in the renderer's state and is the correct identifier to use here.Rendering Flow (for context)
textBufferSetStyledText()receives chunks with optionallink: { url }propertylinkAlloc()allocates URL in ZigLinkPool, returns numeric ID; ID is packed into the upper 24 bits ofattributesu32setStyledText()intext-buffer.zigcallsregisterStyle()with full attributes (including link_id bits)text-buffer-view.zigcalculateVirtualLinesGeneric()— wrapping is link-unaware, splits purely on geometrybuffer.zigdrawTextBufferInternal()resolves style spans per-cell; link_id flows throughresolved_style.attributesinto cell attributesrenderer.zigprepareRenderFrame()emits OSC 8 sequences —currentLinkIdpersists across rows (never reset between rows), but the missingidparam prevents the terminal from grouping the segmentsTest Coverage
Existing hyperlink tests in
packages/core/src/zig/tests/renderer_test.zig(lines 621-760) cover basic hyperlink rendering but do not test multi-line wrapped hyperlinks. A new test should verify that wrapped hyperlinks emit matchingidparameters.