From 86d8a0e32f5b9f9a926dce9f6123b476c0697c37 Mon Sep 17 00:00:00 2001 From: devleejb Date: Tue, 30 Jan 2024 15:26:36 +0900 Subject: [PATCH 1/3] Change document local update logic --- frontend/src/utils/yorkie/yorkieSync.ts | 36 ++++++++++--------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/frontend/src/utils/yorkie/yorkieSync.ts b/frontend/src/utils/yorkie/yorkieSync.ts index 97e010eb..ca57f15c 100644 --- a/frontend/src/utils/yorkie/yorkieSync.ts +++ b/frontend/src/utils/yorkie/yorkieSync.ts @@ -75,30 +75,22 @@ class YorkieSyncPluginValue implements cmView.PluginValue { } update(update: cmView.ViewUpdate) { - if ( - !update.docChanged || - (update.transactions.length > 0 && - update.transactions[0].annotation(yorkieSyncAnnotation) === this.conf) - ) { - return; - } - - let adj = 0; - this._doc.update((root, presence) => { - update.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => { - if (!root.content) { - root.content = new yorkie.Text(); + if (update.docChanged) { + for (const tr of update.transactions) { + const events = ["select", "input", "delete", "move", "undo", "redo"]; + if (!events.map((event) => tr.isUserEvent(event)).some(Boolean)) { + continue; } - const insertText = insert.sliceString(0, insert.length, "\n"); - const updatedIndexRange = root.content.edit(fromA + adj, toA + adj, insertText); - adj += insertText.length - (toA - fromA); - if (updatedIndexRange) { - presence.set({ - selection: root.content.indexRangeToPosRange(updatedIndexRange), - } as unknown as YorkieCodeMirrorPresenceType); + if (tr.annotation(cmState.Transaction.remote)) { + continue; } - }); - }); + tr.changes.iterChanges((fromA, toA, _, __, inserted) => { + this._doc.update((root) => { + root.content.edit(fromA, toA, inserted.toJSON().join("\n")); + }); + }); + } + } } destroy() { From d5fe42616bd360b772c3ebd51eeedc8be5fe50d2 Mon Sep 17 00:00:00 2001 From: devleejb Date: Tue, 30 Jan 2024 15:51:55 +0900 Subject: [PATCH 2/3] Change yorkie updating logic --- frontend/src/utils/yorkie/yorkieSync.ts | 33 +++++++++++++++---------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/frontend/src/utils/yorkie/yorkieSync.ts b/frontend/src/utils/yorkie/yorkieSync.ts index ca57f15c..addb0bbe 100644 --- a/frontend/src/utils/yorkie/yorkieSync.ts +++ b/frontend/src/utils/yorkie/yorkieSync.ts @@ -41,14 +41,24 @@ class YorkieSyncPluginValue implements cmView.PluginValue { view: cmView.EditorView; conf: YorkieSyncConfig; _doc: yorkie.Document; - _observer: yorkie.NextFn>; - _unsubscribe: yorkie.Unsubscribe; constructor(view: cmView.EditorView) { this.view = view; this.conf = view.state.facet(yorkieSyncFacet); + this._doc = this.conf.doc; + + this._doc.subscribe((event) => { + if (event.type !== "snapshot") return; + + // The text is replaced to snapshot and must be re-synced. + const text = this._doc.getRoot().content; + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: text.toString() }, + annotations: [cmState.Transaction.remote.of(true)], + }); + }); - this._observer = (event) => { + this._doc.subscribe("$.content", (event) => { if (event.type !== "remote-change") return; const { operations } = event.value; @@ -65,37 +75,34 @@ class YorkieSyncPluginValue implements cmView.PluginValue { view.dispatch({ changes, - annotations: [yorkieSyncAnnotation.of(this.conf)], + annotations: [cmState.Transaction.remote.of(true)], }); } }); - }; - this._doc = this.conf.doc; - this._unsubscribe = this._doc.subscribe("$.content", this._observer); + }); } update(update: cmView.ViewUpdate) { if (update.docChanged) { for (const tr of update.transactions) { const events = ["select", "input", "delete", "move", "undo", "redo"]; - if (!events.map((event) => tr.isUserEvent(event)).some(Boolean)) { + if (!events.some((event) => tr.isUserEvent(event))) { continue; } if (tr.annotation(cmState.Transaction.remote)) { continue; } + let adj = 0; tr.changes.iterChanges((fromA, toA, _, __, inserted) => { + const insertText = inserted.toJSON().join("\n"); this._doc.update((root) => { - root.content.edit(fromA, toA, inserted.toJSON().join("\n")); + root.content.edit(fromA + adj, toA + adj, insertText); }); + adj += insertText.length - (toA - fromA); }); } } } - - destroy() { - this._unsubscribe(); - } } export const yorkieSync = cmView.ViewPlugin.fromClass(YorkieSyncPluginValue); From 31a70d6737f7bdb30085fb7524cd52d9921c0d09 Mon Sep 17 00:00:00 2001 From: devleejb Date: Tue, 30 Jan 2024 16:33:50 +0900 Subject: [PATCH 3/3] Add auto soft line break --- frontend/src/components/editor/Preview.tsx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/editor/Preview.tsx b/frontend/src/components/editor/Preview.tsx index 1003ab5b..fb3d8340 100644 --- a/frontend/src/components/editor/Preview.tsx +++ b/frontend/src/components/editor/Preview.tsx @@ -14,10 +14,21 @@ function Preview() { useEffect(() => { if (!editorStore.doc) return; - setContent(editorStore.doc?.getRoot().content?.toString() || ""); + const updatePreviewContent = () => { + const editorText = editorStore.doc?.getRoot().content?.toString() || ""; + // Add soft line break + setContent( + editorText + .split("\n") + .map((line) => line + " ") + .join("\n") + ); + }; + + updatePreviewContent(); const unsubsribe = editorStore.doc.subscribe("$.content", () => { - setContent(editorStore.doc?.getRoot().content.toString() as string); + updatePreviewContent(); }); return () => {