diff --git a/apps/desktop/src/components/editor/QueryEditor.vue b/apps/desktop/src/components/editor/QueryEditor.vue index 666e5ae392..8163a8bf34 100644 --- a/apps/desktop/src/components/editor/QueryEditor.vue +++ b/apps/desktop/src/components/editor/QueryEditor.vue @@ -6202,7 +6202,16 @@ onMounted(async () => { if (pendingWindows.length > 0) { const requestedTo = Math.max(...pendingWindows.map((window) => window.to)); const tree = ensureSyntaxTree(currentView.state, requestedTo, requestedTo === sql.length ? 250 : 25); - if (!tree) return this.decorations; + if (!tree) { + // The Lezer parse has not reached the pending windows yet (long + // documents). Keep the decorations that are still valid and let + // the deferred refresh rebuild them once parsing catches up — + // returning an empty set here wiped table-name colors after + // scrolling stopped or when a freshly mounted editor (tab + // switch) had no later viewport change to trigger a rebuild. + this.scheduleRefresh(currentView); + return this.decorations; + } if (shouldPrewarmFullDocument) this.prewarmedDoc = doc; for (const window of pendingWindows) { const entry = { diff --git a/apps/desktop/src/lib/__tests__/editor/queryEditorSemanticHighlightPerformance.spec.ts b/apps/desktop/src/lib/__tests__/editor/queryEditorSemanticHighlightPerformance.spec.ts index 17568c329b..523fc1417c 100644 --- a/apps/desktop/src/lib/__tests__/editor/queryEditorSemanticHighlightPerformance.spec.ts +++ b/apps/desktop/src/lib/__tests__/editor/queryEditorSemanticHighlightPerformance.spec.ts @@ -36,6 +36,14 @@ describe("QueryEditor semantic highlighting while scrolling", () => { expect(queryEditorSource).toContain("if (shouldPrewarmFullDocument) this.prewarmedDoc = doc;"); }); + it("keeps existing highlights while the parser catches up instead of wiping them", () => { + // An incomplete Lezer parse must not clear table-name decorations: the + // deferred refresh retries, so a freshly mounted editor (tab switch) also + // recovers even without a later viewport change. + expect(queryEditorSource).toContain("this.scheduleRefresh(currentView);"); + expect(queryEditorSource).toContain("return this.decorations;"); + }); + it("keeps preview and diagnostics on the shared statement-range cache", () => { expect(queryEditorSource).toContain("executableStatementRangeCache = executableStatementRangeCacheForDoc"); expect(queryEditorSource).toContain('props.databaseType === "sqlserver" ? undefined : executableStatementRangeCache?.ranges');