Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alternative implementation of cursors #313

Open
wants to merge 6 commits into
base: performance
Choose a base branch
from
Open

Alternative implementation of cursors #313

wants to merge 6 commits into from

Conversation

ept
Copy link
Member

@ept ept commented Feb 3, 2021

This PR provides an implementation of cursors, which allow a particular element of a list, or a particular character in an Automerge.Text object, to be referenced from elsewhere in the same document. The API involves a new Automerge.Cursor class, and it can be used like this for lists:

let doc = Automerge.change(Automerge.init(), doc => {
  doc.list = [1, 2, 3]
  doc.cursor = new Automerge.Cursor(doc.list, 2)
})
doc.cursor.index // returns 2

and like this for Text:

let doc = Automerge.change(Automerge.init(), doc => {
  doc.text = new Automerge.Text(['a', 'b', 'c'])
  doc.cursor = doc.text.getCursorAt(2)
})
doc.cursor.index // returns 2

The key thing about a cursor is that its index automatically updates when the list/text it references is changed. In the examples above, the index updates to 3 if you insert a new element before the cursor position, and it updates to 1 if you delete an element before the cursor position. If you delete the element that the cursor points to, the index is set to the index of the closest preceding element that has not been deleted (or -1 if there is no such element that has not been deleted).

The implementation of cursors on #307 requires a direct call from the frontend into the backend, which is inconvenient when frontend and backend are on different threads. This PR is an alternative implementation that is integrated with the existing frontend-backend protocol, making it compatible with multiple threads. This PR also includes a way for cursors to be efficiently represented in the binary storage format for changes and documents. A downside of this approach compared to #307 is that this PR requires cursors to be stored within the same Automerge document; it is not possible to store them somewhere out-of-band, or in a separate document.

Link operation is currently unused (it was previously there for undo,
but we have removed the undo feature for now). The chldActor and chldCtr
columns were only used by link operations, so they can be removed too.
However, for cursors we also need an (actor, counter) pair to reference
the list element in question, so I'm renaming these columns to refActor
and refCtr and will use them for cursor storage.
For now it just stores the elemId referenced by the cursor in the
backend, updates the frontend-backend protocol to handle cursors, and
instantiates Cursor objects in the frontend.

Does not actually perform the conversion from elemId to index yet;
that's next.
@pvh pvh modified the milestones: 1.0 alpha release, next release Feb 4, 2021
@ept
Copy link
Member Author

ept commented Feb 5, 2021

This PR is now mostly complete and working: cursors can be created and stored, and indexes are automatically recomputed as needed. There is one known issue: Automerge.load(Automerge.store(doc)) currently throws an exception when loading a document that contains cursors (there's a skipped test for this). Storing and loading a document should work if it is done as Automerge.applyChanges(Automerge.init(), Automerge.getAllChanges(doc)). I will try to fix this soonish, but otherwise this feature is ready for people to start playing with.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants