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 undocommand 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 Stepinprosemirror-state(similar to howTransactionis a plugin-aware version ofTransform), so that APIs likeStep#invertandStep#applywork on an editor state rather than just a doc.
- Update prosemirror-collabandprosemirror-historyto 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?