From a6b066bff00282e59599a3aea2d070490f035cac Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Wed, 28 Oct 2026 09:57:03 +0800 Subject: [PATCH] fix(agents): Repaint find highlights as the search changes WebKit doesn't repaint where a replaced highlight object was, so matches of an earlier search stayed painted; each highlight is now one object changed in place. --- src/features/agents/SessionEditor.tsx | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/features/agents/SessionEditor.tsx b/src/features/agents/SessionEditor.tsx index 919a17a68..31f52f359 100644 --- a/src/features/agents/SessionEditor.tsx +++ b/src/features/agents/SessionEditor.tsx @@ -232,13 +232,26 @@ function selectionIn(stream: HTMLElement): string { return stream.contains(sel.getRangeAt(0).commonAncestorContainer) ? sel.toString() : ""; } -const highlights = (globalThis as { CSS?: { highlights?: Map } }).CSS?.highlights; -const HighlightCtor = (globalThis as { Highlight?: new (...ranges: Range[]) => unknown }).Highlight; +interface RangeSet { + clear(): void; + add(range: Range): void; +} +const highlights = (globalThis as { CSS?: { highlights?: Map } }).CSS?.highlights; +const HighlightCtor = (globalThis as { Highlight?: new () => RangeSet }).Highlight; +/** + * Sets the ranges of highlight `name`. One registered highlight per name, changed in + * place: WebKit doesn't repaint where a replaced highlight object was. + */ function setHighlight(name: string, ranges: Range[]) { if (!highlights || !HighlightCtor) return; - if (ranges.length) highlights.set(name, new HighlightCtor(...ranges)); - else highlights.delete(name); + let set = highlights.get(name); + if (!set) { + set = new HighlightCtor(); + highlights.set(name, set); + } + set.clear(); + for (const r of ranges) set.add(r); } /** Scrolls `range` into view in `stream`, opening the collapsed tool output or thought holding it. */