@dxos/react-ui-editor 0.4.2-main.022012d → 0.4.2-main.0e5b9e5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,15 +4,14 @@
4
4
  // Ref: https://github.com/automerge/automerge-codemirror
5
5
  //
6
6
 
7
- import { invertedEffects } from '@codemirror/commands';
8
- import { StateField, type Extension, type StateEffect } from '@codemirror/state';
7
+ import { StateField, type Extension } from '@codemirror/state';
9
8
  import { EditorView, ViewPlugin } from '@codemirror/view';
10
9
 
11
10
  import { next as A, type Prop } from '@dxos/automerge/automerge';
12
11
 
13
12
  import { cursorConverter } from './cursor';
14
13
  import { updateHeadsEffect, type IDocHandle, isReconcile, type State } from './defs';
15
- import { PatchSemaphore } from './semaphore';
14
+ import { Syncer } from './sync';
16
15
  import { Cursor } from '../cursor';
17
16
 
18
17
  export type AutomergeOptions = {
@@ -55,7 +54,7 @@ export const automerge = ({ handle, path }: AutomergeOptions): Extension => {
55
54
  },
56
55
  });
57
56
 
58
- const semaphore = new PatchSemaphore(handle, syncState);
57
+ const syncer = new Syncer(handle, syncState);
59
58
 
60
59
  return [
61
60
  Cursor.converter.of(cursorConverter(handle, path)),
@@ -73,7 +72,7 @@ export const automerge = ({ handle, path }: AutomergeOptions): Extension => {
73
72
  }
74
73
 
75
74
  _handleChange() {
76
- semaphore.reconcile(this._view);
75
+ syncer.reconcile(this._view, false);
77
76
  }
78
77
  },
79
78
  ),
@@ -81,23 +80,8 @@ export const automerge = ({ handle, path }: AutomergeOptions): Extension => {
81
80
  // Reconcile local updates.
82
81
  EditorView.updateListener.of(({ view, changes }) => {
83
82
  if (!changes.empty) {
84
- semaphore.reconcile(view);
83
+ syncer.reconcile(view, true);
85
84
  }
86
85
  }),
87
-
88
- // TODO(burdon): Record undo transactions.
89
- // See https://github.com/yjs/y-codemirror.next/tree/main
90
- // https://codemirror.net/examples/inverted-effect
91
- invertedEffects.of((tr) => {
92
- // Each change results it three transactions: insert, delete, insert.
93
- const effects: StateEffect<any>[] = [];
94
- if (!tr.changes.empty) {
95
- tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
96
- // effects.push(effectType.of({});
97
- });
98
- }
99
-
100
- return effects;
101
- }),
102
86
  ];
103
87
  };
@@ -12,11 +12,11 @@ import { next as A } from '@dxos/automerge/automerge';
12
12
  import {
13
13
  getLastHeads,
14
14
  getPath,
15
- isReconcile,
16
- reconcileAnnotation,
17
- updateHeads,
18
15
  type IDocHandle,
19
16
  type State,
17
+ reconcileAnnotation,
18
+ updateHeads,
19
+ isReconcile,
20
20
  } from './defs';
21
21
  import { updateAutomerge } from './update-automerge';
22
22
  import { updateCodeMirror } from './update-codemirror';
@@ -24,8 +24,8 @@ import { updateCodeMirror } from './update-codemirror';
24
24
  /**
25
25
  * Implements three-way merge (on each mutation).
26
26
  */
27
- export class PatchSemaphore {
28
- private _inReconcile = false;
27
+ export class Syncer {
28
+ private _pending = false;
29
29
 
30
30
  // prettier-ignore
31
31
  constructor(
@@ -33,46 +33,44 @@ export class PatchSemaphore {
33
33
  private readonly _state: StateField<State>
34
34
  ) {}
35
35
 
36
- reconcile(view: EditorView) {
37
- if (!this._inReconcile) {
38
- this._inReconcile = true;
39
- this.doReconcile(view);
40
- this._inReconcile = false;
36
+ reconcile(view: EditorView, editor: boolean) {
37
+ // TODO(burdon): Better way to do mutex?
38
+ if (this._pending) {
39
+ return;
41
40
  }
42
- }
43
-
44
- private doReconcile(view: EditorView) {
45
- const path = getPath(view.state, this._state);
46
41
 
47
- // Get the heads before the unreconciled transactions are applied.
48
- const oldHeads = getLastHeads(view.state, this._state);
49
- let selection = view.state.selection;
42
+ this._pending = true;
43
+ if (editor) {
44
+ this.onEditorChange(view);
45
+ } else {
46
+ this.onAutomergeChange(view);
47
+ }
48
+ this._pending = false;
49
+ }
50
50
 
51
- // First undo all the unreconciled transactions.
51
+ onEditorChange(view: EditorView) {
52
+ // Apply the unreconciled transactions to the document.
52
53
  const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
53
- const toInvert = transactions.slice().reverse();
54
- for (const tr of toInvert) {
55
- const inverted = tr.changes.invert(tr.startState.doc);
56
- selection = selection.map(inverted);
54
+ const newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
55
+
56
+ if (newHeads) {
57
57
  view.dispatch({
58
- changes: inverted,
59
- annotations: reconcileAnnotation.of(true),
58
+ effects: updateHeads(newHeads),
59
+ annotations: reconcileAnnotation.of(false),
60
60
  });
61
61
  }
62
+ }
62
63
 
63
- // Apply the unreconciled transactions to the document.
64
- // NOTE: null and undefined each come from automerge and repo respectively.
65
- let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
66
- if (newHeads === null || newHeads === undefined) {
67
- // TODO(alexjg): this is the call that's resetting the editor state on click.
68
- newHeads = A.getHeads(this._handle.docSync()!);
69
- }
70
-
71
- // Now get the diff between the updated state of the document and the heads and apply that to the codemirror doc.
64
+ onAutomergeChange(view: EditorView) {
65
+ // Get the diff between the updated state of the document and the heads and apply that to the codemirror doc.
66
+ const oldHeads = getLastHeads(view.state, this._state);
67
+ const newHeads = A.getHeads(this._handle.docSync()!);
72
68
  const diff = A.equals(oldHeads, newHeads) ? [] : A.diff(this._handle.docSync()!, oldHeads, newHeads);
69
+
70
+ const selection = view.state.selection;
71
+ const path = getPath(view.state, this._state);
73
72
  updateCodeMirror(view, selection, path, diff);
74
73
 
75
- // Update automerge state.
76
74
  view.dispatch({
77
75
  effects: updateHeads(newHeads),
78
76
  annotations: reconcileAnnotation.of(false),
@@ -1 +0,0 @@
1
- {"version":3,"file":"semaphore.d.ts","sourceRoot":"","sources":["../../../../../src/extensions/automerge/semaphore.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD,OAAO,EAML,KAAK,UAAU,EACf,KAAK,KAAK,EACX,MAAM,QAAQ,CAAC;AAIhB;;GAEG;AACH,qBAAa,cAAc;IAKvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IALzB,OAAO,CAAC,YAAY,CAAS;gBAIV,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC;IAG5C,SAAS,CAAC,IAAI,EAAE,UAAU;IAQ1B,OAAO,CAAC,WAAW;CAqCpB"}