OSC 8 hyperlink is dropped on wrapped continuation rows in TUI output
OSC 8 hyperlink is dropped on wrapped continuation rows in TUI output
Version: 2.1.222 (same on 2.1.221)
Platform: macOS 27.0, darwin arm64 · iTerm2 3.6.11 · tmux 3.7b
Env: FORCE_HYPERLINK=1, TERM=tmux-256color, TERM_PROGRAM=tmux, pane width 90
Summary
When a hyperlink's visible label is wider than the pane, the TUI word-wraps it and emits the
continuation on a new row without re-opening the OSC 8 sequence. Only the first row is
clickable; the rest is inert text.
It also actively misfires: iTerm2 falls back to heuristic URL detection on the orphaned
fragment and prepends a scheme. Hovering the second row of a wrapped path shows
http://respondence/Seidl_Intro_and_Simplified_Outreach_2026-08-04.md
— respondence (the tail of 02_Correspondence) read as a hostname. So a wrapped path is
not merely unclickable, it becomes a link to a nonexistent host.
Expected
Each row of a wrapped hyperlink carries the OSC 8 target, the same way wrap-ansi re-emits
SGR state at the start of every wrapped line. OSC 8 is per-cell metadata and does not depend
on line continuity, so a hard wrap need not break it — the continuation row just needs the
sequence re-opened.
Actual
Only the first row carries the link.
The terminal stack is not at fault
This is the part missing from the previous reports, which were closed on the assumption that
the terminal lacked support. Run this from a plain shell in the same tmux pane (89 cols):
P="/Users/me/deep/path/that/is/140/characters/long/Some_Long_File_Name_2026-08-04.md"
# 1) short label, vscode:// target
printf '\033]8;;vscode://file%s\033\\>>> CLICK-SHORT <<<\033]8;;\033\\\n' "$P"
# 2) long label (must wrap), vscode:// target
printf '\033]8;;vscode://file%s\033\\%s\033]8;;\033\\\n' "$P" "$P"
# 3) long label (must wrap), file:// target
printf '\033]8;;file://%s\033\\%s\033]8;;\033\\\n' "$P" "$P"
# 4) bare path, no hyperlink at all
print -r -- "$P"
All four are clickable, wrapped rows included. Therefore:
- tmux forwards OSC 8 — the attached client negotiated it
(client_termfeatures includes hyperlinks; note this requires
set -as terminal-features ",*:hyperlinks", without which tmux silently strips OSC 8);
- iTerm2 honors OSC 8 across wrapped rows, and separately rejoins soft-wrapped plain text,
which is why even case 4 works.
The identical 140-character link fails only when Claude Code renders it, in the same pane,
in the same session. That isolates the defect to the TUI's wrap step.
Code observation
The screen model already carries everything required:
- cells hold an interned hyperlink id (
hyperlinkPool.intern, extracted from the cell
attribute word), and
- there is a per-row
softWrap: Int32Array(height)plus apackSoftWrap(row, startCol)
helper, so wrap continuations are already tracked.
The gap is upstream of the cell writer: the ANSI-aware wrap that produces the rows does not
re-emit the active OSC 8 at the start of each continuation row, so those cells are written
with no hyperlink id and the row renders inert.
Impact
Any file path printed in a pane narrower than the path is unclickable. This is not an edge
case for deep trees — in the project where I hit it, 489 of 490 files exceed 90 columns
(longest 276), so effectively every path is affected, and each one leaves a bogus http://
fragment behind. ⌘-click-to-open is unusable, which is the whole point of the feature added
in 2.1.x.
Widening the pane cannot fix it (a 276-column pane is not viable) and neither can shortening
directory names, since some filenames alone exceed 150 characters.
Related issues
All previously closed as duplicate / not planned / stale, none with the isolating
reproduction above:
- #62678 — Long URLs break when ctrl-clicked or copied due to line wrapping
- #54606 — URLs not clickable when wrapping across lines (contains the hard-newline analysis)
- #48652 — Support OSC 8 hyperlinks for file paths and URLs in TUI output
- #27889 — Clickable file links for Write/Edit/Read output paths
- #13008 — OSC 8 hyperlinks for clickable file paths
- #18717 — New OSC 8
file:///hyperlinks don't work in VS Code
Suggested fix
In the wrap routine, treat the active OSC 8 like SGR state: on emitting a continuation row,
close the link at the row boundary and re-open it with the same URI (and id= parameter, so
conforming terminals treat the segments as one logical link) at the start of the next row.