diff --git a/src/editors/automerge/automergeDocumentEditor.tsx b/src/editors/automerge/automergeDocumentEditor.tsx index 6a1a35c..b7d3fec 100644 --- a/src/editors/automerge/automergeDocumentEditor.tsx +++ b/src/editors/automerge/automergeDocumentEditor.tsx @@ -31,16 +31,16 @@ export function AutomergeDocumentEditor({ const readOnlyCompartment = useRef(new Compartment()); - // Echo suppression: when a local write is in flight, skip dispatching - // the resulting change back into the editor. - const isInFlightRef = useRef(false); - // Current content as a string, used for diff computation. const contentRef = useRef(''); // Debounce timer for the save-based writer. const saveTimerRef = useRef | null>(null); + // Lock: set while we are writing to the doc so the sync useEffect + // can skip the round-trip back into the editor. + const isWriting = useRef(false); + // Version counter — bumped when the session notifies us of a doc change. const [docVersion, setDocVersion] = useState(0); @@ -57,16 +57,22 @@ export function AutomergeDocumentEditor({ // When the session loads/updates the doc, push the new content into CM6. useEffect(() => { const newContent = doc.content ?? ''; - contentRef.current = newContent; const view = viewRef.current; if (!view) return; + if (isWriting.current) { + isWriting.current = false; + contentRef.current = newContent; + return; + } + const currentText = view.state.doc.toString(); if (currentText !== newContent) { view.dispatch({ changes: { from: 0, to: currentText.length, insert: newContent }, }); } + contentRef.current = newContent; }, [docVersion, doc.content]); // Create EditorView on mount. @@ -85,14 +91,10 @@ export function AutomergeDocumentEditor({ if (saveTimerRef.current) clearTimeout(saveTimerRef.current); saveTimerRef.current = setTimeout(() => { saveTimerRef.current = null; - isInFlightRef.current = true; - try { - applyChangeRef.current((d) => { - d.content = newContent; - }); - } finally { - isInFlightRef.current = false; - } + isWriting.current = true; + applyChangeRef.current((d) => { + d.content = newContent; + }); }, 50); } }); @@ -142,14 +144,9 @@ export function AutomergeDocumentEditor({ clearTimeout(saveTimerRef.current); saveTimerRef.current = null; const finalContent = view.state.doc.toString(); - isInFlightRef.current = true; - try { - applyChangeRef.current((d) => { - d.content = finalContent; - }); - } finally { - isInFlightRef.current = false; - } + applyChangeRef.current((d) => { + d.content = finalContent; + }); } view.destroy(); viewRef.current = null;