I’m writing a plugin that track ranges (from→to) in a document (one use-case is for inline-commenting), and I wanted to leverage the existing collab and history infrastructure as much as possible. To do this I have written some custom steps for creating, deleting, and moving a range, and have written an RFC to introduce a replaceTransaction
API so that these steps can be injected into transactions when appropriate. For example:
- deleting the entire content of a range, should delete the range
- executing the
undo
command should restore the content and the the range - ranges should be synchronised in via prosemirror-collab
However there are a few problems with using Steps for this. Currently steps are intended for doc transforms only (they come from prosemirror-transform
, not prosemirror-state
), so they’re not aware of editor state or plugins. I’m investigating if it would be desirable to have them transform plugin state too. It seems desirable because it would allow plugins to be written that track their own data adjacent to the doc, and have that data stored adjacent in a backend, however it’s possible there’s some practicalities I haven’t taken into account that may make this approach unviable.
To have steps work for plugin state transforms, I think a few changes would be needed:
-
prosemirror-collab wouldn’t look for doc changes
tr.docChanged
, instead it would assume all presence steps should be synced, and so just do atr.steps.length > 0
- Create a plugin-aware
Step
inprosemirror-state
(similar to howTransaction
is a plugin-aware version ofTransform
), so that APIs likeStep#invert
andStep#apply
work on an editor state rather than just a doc. - Update
prosemirror-collab
andprosemirror-history
to use the newStep
.
(2) and (3) are not entirely necessary, a less desirable alternative is to make whatever initial state is needed to invert the step part of the step itself (i.e. pass it in via the constructor), so that it’s available in invert()
.
It’s actually perhaps not necessary to change Step#apply
, as any changes to plugin state can be achieved through the plugin state’s apply
method, so perhaps only Step#invert
would need access to editor state, so that a plugin’s current state can be retrieved and used to produce the inverted step.
I’m also not sure about the implications for rebasing—what does it mean to rebase a plugin state transform—but I think it will just mean custom steps need to be carefully designed to be compatible with rebasing.
Does this seem like a viable direction to pursue, is anyone else interested in this?