feat(editor): 持久化SQL编辑器光标位置
Co-authored-by: zipg <4047349+zipg@users.noreply.github.com>
This commit is contained in:
1 parent
772ce36de8
commit
5fb667716f
7 files changed
+52
-2
No files matched your search
@@ -3573,6 +3573,7 @@ onUnmounted(() => {
|
||||
"
|
||||
@editor-viewport-change="(tabId: string, viewport: { scrollTop: number; scrollLeft: number }) => queryStore.updateEditorViewport(tabId, viewport)"
|
||||
@editor-selection-state-change="(tabId: string, selection: { anchor: number; head: number }) => queryStore.updateEditorSelection(tabId, selection)"
|
||||
@editor-state-flushed="(tabId: string) => void queryStore.flushEditorState(tabId)"
|
||||
@format-error="toast(t('toolbar.formatSqlFailed'))"
|
||||
@save-sql="(tabId: string) => void openSaveSqlDialog(tabId)"
|
||||
@reload="(tabId: string, sql: any, searchText: any, whereInput: any, orderBy: any, limit: any, offset: any, intent: any) => onReloadData(tabId, sql, searchText, whereInput, orderBy, limit, offset, intent)"
|
||||
|
||||
@@ -244,6 +244,7 @@ const emit = defineEmits<{
|
||||
closeColumnPanel: [];
|
||||
viewportChange: [viewport: { scrollTop: number; scrollLeft: number }];
|
||||
selectionStateChange: [selection: { anchor: number; head: number }];
|
||||
editorStateFlushed: [];
|
||||
sendSelectionToAi: [sql: string];
|
||||
}>();
|
||||
|
||||
@@ -6983,6 +6984,7 @@ function pauseQueryEditorBackgroundWork() {
|
||||
cancelBatchColumnSelectionRefresh();
|
||||
flushEditorViewport();
|
||||
flushEditorSelection();
|
||||
emit("editorStateFlushed");
|
||||
clearTableNavigationHover();
|
||||
clearPendingCompletionEnter();
|
||||
clearPendingCompletionTab();
|
||||
|
||||
@@ -1305,6 +1305,7 @@ defineExpose({
|
||||
@preview-changes-available="emit('previewChangesAvailable', activeTab.id, $event)"
|
||||
@viewport-change="emit('editorViewportChange', activeTab.id, $event)"
|
||||
@selection-state-change="emit('editorSelectionStateChange', activeTab.id, $event)"
|
||||
@editor-state-flushed="emit('editorStateFlushed', activeTab.id)"
|
||||
@format-error="emit('formatError', activeTab.id)"
|
||||
@execute="emit('execute', activeTab.id, $event)"
|
||||
@execute-in-new-result-tab="emit('executeInNewResultTab', activeTab.id, $event)"
|
||||
|
||||
@@ -75,6 +75,7 @@ export interface ContentAreaSurfaceEmits {
|
||||
editorCursorChange: [tabId: string, pos: number];
|
||||
editorViewportChange: [tabId: string, viewport: { scrollTop: number; scrollLeft: number }];
|
||||
editorSelectionStateChange: [tabId: string, selection: { anchor: number; head: number }];
|
||||
editorStateFlushed: [tabId: string];
|
||||
formatError: [tabId: string];
|
||||
reload: [tabId: string, sql?: string, searchText?: string, whereInput?: string, orderBy?: string, limit?: number, offset?: number, intent?: DataGridReloadIntent];
|
||||
paginate: [tabId: string, offset: number, limit: number, whereInput?: string, orderBy?: string];
|
||||
|
||||
@@ -25,6 +25,8 @@ export interface SavedOpenTab {
|
||||
catalog?: string;
|
||||
schema?: string;
|
||||
sql: string;
|
||||
editorViewport?: QueryTab["editorViewport"];
|
||||
editorSelection?: QueryTab["editorSelection"];
|
||||
originalSql?: string;
|
||||
savedSqlId?: string;
|
||||
externalSqlPath?: string;
|
||||
@@ -108,6 +110,24 @@ function restoredOriginalSql(tab: SavedOpenTab, mode: QueryTab["mode"], sql: str
|
||||
return "";
|
||||
}
|
||||
|
||||
function restoredEditorSelection(tab: SavedOpenTab, docLength: number): QueryTab["editorSelection"] {
|
||||
const selection = tab.editorSelection;
|
||||
if (!selection || !Number.isFinite(selection.anchor) || !Number.isFinite(selection.head)) return undefined;
|
||||
return {
|
||||
anchor: Math.min(Math.max(0, Math.trunc(selection.anchor)), docLength),
|
||||
head: Math.min(Math.max(0, Math.trunc(selection.head)), docLength),
|
||||
};
|
||||
}
|
||||
|
||||
function restoredEditorViewport(tab: SavedOpenTab): QueryTab["editorViewport"] {
|
||||
const viewport = tab.editorViewport;
|
||||
if (!viewport || !Number.isFinite(viewport.scrollTop) || !Number.isFinite(viewport.scrollLeft)) return undefined;
|
||||
return {
|
||||
scrollTop: Math.max(0, viewport.scrollTop),
|
||||
scrollLeft: Math.max(0, viewport.scrollLeft),
|
||||
};
|
||||
}
|
||||
|
||||
export function serializeOpenTabs(tabs: QueryTab[]): SavedOpenTab[] {
|
||||
return tabs.map((tab) => ({
|
||||
id: tab.id,
|
||||
@@ -119,6 +139,8 @@ export function serializeOpenTabs(tabs: QueryTab[]): SavedOpenTab[] {
|
||||
...(tab.catalog !== undefined ? { catalog: tab.catalog } : {}),
|
||||
schema: tab.schema,
|
||||
sql: shouldPersistTabSql(tab) ? tab.sql : "",
|
||||
...(tab.editorViewport ? { editorViewport: tab.editorViewport } : {}),
|
||||
...(tab.editorSelection ? { editorSelection: tab.editorSelection } : {}),
|
||||
// Plain query tabs always round-trip originalSql. External-file tabs only persist it
|
||||
// while dirty so their disk baseline survives restart without duplicating clean SQL.
|
||||
...(tab.originalSql !== undefined && !tab.savedSqlId && (!tab.externalSqlPath || tab.sql !== tab.originalSql) ? { originalSql: tab.originalSql } : {}),
|
||||
@@ -212,8 +234,8 @@ function restoreOpenTabsArray(parsed: unknown, rawActiveTabId: string | null, op
|
||||
isCancelling: false,
|
||||
queryExecutionStartedAt: undefined,
|
||||
executingResultRunId: undefined,
|
||||
editorViewport: undefined,
|
||||
editorSelection: undefined,
|
||||
editorViewport: restoredEditorViewport(tab),
|
||||
editorSelection: restoredEditorSelection(tab, typeof tab.sql === "string" ? tab.sql.length : 0),
|
||||
isExplaining: false,
|
||||
originalSql: restoredOriginalSql(tab, mode, typeof tab.sql === "string" ? tab.sql : ""),
|
||||
resultEvicted: mode === "data" ? undefined : tab.resultEvicted,
|
||||
|
||||
@@ -2228,6 +2228,8 @@ export const useQueryStore = defineStore("query", () => {
|
||||
database: t.database,
|
||||
schema: t.schema,
|
||||
sql: t.sql,
|
||||
editorViewport: t.editorViewport,
|
||||
editorSelection: t.editorSelection,
|
||||
savedSqlId: t.savedSqlId,
|
||||
externalSqlPath: t.externalSqlPath,
|
||||
externalSqlFileVersion: t.externalSqlFileVersion,
|
||||
@@ -3237,6 +3239,13 @@ export const useQueryStore = defineStore("query", () => {
|
||||
);
|
||||
}
|
||||
|
||||
function flushEditorState(id: string): Promise<void> {
|
||||
const tab = tabs.value.find((item) => item.id === id);
|
||||
if (!tab) return Promise.resolve();
|
||||
persistSavedSqlEditorPosition(tab);
|
||||
return flushPendingPersist();
|
||||
}
|
||||
|
||||
function queueSavedSqlEditorPositionPersist(tab: QueryTab | undefined) {
|
||||
if (!tab?.savedSqlId || tab.mode !== "query") return;
|
||||
const pending = savedSqlEditorPositionTimers.get(tab.savedSqlId);
|
||||
@@ -7780,6 +7789,7 @@ export const useQueryStore = defineStore("query", () => {
|
||||
updateDataGridHiddenColumnKeys,
|
||||
updateEditorViewport,
|
||||
updateEditorSelection,
|
||||
flushEditorState,
|
||||
updateObjectBrowserViewport,
|
||||
updateObjectBrowserSearch,
|
||||
updateNacosConfigEditorViewport,
|
||||
|
||||
Reference in new issue
Block a user