Skip to content

Hyperlinks spanning wrapped lines are not grouped (missing 'id' parameter in OSC 8) #735

Closed

Description

@mugnimaestra

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 id parameter, so the terminal treats the link segments on each row as separate hyperlinks rather than one continuous link.

Video Demonstration

opencode-issues.mov

Root Cause

In packages/core/src/zig/renderer.zig at line 670, the OSC 8 open sequence does not include an id parameter:

// Current (line 670):
writer.print("\x1b]8;;{s}\x1b\\", .{url_bytes}) catch {};

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 id parameter to recognize that both segments belong to the same logical hyperlink.

Proposed Fix

Add the link ID to the OSC 8 open sequence:

// Fixed:
writer.print("\x1b]8;id={d};{s}\x1b\\", .{currentLinkId, url_bytes}) catch {};

currentLinkId is already tracked in the renderer's state and is the correct identifier to use here.

Rendering Flow (for context)

  1. JS layer: textBufferSetStyledText() receives chunks with optional link: { url } property
  2. Link encoding: linkAlloc() allocates URL in Zig LinkPool, returns numeric ID; ID is packed into the upper 24 bits of attributes u32
  3. Style registration: setStyledText() in text-buffer.zig calls registerStyle() with full attributes (including link_id bits)
  4. Word wrapping: text-buffer-view.zig calculateVirtualLinesGeneric() — wrapping is link-unaware, splits purely on geometry
  5. Cell rendering: buffer.zig drawTextBufferInternal() resolves style spans per-cell; link_id flows through resolved_style.attributes into cell attributes
  6. Terminal output: renderer.zig prepareRenderFrame() emits OSC 8 sequences — currentLinkId persists across rows (never reset between rows), but the missing id param prevents the terminal from grouping the segments

Test 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 matching id parameters.

Activity

  1. added 2 commits that reference this issue on Feb 24, 2026
    2f689b2
    5a892d5
  2. added
    bugSomething isn't working
    coreThis relates to the core package
    on Feb 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcoreThis relates to the core package

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions