From c5cf80a7473334b07cf570ba5970f5b70ab802fb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Feb 2026 09:35:31 +0000 Subject: [PATCH 1/3] Initial plan From 8ff70b11652bcab099bee3b40b5249ff8e801f9e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Feb 2026 09:40:37 +0000 Subject: [PATCH 2/3] Fix RangeError from stale decoration positions in async updateWidgets Co-authored-by: mProjectsCode <61602848+mProjectsCode@users.noreply.github.com> --- src/codemirror/Cm6_ViewPlugin.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/codemirror/Cm6_ViewPlugin.ts b/src/codemirror/Cm6_ViewPlugin.ts index 783d0a7..80ce468 100644 --- a/src/codemirror/Cm6_ViewPlugin.ts +++ b/src/codemirror/Cm6_ViewPlugin.ts @@ -55,7 +55,13 @@ export function createCm6Plugin(plugin: ShikiPlugin) { * @param update */ update(update: ViewUpdate): void { - this.decorations = this.decorations.map(update.changes); + try { + this.decorations = this.decorations.map(update.changes); + } catch (e) { + // Decorations may have stale positions if the document changed while an async + // updateWidgets call was in flight. Reset them so the next update can rebuild. + this.decorations = Decoration.none; + } // we handle doc changes and selection changes here if (update.docChanged || update.selectionSet) { @@ -79,6 +85,9 @@ export function createCm6Plugin(plugin: ShikiPlugin) { let lang = ''; let state: SyntaxNode[] = []; const decorationUpdates: DecorationUpdate[] = []; + // Capture the state at the time of the syntax tree traversal so we can + // detect if the document changed while async decoration building was in flight. + const capturedState = view.state; // const t1 = performance.now(); @@ -172,6 +181,11 @@ export function createCm6Plugin(plugin: ShikiPlugin) { this.removeDecoration(node.from, node.to); } else if (node.type === DecorationUpdateType.Insert) { const decorations = await this.buildDecorations(node.hideTo ?? node.from, node.to, node.lang, node.content); + // If the document changed while we were awaiting, the positions we captured + // from the syntax tree are stale. Abort to avoid applying out-of-range decorations. + if (this.view.state !== capturedState) { + return; + } this.removeDecoration(node.from, node.to); if (node.hideLang) { // add the decoration that hides the language tag From c57d76ab95b96e71686d80e765bc01108681d9a9 Mon Sep 17 00:00:00 2001 From: Moritz Jung Date: Wed, 25 Feb 2026 10:55:01 +0100 Subject: [PATCH 3/3] add warning log --- src/codemirror/Cm6_ViewPlugin.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/codemirror/Cm6_ViewPlugin.ts b/src/codemirror/Cm6_ViewPlugin.ts index 80ce468..1441df3 100644 --- a/src/codemirror/Cm6_ViewPlugin.ts +++ b/src/codemirror/Cm6_ViewPlugin.ts @@ -61,6 +61,7 @@ export function createCm6Plugin(plugin: ShikiPlugin) { // Decorations may have stale positions if the document changed while an async // updateWidgets call was in flight. Reset them so the next update can rebuild. this.decorations = Decoration.none; + console.warn('Resetting decorations due to error:', e); } // we handle doc changes and selection changes here