A few months ago you considered using a CRDT as a data model for CodeMirror.
I completely understand that you are hesitant to integrate a CRDT into CodeMirror just for better position handling. Although, I showed that the overhead of using a CRDT is not that expensive (https://blog.kevinjahns.de/are-crdts-suitable-for-shared-editing/).
ProseMirror and CodeMirror 6 now both implement a similar approach for transforming positions. From a developer experience, this is great. This allows third-party plugins to provide features such as commenting on ranges of the document to unique map positions while accounting for remote changes.
Your blog post describes perfectly the advantages of using a CRDT for position mapping. As I described in the ProseMirror forum, the current position mapping approach is unsuitable for CRDT-bindings to *Mirror editors. So third-party plugins won’t work with CRDT approaches to provide shared editing.
I think there are several good arguments to reconsider using a CRDT for shared editing in CodeMirror.
- Better position handling
- The author of ShareJS and ShareDB openly speaks out against OT: https://news.ycombinator.com/item?id=24194091
- The web has evolved to a point where web applications do work peer-to-peer over WebRTC. One of many real-world examples is room.sh. They use Yjs & CodeMirror 5 to provide collaboration in peer-to-peer WebRTC sessions.
I hope that the future web is more decentralized. Collaboration over WebRTC is already very common. Shared editing backends that use CRDTs are easier to scale because they only require a simple PubSub server to exchange updates (Nimbus based their editor on Yjs because CRDTs are easier to scale). I hope that Local-first software will become more relevant because I believe that data should be owned by the user.
Decentralized web applications are no longer an edge case and they hold a lot of future potential. I hope that CodeMirror 6 plugins, that use the default position mapping, will work as expected in decentralized applications.
So I hope that you reconsider using a CRDT as a data model in CodeMirror 6.
A bit of background about me: I’m the author of a CRDT framework Yjs that enables shared editing over any network stack (WebRTC, Hyper, WebSocket, …). A couple of demos for shared editing in different editors (ProseMirror, CodeMirror, Quil, Atlaskit, …): https://docs.yjs.dev/ecosystem/editor-bindings & https://demos.yjs.dev/
My goal is to power shared editing on the web with Yjs. Different editors can use the same technology to provide shared editing over different backends. I think the Y.Text type would be a great data model for CodeMirror 6. If you are interested, I’d love to help you to integrate the Y.Text type into CodeMirror 6 and work with you on a better approach for position mapping. Another advantage of Yjs is that it supports selective Undo/Redo for free (no additional data structure to hold operations, just ranges on the vector clocks).
Alternatively, it would be helpful if CodeMirror 6 would allow CRDT editor bindings to hijack position mappings. Although, as you explained, index positions don’t always accurately describe ranges in collaborative documents. With CRDTs, it is possible to refer to deleted characters. This is not possible if positions are described as index positions. With any change around the mapped position, some information gets lost. A commenting plugin that describes comments as numeric index ranges on the document wouldn’t work in WebRTC applications like room.sh.
Another alternative is to abstract positions in CodeMirror. A CRDT implementation could add markers to the abstract position to describe the position relative to the CRDT model without doing index transformations (i.e. map to the unique ID of the character).
This abstract position approach is the least intrusive approach that would allow CM to work in distributed software. I would still favor the CRDT integration as shared Undo/Redo should be handled by the CRDT implementation. There are more advantages of integrating a collaboration-aware model into CodeMirror (e.g. support for diffs on the CRDT model, similarly to versions in the yjs.dev demo). But anything that would allow me to provide Yjs bindings for the fantastic CM 6 editor would work for me.