perf(tui): memoize copy-selector preview highlight across renders
Every keystroke or arrow-key navigation in the copy selector re-rendered the preview by syntax-highlighting the entire `target.preview`, replacing tabs, and wrapping it to width. `CopySelectorComponent` now keeps instance-private memo fields for the last target and its generated source; `invalidate()` clears them, and rendering reuses the cached source while the selected target is unchanged. Verified with `bun test packages/coding-agent/test/modes/components/copy-selector.test.ts` (5 pass, 0 fail). Closes #4238
This commit is contained in:
@@ -53,6 +53,8 @@ function gutterCells(hasNext: boolean): string {
|
||||
export class CopySelectorComponent implements Component {
|
||||
#roots: CopyTarget[];
|
||||
#cursorId: string;
|
||||
#lastSourceTarget?: CopyTarget;
|
||||
#lastSource?: string;
|
||||
#treeRows = MIN_TREE_ROWS;
|
||||
// Reused across renders to wrap preview content to the pane width.
|
||||
#previewText = new Text("", 0, 0);
|
||||
@@ -65,7 +67,10 @@ export class CopySelectorComponent implements Component {
|
||||
this.#cursorId = roots[0]?.id ?? "";
|
||||
}
|
||||
|
||||
invalidate(): void {}
|
||||
invalidate(): void {
|
||||
this.#lastSourceTarget = undefined;
|
||||
this.#lastSource = undefined;
|
||||
}
|
||||
|
||||
#flatten(): FlatNode[] {
|
||||
const out: FlatNode[] = [];
|
||||
@@ -153,9 +158,16 @@ export class CopySelectorComponent implements Component {
|
||||
// Code/command previews are syntax-highlighted; everything else is shown
|
||||
// as plain text. Both are wrapped (not hard-truncated) to the pane width.
|
||||
const isCode = target.language !== undefined;
|
||||
const source = isCode
|
||||
? highlightCode(replaceTabs(target.preview), target.language).join("\n")
|
||||
: replaceTabs(target.preview);
|
||||
let source: string;
|
||||
if (target === this.#lastSourceTarget && this.#lastSource !== undefined) {
|
||||
source = this.#lastSource;
|
||||
} else {
|
||||
source = isCode
|
||||
? highlightCode(replaceTabs(target.preview), target.language).join("\n")
|
||||
: replaceTabs(target.preview);
|
||||
this.#lastSourceTarget = target;
|
||||
this.#lastSource = source;
|
||||
}
|
||||
this.#previewText.setText(source);
|
||||
const wrapped = this.#previewText.render(Math.max(1, width - 4));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user