From 8cc924270cb1c87a49cdf42689af455a08cb7aee Mon Sep 17 00:00:00 2001 From: zipg Date: Mon, 24 Aug 2026 13:30:50 +0800 Subject: [PATCH] fix(editor): preserve user-adjusted SQL editor position during execution --- .../src/components/editor/QueryEditor.vue | 25 ++++++--- .../src/components/layout/ContentArea.vue | 3 + .../editor/queryEditorExecution.spec.ts | 56 +++++++++++++++++-- .../editor/queryEditorExecutionViewport.ts | 19 ++++++- 4 files changed, 86 insertions(+), 17 deletions(-) diff --git a/apps/desktop/src/components/editor/QueryEditor.vue b/apps/desktop/src/components/editor/QueryEditor.vue index a875213805..4754fdac42 100644 --- a/apps/desktop/src/components/editor/QueryEditor.vue +++ b/apps/desktop/src/components/editor/QueryEditor.vue @@ -226,7 +226,7 @@ let viewportEmitFrame: number | null = null; let viewportRestoreFrame: number | null = null; let latestViewport: { scrollTop: number; scrollLeft: number } | undefined = props.initialViewport; let lastEmittedViewport: { scrollTop: number; scrollLeft: number } | undefined = props.initialViewport; -const gutterExecutionViewport = createQueryEditorExecutionViewportOwnership(); +const executionViewportOwnership = createQueryEditorExecutionViewportOwnership(); let latestSelection: { anchor: number; head: number } | undefined = props.initialSelection; const connectionStore = useConnectionStore(); const settingsStore = useSettingsStore(); @@ -830,7 +830,7 @@ interface RequestExecuteOptions { function emitExecutionRequest(source: SqlExecutionOverride, openInNewResultTab = false) { if (typeof source === "string" || source.editorViewportRequestId === undefined) { - gutterExecutionViewport.cancelPendingRequest(); + executionViewportOwnership.cancelPendingRequest(); } if (openInNewResultTab) { emit("executeInNewResultTab", source); @@ -840,7 +840,7 @@ function emitExecutionRequest(source: SqlExecutionOverride, openInNewResultTab = } function requestExecute(options: RequestExecuteOptions = {}) { - gutterExecutionViewport.cancelPendingRequest(); + executionViewportOwnership.cancelPendingRequest(); const currentView = view.value; if (!currentView) return false; currentView.focus(); @@ -1689,7 +1689,7 @@ function executeSqlStatementFromGutter(currentView: EditorViewType, line: { from event.stopPropagation(); // Gutter play is always scoped to the statement/command for that line, even // when the main editor execute action would run the full document. - const editorViewportRequestId = gutterExecutionViewport.beginRequest(); + const editorViewportRequestId = executionViewportOwnership.beginRequest(); emitExecutionRequest({ ...sqlExecutionSnapshotForRange(currentView, statementRange), editorViewportRequestId }); // 不主动聚焦编辑器,否则 CodeMirror 会把屏幕滚回之前的光标位置。 // currentView.focus(); @@ -5847,7 +5847,7 @@ function pauseQueryEditorBackgroundWork() { flushEditorSelection(); clearTableNavigationHover(); clearPendingCompletionTab(); - gutterExecutionViewport.reset(); + executionViewportOwnership.reset(); editorIsActive = false; clearScheduledSemanticDiagnostics(); completionEpoch++; @@ -6006,7 +6006,7 @@ function openReplace(): boolean { } function scrollCursorIntoView() { - const preserveViewport = gutterExecutionViewport.consumeAcceptedRequest(); + const preserveViewport = executionViewportOwnership.consumeCompletionPreservation(); if (!view.value || !editorViewModule || !editorIsActive || preserveViewport) return; const pos = view.value.state.selection.main.head; // Use "center" rather than "nearest": by the time this runs, the results pane has already @@ -6020,19 +6020,28 @@ function scrollCursorIntoView() { }); } +function beginExecutionViewportTracking() { + executionViewportOwnership.beginExecution(); +} + +function recordExecutionViewportInteraction() { + executionViewportOwnership.recordUserInteraction(); +} + function dismissHoverTooltip() { if (!view.value || !hoverCloseEffect) return; view.value.dispatch({ effects: hoverCloseEffect }); } function acceptGutterExecutionViewport(requestId: number) { - return gutterExecutionViewport.acceptRequest(requestId); + return executionViewportOwnership.acceptRequest(requestId); } defineExpose({ openSearch, openReplace, scrollCursorIntoView, + beginExecutionViewportTracking, acceptGutterExecutionViewport, requestExecute, requestExecuteInNewResultTab, @@ -6044,7 +6053,7 @@ defineExpose({