perf(editor): cache executable statement ranges for large SQL scrolling

Co-authored-by: staff <staff@qimaos-MacBook-Pro.local>
This commit is contained in:
zipgandstaff authored and GitHub committed 2026-06-30 18:05:37 +08:00
1 parent 8162a420e3
commit ccb91784b3
3 files changed
+79 -15

No files matched your search

@@ -10,7 +10,8 @@ import SqlExecutionTargetPicker from "./SqlExecutionTargetPicker.vue";
import CustomContextMenu, { type ContextMenuItem } from "@/components/ui/CustomContextMenu.vue";
import { copyToClipboard } from "@/lib/clipboard";
import { resolveExecutableSql, type SqlExecutionSnapshot, type SqlExecutionOverride, type SqlExecutionCandidate } from "@/lib/sqlExecutionTarget";
import { buildExecutionCandidates, executableStatementRanges, hasMultipleExecutionTargets, supportsExecutionTargetPicker, type SqlTextRange } from "@/lib/sqlStatementRanges";
import { buildExecutionCandidates, hasMultipleExecutionTargets, supportsExecutionTargetPicker, type SqlTextRange } from "@/lib/sqlStatementRanges";
import { executableStatementRangeCacheForDoc, executableStatementRangeStartingAt as executableStatementRangeStartingAtLine, type ExecutableStatementRangeCache } from "@/lib/executableStatementRangeCache";
import { formatSqlText, type SqlFormatDialect } from "@/lib/sqlFormatter";
import { formatMongoShellText } from "@/lib/mongoFormatter";
import { useConnectionStore } from "@/stores/connectionStore";
@@ -213,6 +214,7 @@ let editorIsActive = true;
let tableReferenceDropListenerRegistered = false;
let imeCompositionActive = false;
let pendingImeModelEmit = false;
let executableStatementRangeCache: ExecutableStatementRangeCache | null = null;
const tableNavigationHoverClass = "query-editor--table-navigation-hover";
function editorThemeAppearance() {
@@ -512,7 +514,8 @@ function openTableDdlFromContextMenu() {
}
function executableStatementRangeStartingAt(currentView: EditorViewType, lineFrom: number) {
return executableStatementRanges(currentView.state.doc.toString(), props.databaseType).find((range) => range.from === lineFrom) ?? null;
executableStatementRangeCache = executableStatementRangeCacheForDoc(executableStatementRangeCache, currentView.state.doc, props.databaseType);
return executableStatementRangeStartingAtLine(executableStatementRangeCache, lineFrom);
}
function executeSqlStatementFromGutter(currentView: EditorViewType, line: { from: number; to: number }, event: Event): boolean {
@@ -2050,25 +2053,18 @@ onMounted(async () => {
const theme = await loadEditorTheme(initialSettings.theme, editorThemeAppearance(), getCurrentCustomThemeColors());
class RunStatementGutterMarker extends GutterMarker {
constructor(private readonly isExecutable: boolean) {
super();
}
toDOM() {
const marker = document.createElement(this.isExecutable ? "button" : "span");
marker.className = this.isExecutable ? "cm-run-statement-marker cm-run-statement-marker--active" : "cm-run-statement-marker";
if (this.isExecutable) {
marker.setAttribute("type", "button");
marker.setAttribute("aria-label", "Execute statement");
}
const marker = document.createElement("button");
marker.className = "cm-run-statement-marker cm-run-statement-marker--active";
marker.setAttribute("type", "button");
marker.setAttribute("aria-label", "Execute statement");
marker.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z"></path></svg>';
return marker;
}
}
const executableStatementMarker = new RunStatementGutterMarker(true);
const inactiveStatementMarker = new RunStatementGutterMarker(false);
const executableStatementMarker = new RunStatementGutterMarker();
const activeLineHighlighter = ViewPlugin.fromClass(
class {
@@ -2112,7 +2108,7 @@ onMounted(async () => {
gutter({
class: "cm-run-statement-gutter",
lineMarker(currentView, line) {
return executableStatementRangeStartingAt(currentView, line.from) ? executableStatementMarker : inactiveStatementMarker;
return executableStatementRangeStartingAt(currentView, line.from) ? executableStatementMarker : null;
},
domEventHandlers: {
mousedown: executeSqlStatementFromGutter,