Browse Source

feat: playground fold status persist (#819)

Shuyoou 4 months ago
parent
commit
1248bbe945

+ 1 - 0
client/src/consts/Localstorage.ts

@@ -16,3 +16,4 @@ export const ATTU_UI_TREE_WIDTH = 'attu.ui.tree.with';
 export const ATTU_AUTH_HISTORY = 'attu.auth.history';
 export const ATTU_THEME_MODE = 'attu.theme.mode';
 export const ATTU_PLAY_CODE = 'attu.play.code';
+export const ATTU_PLAY_FOLD_STATE = 'attu.play.fold.state';

+ 5 - 5
client/src/pages/play/Constants.ts

@@ -73,9 +73,9 @@ POST /v2/vectordb/entities/search
 `;
 
 export const DEFAULT_FOLD_LINE_RANGES = [
-  { lineFrom: 5, LineTo: 26 },
-  { lineFrom: 30, LineTo: 40 },
-  { lineFrom: 44, LineTo: 46 },
-  { lineFrom: 50, LineTo: 62 },
-  { lineFrom: 66, LineTo: 72 },
+  { lineFrom: 5, lineTo: 26 },
+  { lineFrom: 30, lineTo: 40 },
+  { lineFrom: 44, lineTo: 46 },
+  { lineFrom: 50, lineTo: 62 },
+  { lineFrom: 66, lineTo: 72 },
 ];

+ 8 - 1
client/src/pages/play/hooks/use-codemirror.ts

@@ -45,6 +45,9 @@ import {
 import {
   customFoldGutter,
   foldByLineRanges,
+  persistFoldState,
+  loadFoldState,
+  recoveryFoldState,
 } from '../language/extensions/fold';
 
 const basicSetup = () => [
@@ -75,6 +78,7 @@ const basicSetup = () => [
     ...lintKeymap,
   ]),
   customFoldGutter(),
+  persistFoldState(),
 ];
 
 const External = Annotation.define<boolean>();
@@ -115,7 +119,10 @@ export const useCodeMirror = (props: UseCodeMirrorProps) => {
         parent: container,
       });
 
-      if (value === DEFAULT_CODE_VALUE) {
+      const foldState = loadFoldState();
+      if (foldState) {
+        recoveryFoldState(editorView);
+      } else if (value === DEFAULT_CODE_VALUE) {
         foldByLineRanges(editorView, DEFAULT_FOLD_LINE_RANGES);
       }
       setView(editorView);

+ 58 - 5
client/src/pages/play/language/extensions/fold.ts

@@ -1,17 +1,24 @@
-import { foldEffect, foldService, syntaxTree } from '@codemirror/language';
-import { EditorState, StateEffect } from '@codemirror/state';
+import {
+  foldEffect,
+  unfoldEffect,
+  foldService,
+  syntaxTree,
+  foldState,
+} from '@codemirror/language';
+import { EditorState } from '@codemirror/state';
 import { EditorView } from '@codemirror/view';
+import { ATTU_PLAY_FOLD_STATE } from '@/consts';
 
 export const foldByLineRanges = (
   view: EditorView,
-  lineRanges: Array<{ lineFrom: number; LineTo: number }>
+  lineRanges: Array<{ lineFrom: number; lineTo: number }>
 ) => {
   const effects = [];
   const { state } = view;
 
-  for (const { lineFrom, LineTo } of lineRanges) {
+  for (const { lineFrom, lineTo } of lineRanges) {
     const lineStart = state.doc.line(lineFrom).from + 1;
-    const lineEnd = state.doc.line(LineTo).to - 1;
+    const lineEnd = state.doc.line(lineTo).to - 1;
     effects.push(foldEffect.of({ from: lineStart, to: lineEnd }));
   }
 
@@ -40,3 +47,49 @@ export const customFoldGutter = () => {
     }
   );
 };
+
+export const persistFoldState = () => {
+  return EditorView.updateListener.of(update => {
+    for (const tr of update.transactions) {
+      for (const effect of tr.effects) {
+        if (effect.is(foldEffect) || effect.is(unfoldEffect)) {
+          const view = update.view;
+          const folded = view.state.field(foldState);
+          const lineRanges: Array<{ from: number; to: number }> = [];
+          folded.between(0, view.state.doc.length, (from, to) => {
+            lineRanges.push({ from, to });
+          });
+          localStorage.setItem(
+            ATTU_PLAY_FOLD_STATE,
+            JSON.stringify(lineRanges)
+          );
+        }
+      }
+    }
+  });
+};
+
+export const loadFoldState = () => {
+  try {
+    const lineRanges = localStorage.getItem(ATTU_PLAY_FOLD_STATE);
+    if (lineRanges) {
+      return JSON.parse(lineRanges) as Array<{ from: number; to: number }>;
+    }
+    return null;
+  } catch (err) {
+    console.error(err);
+  }
+};
+
+export const recoveryFoldState = (view: EditorView) => {
+  const foldState = loadFoldState();
+  if (foldState) {
+    try {
+      view.dispatch({
+        effects: foldState.map(item => foldEffect.of(item)),
+      });
+    } catch (err) {
+      console.error(err);
+    }
+  }
+};