diff --git a/src/tui/components/hyperlink-markdown.test.ts b/src/tui/components/hyperlink-markdown.test.ts index 7e819c0cb3c5..2de9e9975702 100644 --- a/src/tui/components/hyperlink-markdown.test.ts +++ b/src/tui/components/hyperlink-markdown.test.ts @@ -17,6 +17,30 @@ function osc8Targets(raw: string) { } describe("HyperlinkMarkdown", () => { + it("does not reallocate prepared lines for an unchanged same-width redraw", () => { + const markdown = new HyperlinkMarkdown( + "مرحبا [docs](https://example.test/path)", + 0, + 0, + markdownTheme, + ); + + const first = markdown.render(80); + expect(markdown.render(80)).toBe(first); + + const resized = markdown.render(40); + expect(resized).not.toBe(first); + expect(markdown.render(40)).toBe(resized); + + markdown.setText("updated"); + const updated = markdown.render(40); + expect(updated).not.toBe(resized); + expect(markdown.render(40)).toBe(updated); + + markdown.invalidate(); + expect(markdown.render(40)).not.toBe(updated); + }); + it("moves dunder identifiers intact across fenced code wrap boundaries", () => { const markdown = new HyperlinkMarkdown( ["```python", 'if __name__ == "__main__":', "```"].join("\n"), diff --git a/src/tui/components/hyperlink-markdown.ts b/src/tui/components/hyperlink-markdown.ts index 18a64836f97b..9f0347cebde6 100644 --- a/src/tui/components/hyperlink-markdown.ts +++ b/src/tui/components/hyperlink-markdown.ts @@ -24,6 +24,7 @@ function sanitizeMarkdownDisplayText(text: string): string { export class HyperlinkMarkdown implements Component { private inner: Markdown; private urls: string[]; + private cachedRender?: { width: number; lines: string[] }; constructor( text: string, @@ -39,16 +40,25 @@ export class HyperlinkMarkdown implements Component { } render(width: number): string[] { - return addOsc8Hyperlinks(this.inner.render(width), this.urls).map(isolateRtlRenderedLine); + if (this.cachedRender?.width === width) { + return this.cachedRender.lines; + } + const lines = addOsc8Hyperlinks(this.inner.render(width), this.urls).map( + isolateRtlRenderedLine, + ); + this.cachedRender = { width, lines }; + return lines; } setText(text: string): void { const displayText = sanitizeMarkdownDisplayText(text); this.inner.setText(displayText); this.urls = extractUrls(displayText); + this.cachedRender = undefined; } invalidate(): void { this.inner.invalidate(); + this.cachedRender = undefined; } }