Emit OSC 8 hyperlinks through the render path#26
Merged
Conversation
The renderer reconstructs its output from midterm's cell grid, so OSC 8 sequences from the inner program were being dropped even though the fork now tracks them per-region. Walk Region.URLID transitions in RenderLineFrom and emit \033]8;;<URL>\033\\ open/close pairs around runs sharing a URL. Each row stands alone — opening at the start of a linked run and closing at row end — so the cursor reposition between rows doesn't carry a stale link forward. Scrollback entries store the resolved URI per FormatRun (not just the URL ID) so they're self-contained against later midterm state changes, captured at OnScrollback time. renderHistoryEntry emits OSC 8 the same way as the live path. go.mod uses a local replace for the midterm fork during development; needs to be repointed at a pushed dcosson/midterm commit before merge. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A URI containing ESC/BEL/other C0 controls could break out of the OSC 8 envelope and inject arbitrary terminal sequences into the outer terminal. midterm's parser already terminates OSC at ESC and BEL so the live path is naturally safe in practice, but the history path stores resolved URI strings as plain data — defense in depth at the rendering boundary is cheap and protects against future midterm changes. writeOSC8BoundaryStr is now the single emission gate; it rejects any URL containing bytes < 0x20 or 0x7F (DEL) and drops the link entirely rather than try partial recovery. RenderLineFrom pre-resolves and caches the sanitized URL per region ID so state-tracking stays consistent. Repoint go.mod replace from a local checkout to the pushed dcosson/midterm osc8-hyperlinks branch so other agents and CI can build. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Symmetry fix from review: previously lastURL held the raw run.URL even when writeOSC8BoundaryStr had dropped the URL as unsafe, so an unsafe-only linked run would emit a harmless final close at row end without a corresponding open. Pre-sanitize and track the result, just like RenderLineFrom does, so the state machine reflects what was actually emitted. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the pseudo-version pin with the v0.2.4-dcosson.1 tag on the dcosson/midterm fork. The pre-release suffix keeps us sorted below any future upstream v0.2.4 release. Co-Authored-By: Claude Opus 4.7 (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.
Summary
Emit OSC 8 hyperlinks through h2's render path so links from inner programs (Claude Code file paths,
gh,ls --hyperlink=always, etc.) become clickable in the outer terminal. Previously midterm parsed OSC 8 but our renderer reconstructed output cell-by-cell and dropped the URLs.RenderLineFromwalksRegion.URLIDtransitions and emits OSC 8 open/close around each linked run. Each row stands alone (open at start of linked run, close at row end).ScrollHistoryentries store the resolved URI perFormatRunso they're self-contained against later midterm state changes; captured at OnScrollback time.renderHistoryEntryemits OSC 8 the same way.go.modpinned todcosson/midterm@v0.2.4-dcosson.1(pre-release suffix keeps us behind any future upstream v0.2.4).Test plan
make checklints cleanprintf '\e]8;;https://example.com\e\\click here\e]8;;\e\\\n'insideh2 run --command bashrenders as a clickable link🤖 Generated with Claude Code