← Back to PRs

#17814: fix(tui): add OSC 8 hyperlinks for wrapped URLs

by Phineas1500 open 2026-02-16 06:20 View on GitHub →
stale size: M
## Summary Fixes #17772 — an alternative to #17777 that uses **OSC 8 terminal hyperlinks** instead of ZWNJ characters. - Post-processes rendered markdown output to wrap URL fragments with [OSC 8 hyperlink sequences](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda), making them clickable even when broken across lines by pi-tui's word wrapping - Each line fragment of a broken URL gets its own OSC 8 sequence pointing to the full URL - Gracefully degrades on terminals without OSC 8 support (iTerm2, Windows Terminal, GNOME Terminal 3.50+, Kitty, WezTerm all support it) ## Why this over #17777 (ZWNJ approach) | | #17777 (ZWNJ) | This PR (OSC 8) | |---|---|---| | **Copy/paste** | Broken — invisible U+200C chars corrupt pasted URLs | Clean — URL text is untouched | | **Clickable links** | No — only hints where to break lines | Yes — each fragment is a real terminal hyperlink | | **Works with pi-tui** | No — `breakLongWord()` still breaks char-by-char regardless of ZWNJ | Yes — post-processes *after* wrapping | | **Unicode correctness** | U+200C has line-break class `CM`, not `WJ`; doesn't actually prevent breaks | N/A — accepts wrapping, makes fragments clickable | | **Degradation** | Invisible chars always present in text | Terminals without OSC 8 simply ignore sequences | The ZWNJ approach tries to *prevent* wrapping but fails because `breakLongWord()` ignores ZWNJ. Our approach *accepts* wrapping and makes the broken fragments clickable using the industry-standard OSC 8 mechanism. ## Changes - **`src/tui/osc8-hyperlinks.ts`** — `extractUrls()` to find URLs in markdown source, `addOsc8Hyperlinks()` to post-process rendered lines with OSC 8 sequences (handles multi-line URL splits) - **`src/tui/components/hyperlink-markdown.ts`** — `HyperlinkMarkdown` wrapper around pi-tui's `Markdown` that applies OSC 8 post-processing in `render()` - **`src/tui/components/assistant-message.ts`** — Use `HyperlinkMarkdown` instead of `Markdown` - **`src/tui/osc8-hyperlinks.test.ts`** — 17 unit tests ## Test plan - [x] `pnpm vitest run src/tui/osc8-hyperlinks.test.ts` — 17/17 pass - [x] `pnpm build` passes - [x] `pnpm check` passes (lint + format + types) - [x] Manual: TUI renders long URLs as clickable OSC 8 hyperlinks in iTerm2 - [ ] Manual: verify graceful degradation in a terminal without OSC 8 support <!-- greptile_comment --> <h3>Greptile Summary</h3> Implemented OSC 8 terminal hyperlinks to make URLs in TUI markdown clickable even when wrapped across lines. - Added `osc8-hyperlinks.ts` with URL extraction from markdown (`extractUrls`) and OSC 8 sequence injection (`addOsc8Hyperlinks`) - Created `HyperlinkMarkdown` wrapper component that post-processes pi-tui's `Markdown` output with OSC 8 sequences - Updated `AssistantMessageComponent` to use `HyperlinkMarkdown` instead of raw `Markdown` - Handles multi-line URL splits by tracking pending URL state across lines - Preserves ANSI styling codes while injecting OSC 8 sequences - Comprehensive test suite with 17 tests covering single-line, multi-line, styled, and edge cases <h3>Confidence Score: 4/5</h3> - This PR is safe to merge with minor considerations for the previously flagged issues - The implementation is solid with comprehensive tests (17/17 passing), handles ANSI codes correctly, and uses a sound post-processing approach. Two minor logic issues were previously flagged regarding regex patterns and prefix resolution that should be verified but don't affect core functionality. The feature gracefully degrades on unsupported terminals and doesn't introduce security risks. - The `src/tui/osc8-hyperlinks.ts` file has two previously identified issues in the URL resolution logic that should be reviewed, but these are edge cases that don't affect typical usage <sub>Last reviewed commit: ac29c75</sub> <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs