mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-30 02:22:25 +00:00
fix(tui): add OSC 8 hyperlinks for wrapped URLs (#17814)
* feat(tui): add OSC 8 hyperlinks to make wrapped URLs clickable Long URLs that exceed terminal width get broken across lines by pi-tui's word wrapping, making them unclickable. Post-process rendered markdown output to add OSC 8 terminal hyperlink sequences around URL fragments, so each line fragment links to the full URL. Gracefully degrades on terminals without OSC 8 support. * tui: harden OSC8 URL extraction and prefix resolution * tui: add changelog entry for OSC 8 markdown hyperlinks --------- Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
This commit is contained in:
@@ -1,12 +1,22 @@
|
||||
import { theme } from "../theme/theme.js";
|
||||
import { MarkdownMessageComponent } from "./markdown-message.js";
|
||||
import { Container, Spacer } from "@mariozechner/pi-tui";
|
||||
import { markdownTheme, theme } from "../theme/theme.js";
|
||||
import { HyperlinkMarkdown } from "./hyperlink-markdown.js";
|
||||
|
||||
export class AssistantMessageComponent extends Container {
|
||||
private body: HyperlinkMarkdown;
|
||||
|
||||
export class AssistantMessageComponent extends MarkdownMessageComponent {
|
||||
constructor(text: string) {
|
||||
super(text, 0, {
|
||||
super();
|
||||
this.body = new HyperlinkMarkdown(text, 1, 0, markdownTheme, {
|
||||
// Keep assistant body text in terminal default foreground so contrast
|
||||
// follows the user's terminal theme (dark or light).
|
||||
color: (line) => theme.assistantText(line),
|
||||
});
|
||||
this.addChild(new Spacer(1));
|
||||
this.addChild(this.body);
|
||||
}
|
||||
|
||||
setText(text: string) {
|
||||
this.body.setText(text);
|
||||
}
|
||||
}
|
||||
|
||||
37
src/tui/components/hyperlink-markdown.ts
Normal file
37
src/tui/components/hyperlink-markdown.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import type { Component, DefaultTextStyle, MarkdownTheme } from "@mariozechner/pi-tui";
|
||||
import { Markdown } from "@mariozechner/pi-tui";
|
||||
import { addOsc8Hyperlinks, extractUrls } from "../osc8-hyperlinks.js";
|
||||
|
||||
/**
|
||||
* Wrapper around pi-tui's Markdown component that adds OSC 8 terminal
|
||||
* hyperlinks to rendered output, making URLs clickable even when broken
|
||||
* across multiple lines by word wrapping.
|
||||
*/
|
||||
export class HyperlinkMarkdown implements Component {
|
||||
private inner: Markdown;
|
||||
private urls: string[];
|
||||
|
||||
constructor(
|
||||
text: string,
|
||||
paddingX: number,
|
||||
paddingY: number,
|
||||
theme: MarkdownTheme,
|
||||
options?: DefaultTextStyle,
|
||||
) {
|
||||
this.inner = new Markdown(text, paddingX, paddingY, theme, options);
|
||||
this.urls = extractUrls(text);
|
||||
}
|
||||
|
||||
render(width: number): string[] {
|
||||
return addOsc8Hyperlinks(this.inner.render(width), this.urls);
|
||||
}
|
||||
|
||||
setText(text: string): void {
|
||||
this.inner.setText(text);
|
||||
this.urls = extractUrls(text);
|
||||
}
|
||||
|
||||
invalidate(): void {
|
||||
this.inner.invalidate();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user