Skip to content

Commit

Permalink
Fix remote change handling
Browse files Browse the repository at this point in the history
  • Loading branch information
dmaretskyi committed Nov 13, 2023
1 parent d05da4f commit 572bf10
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 5 deletions.
4 changes: 2 additions & 2 deletions src/PatchSemaphore.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { next as automerge } from "@automerge/automerge"
import { next as automerge, equals } from "@automerge/automerge"
import { DocHandle } from "@automerge/automerge-repo"
import { EditorView } from "@codemirror/view"
import codeMirrorToAm from "./codeMirrorToAm"
Expand Down Expand Up @@ -70,7 +70,7 @@ export class PatchSemaphore {

// now get the diff between the updated state of the document and the heads
// and apply that to the codemirror doc
const diff = automerge.diff(handle.docSync(), oldHeads, newHeads)
const diff = automerge.equals(oldHeads, newHeads) ? [] : automerge.diff(handle.docSync(), oldHeads, newHeads)
amToCodemirror(view, selection, path, diff)

view.dispatch({
Expand Down
21 changes: 18 additions & 3 deletions src/amToCodemirror.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import {
InsertPatch,
Patch,
Prop,
PutPatch,
SpliceTextPatch,
} from "@automerge/automerge"
import { ChangeSet, ChangeSpec, EditorSelection } from "@codemirror/state"
import { ChangeSet, ChangeSpec, EditorSelection, EditorState } from "@codemirror/state"
import { EditorView } from "@codemirror/view"
import { reconcileAnnotationType } from "./plugin"

Expand All @@ -16,7 +17,7 @@ export default function (
patches: Patch[]
) {
for (const patch of patches) {
const changeSpec = handlePatch(patch, target)
const changeSpec = handlePatch(patch, target, view.state)
if (changeSpec != null) {
const changeSet = ChangeSet.of(changeSpec, view.state.doc.length, "\n")
selection = selection.map(changeSet, 1)
Expand All @@ -32,13 +33,15 @@ export default function (
})
}

function handlePatch(patch: Patch, target: Prop[]): ChangeSpec | null {
function handlePatch(patch: Patch, target: Prop[], state: EditorState): ChangeSpec | null {
if (patch.action === "insert") {
return handleInsert(target, patch)
} else if (patch.action === "splice") {
return handleSplice(target, patch)
} else if (patch.action === "del") {
return handleDel(target, patch)
} else if(patch.action === "put") {
return handlePut(target, patch, state)
} else {
return null
}
Expand Down Expand Up @@ -73,6 +76,18 @@ function handleDel(target: Prop[], patch: DelPatch): Array<ChangeSpec> {
return [{ from: index, to: index + length }]
}

function handlePut(target: Prop[], patch: PutPatch, state: EditorState): Array<ChangeSpec> {
const index = charPath(target, [...patch.path, 0]);
if (index == null) {
return [];
}
const length = state.doc.length;
if(typeof patch.value !== "string") {
return [] // TODO(dmaretskyi): How to handle non string values?
}
return [{ from: 0, to: length, insert: patch.value as any }];
}

// If the path of the patch is of the form [path, <index>] then we know this is
// a path to a character within the sequence given by path
function charPath(textPath: Prop[], candidatePath: Prop[]): number | null {
Expand Down
15 changes: 15 additions & 0 deletions src/codeMirrorToAm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@ export default function (
): Heads | undefined {
const { lastHeads, path } = state.field(field)

// We don't want to call `automerge.updateAt` if there are no changes.
// Otherwise later on `automerge.diff` will return empty patches that result in a no-op but still mess up the selection.
let hasChanges = false;
for (const tr of transactions) {
if (tr.changes.length) {
tr.changes.iterChanges(() => {
hasChanges = true;
});
}
}

if(!hasChanges) {
return undefined;
}

const newHeads = update(lastHeads, (doc: am.Doc<unknown>) => {
for (const tr of transactions) {
tr.changes.iterChanges(
Expand Down

0 comments on commit 572bf10

Please sign in to comment.