-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Problem
Markdown links [text](url) in TUI chat messages are parsed by pulldown-cmark and styled (cyan + underline), but the URL is discarded after styling. The link text is visually distinct but not clickable in the terminal.
Bare URLs (e.g. https://github.com/...) are already clickable via regex detection + OSC 8 escape sequences in hyperlink.rs.
This means long URLs from LLM responses (PR links, documentation links, etc.) cannot be shortened to readable text like [PR #570](https://github.com/bug-ops/zeph/pull/570) — users either see the full URL or a styled but non-clickable label.
Current flow
pulldown-cmark parser
→ MdRenderer captures link_url in Event::Start(Tag::Link)
→ Text styled with theme.link (cyan + underline)
→ Event::End(TagEnd::Link) clears link_url
→ URL is discarded — never reaches hyperlink system
Proposed solution
Collect (rendered_text_range, url) pairs during markdown rendering and merge them into the hyperlink collection alongside regex-detected bare URLs.
Changes
-
widgets/chat.rs—MdRenderer- Add a field
link_spans: Vec<(String, String)>to accumulate(display_text, url)pairs - On
Event::End(TagEnd::Link), push the captured text and URL intolink_spans - Expose
link_spansviafinish()return value (or a separate accessor)
- Add a field
-
widgets/chat.rs—render_md()/render_chat_message()- Propagate the collected link spans up to the caller
- Store them alongside rendered lines so
collect_from_buffercan use them
-
hyperlink.rs—collect_from_buffer()- Accept an additional parameter: pre-resolved markdown link mappings
- For spans matching a known markdown link text at the expected position, use the stored URL instead of regex detection
- Regex detection continues to handle bare URLs as before
-
No changes needed in
write_osc8()— it already handles arbitraryHyperlinkSpanentries
Scope
- ~50-80 lines of changes across 2 files
- No new dependencies
- Backward compatible: bare URL detection unchanged
Acceptance criteria
-
[text](url)in assistant messages renders as clickable OSC 8 hyperlink withtextas display - Bare URLs remain clickable as before
- Nested markdown formatting inside links preserved (e.g.
[**bold link**](url)) - Existing hyperlink tests pass; new tests cover markdown link collection
Related files
crates/zeph-tui/src/hyperlink.rs— URL detection, OSC 8 outputcrates/zeph-tui/src/widgets/chat.rs—MdRenderer, markdown rendering pipelinecrates/zeph-tui/src/lib.rs— hyperlink emission in render loop