From dda8db5fb20b66bbe30fa3895ca5ffd5ea55e555 Mon Sep 17 00:00:00 2001 From: purocean Date: Fri, 10 Jan 2025 18:54:49 +0800 Subject: [PATCH] feat(editor-restore-state): enhance view state management with debounced saving and reactive storage --- src/renderer/plugins/editor-restore-state.ts | 61 +++++++++++++++----- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/src/renderer/plugins/editor-restore-state.ts b/src/renderer/plugins/editor-restore-state.ts index 65d89369..ba1982d8 100644 --- a/src/renderer/plugins/editor-restore-state.ts +++ b/src/renderer/plugins/editor-restore-state.ts @@ -1,35 +1,64 @@ import type { Plugin } from '@fe/context' import { registerHook } from '@fe/core/hook' - -const viewStateCache = new Map() +import type { editor } from 'monaco-editor' export default { name: 'editor-restore-state', register: (ctx) => { const logger = ctx.utils.getLogger('plugin:editor-restore-state') + const storageKey = 'plugin.editor-state' + + const viewStateCache = ctx.lib.vue.shallowReactive>(ctx.storage.get(storageKey, {})) + + ctx.lib.vue.watch(viewStateCache, () => { + // keep recent 10 view states + const entries = Object.entries(viewStateCache) + .sort((a, b) => b[1]._t - a[1]._t) + .slice(0, 10) + + ctx.storage.set(storageKey, Object.fromEntries(entries)) + }) + + function saveState (uri: editor.ITextModel['uri'] | null | undefined, viewState: editor.ICodeEditorViewState | null) { + if (!uri) return + + const uriStr = uri.toString() + logger.debug('save view state', uriStr) + viewStateCache[uriStr] = { + _t: Date.now(), + v: viewState + } + } + + const saveStateDebounced = ctx.lib.lodash.debounce(saveState, 500) registerHook('DOC_BEFORE_SWITCH', () => { ctx.editor.whenEditorReady().then(({ editor }) => { - const currentDoc = ctx.store.state.currentFile - const uri = ctx.doc.toUri(currentDoc) + const uri = editor.getModel()?.uri + if (!uri) return const viewState = editor.saveViewState() - - logger.debug('save view state', uri) - viewStateCache.set(uri, viewState) + saveState(uri, viewState) }) }) ctx.editor.whenEditorReady().then(({ editor }) => { - editor.onDidChangeModel(() => { - // restore view state - const currentDoc = ctx.store.state.currentFile - const uri = ctx.doc.toUri(currentDoc) - const viewState = viewStateCache.get(ctx.doc.toUri(currentDoc)) - if (viewState) { + editor.onDidChangeModel((e) => { + const uri = e.newModelUrl?.toString() + if (!uri) return + const viewState = viewStateCache[uri] + if (viewState && viewState.v) { logger.debug('restore view state', uri) - editor.restoreViewState(viewState) + editor.restoreViewState(viewState.v) } }) + + editor.onDidChangeCursorPosition(() => { + saveStateDebounced(editor.getModel()?.uri, editor.saveViewState()) + }) + + editor.onDidScrollChange(() => { + saveStateDebounced(editor.getModel()?.uri, editor.saveViewState()) + }) }) ctx.lib.vue.watch(() => ctx.store.state.tabs, () => { @@ -37,10 +66,10 @@ export default { const uris = ctx.store.state.tabs.map(x => x.key) // clean view state - for (const uri of viewStateCache.keys()) { + for (const uri of Object.keys(viewStateCache)) { if (!uris.includes(uri)) { logger.debug('dispose view state', uri) - viewStateCache.delete(uri) + delete viewStateCache[uri] } }