mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-17 14:29:46 +02:00
Revert to preserving editor state with fromJson due to state callbacks not being preserved
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { defaultKeymap } from '@codemirror/commands';
|
||||
import { forceParsing } from '@codemirror/language';
|
||||
import { Compartment, EditorState, type Extension } from '@codemirror/state';
|
||||
import { defaultKeymap, historyField } from '@codemirror/commands';
|
||||
import { foldState, forceParsing } from '@codemirror/language';
|
||||
import type { EditorStateConfig, Extension } from '@codemirror/state';
|
||||
import { Compartment, EditorState } from '@codemirror/state';
|
||||
import { keymap, placeholder as placeholderExt, tooltips } from '@codemirror/view';
|
||||
import type { EnvironmentVariable } from '@yaakapp-internal/models';
|
||||
import type { TemplateFunction } from '@yaakapp-internal/plugin';
|
||||
@@ -74,6 +75,8 @@ export interface EditorProps {
|
||||
stateKey: string | null;
|
||||
}
|
||||
|
||||
const stateFields = { history: historyField, folds: foldState };
|
||||
|
||||
const emptyVariables: EnvironmentVariable[] = [];
|
||||
|
||||
export const Editor = forwardRef<EditorView | undefined, EditorProps>(function Editor(
|
||||
@@ -305,40 +308,42 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
|
||||
onClickPathParameter,
|
||||
});
|
||||
|
||||
const extensions = [
|
||||
languageCompartment.of(langExt),
|
||||
placeholderCompartment.current.of(
|
||||
placeholderExt(placeholderElFromText(placeholder ?? '')),
|
||||
),
|
||||
wrapLinesCompartment.current.of(wrapLines ? [EditorView.lineWrapping] : []),
|
||||
...getExtensions({
|
||||
container,
|
||||
readOnly,
|
||||
singleLine,
|
||||
hideGutter,
|
||||
stateKey,
|
||||
onChange: handleChange,
|
||||
onPaste: handlePaste,
|
||||
onPasteOverwrite: handlePasteOverwrite,
|
||||
onFocus: handleFocus,
|
||||
onBlur: handleBlur,
|
||||
onKeyDown: handleKeyDown,
|
||||
}),
|
||||
...(extraExtensions ?? []),
|
||||
];
|
||||
|
||||
const cachedJsonState = getCachedEditorState(defaultValue ?? '', stateKey);
|
||||
|
||||
const state =
|
||||
cachedJsonState ??
|
||||
EditorState.create({
|
||||
doc: `${defaultValue ?? ''}`,
|
||||
extensions: [
|
||||
languageCompartment.of(langExt),
|
||||
placeholderCompartment.current.of(
|
||||
placeholderExt(placeholderElFromText(placeholder ?? '')),
|
||||
),
|
||||
wrapLinesCompartment.current.of(wrapLines ? [EditorView.lineWrapping] : []),
|
||||
...getExtensions({
|
||||
container,
|
||||
readOnly,
|
||||
singleLine,
|
||||
hideGutter,
|
||||
stateKey,
|
||||
onChange: handleChange,
|
||||
onPaste: handlePaste,
|
||||
onPasteOverwrite: handlePasteOverwrite,
|
||||
onFocus: handleFocus,
|
||||
onBlur: handleBlur,
|
||||
onKeyDown: handleKeyDown,
|
||||
}),
|
||||
...(extraExtensions ?? []),
|
||||
],
|
||||
});
|
||||
const doc = `${defaultValue ?? ''}`;
|
||||
const config: EditorStateConfig = { extensions, doc };
|
||||
|
||||
const state = cachedJsonState
|
||||
? EditorState.fromJSON(cachedJsonState, config, stateFields)
|
||||
: EditorState.create(config);
|
||||
|
||||
const view = new EditorView({ state, parent: container });
|
||||
|
||||
// For large documents, the parser may parse the max number of lines and fail to add
|
||||
// things like fold markers because of it.
|
||||
// This forces it to parse more but keeps the timeout to the default of 100ms.
|
||||
// This forces it to parse more but keeps the timeout to the default of 100 ms.
|
||||
forceParsing(view, 9e6, 100);
|
||||
|
||||
cm.current = { view, languageCompartment };
|
||||
@@ -544,24 +549,25 @@ const placeholderElFromText = (text: string) => {
|
||||
return el;
|
||||
};
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
editorStates: Record<string, EditorState>;
|
||||
}
|
||||
}
|
||||
window.editorStates = window.editorStates ?? {};
|
||||
|
||||
function saveCachedEditorState(stateKey: string | null, state: EditorState | null) {
|
||||
if (!stateKey || state == null) return;
|
||||
window.editorStates[stateKey] = state;
|
||||
sessionStorage.setItem(stateKey, JSON.stringify(state.toJSON(stateFields)));
|
||||
}
|
||||
|
||||
function getCachedEditorState(doc: string, stateKey: string | null) {
|
||||
if (stateKey == null) return;
|
||||
|
||||
const state = window.editorStates[stateKey] ?? null;
|
||||
if (state == null) return null;
|
||||
if (state.doc.toString() !== doc) return null;
|
||||
const stateStr = sessionStorage.getItem(stateKey)
|
||||
if (stateStr == null) return null;
|
||||
|
||||
return state;
|
||||
try {
|
||||
const state = JSON.parse(stateStr);
|
||||
if (state.doc !== doc) return null;
|
||||
|
||||
return state;
|
||||
} catch {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import {
|
||||
} from '@codemirror/autocomplete';
|
||||
import { history, historyKeymap, indentWithTab } from '@codemirror/commands';
|
||||
import { javascript } from '@codemirror/lang-javascript';
|
||||
import { markdown } from '@codemirror/lang-markdown';
|
||||
import { json } from '@codemirror/lang-json';
|
||||
import { markdown } from '@codemirror/lang-markdown';
|
||||
import { xml } from '@codemirror/lang-xml';
|
||||
import type { LanguageSupport } from '@codemirror/language';
|
||||
import {
|
||||
@@ -37,7 +37,8 @@ import type { EnvironmentVariable } from '@yaakapp-internal/models';
|
||||
import type { TemplateFunction } from '@yaakapp-internal/plugin';
|
||||
import { graphql } from 'cm6-graphql';
|
||||
import { EditorView } from 'codemirror';
|
||||
import type {EditorProps} from "./Editor";
|
||||
import { pluralizeCount } from '../../../lib/pluralize';
|
||||
import type { EditorProps } from './Editor';
|
||||
import { pairs } from './pairs/extension';
|
||||
import { text } from './text/extension';
|
||||
import { twig } from './twig/extension';
|
||||
@@ -162,11 +163,15 @@ export const multiLineExtensions = ({ hideGutter }: { hideGutter?: boolean }) =>
|
||||
const el = document.createElement('span');
|
||||
el.onclick = onclick;
|
||||
el.className = 'cm-foldPlaceholder';
|
||||
el.innerText = prepared;
|
||||
el.innerText = prepared || '…';
|
||||
el.title = 'unfold';
|
||||
el.ariaLabel = 'folded code';
|
||||
return el;
|
||||
},
|
||||
/**
|
||||
* Show the number of items when code folded. NOTE: this doesn't get called when restoring
|
||||
* a previous serialized editor state, which is a bummer
|
||||
*/
|
||||
preparePlaceholder(state, range) {
|
||||
let count: number | undefined;
|
||||
let startToken = '{';
|
||||
@@ -191,13 +196,9 @@ export const multiLineExtensions = ({ hideGutter }: { hideGutter?: boolean }) =>
|
||||
}
|
||||
|
||||
if (count !== undefined) {
|
||||
const label = isArray ? 'item' : 'prop';
|
||||
const plural = count === 1 ? '' : 's';
|
||||
|
||||
return `${count} ${label}${plural}`;
|
||||
const label = isArray ? 'item' : 'key';
|
||||
return pluralizeCount(label, count);
|
||||
}
|
||||
|
||||
return '…';
|
||||
},
|
||||
}),
|
||||
EditorState.allowMultipleSelections.of(true),
|
||||
|
||||
Reference in New Issue
Block a user