Reimplementing markRange for comments

I know that markRange has previously been replaced with Decorations, and I also know that commenting cross node has been discussed a fair bit on here and there are questions re: their validity in a document model. However, comments definitely form part of our document model and as such I’ve spent the last couple of days reimplementing the logic for markRange.

This has meant creating a separate model that stores the start and end of comments and maps all those positions through each transaction before appending a transaction that handles storedMarks and removing them. I also use Decorations for showing the start / end of comments that span a few nodes. Undo and copy / paste were pretty hairy areas to sort out (going through the added slice, scanning for marks, rebuilding the model etc.) but I’ve sort of got it working. I can’t help but feel that I’m definitely fighting against the API a bit here and wondered if there were a preferred way to go about this?

The approach I’ve got for commenting works (until I find an edge case that it doesn’t work for) but it doesn’t feel efficient and it certainly doesn’t feel like I’m using ProseMirror in the way it was intended.

For example, as mentioned above, in order to cleanly handle undo / paste operations I need to find all the marks in the edited range and rebuild the comment model from their (giving them a new id). To do this I’ve repurposed the code from tr.removeMark to find all the marks and go from there. As finding mark positions isn’t part of the API even though the logic is present in the library I wonder if either there is a plan to expose tools to handle this sort of plugin or otherwise to handle marks that span multiple nodes more broadly without a plugin?

There isn’t a good solution to integrating comments with copy/paste and history so far. markRange didn’t help there either.

Ok, well I’m glad the code I’m writing isn’t unnecessarily complex. Would you accept a PR to expose some of the mark finding logic from the lib, rather than me trying to keep it up to date going forward?

Probably not. What does the mark-finding logic do?

When pasting / undoing it needs to find the marks from the added content and rebuild the comment model I’ve fleshed out - that lives alongside the PM model - based on where those marks are. How (no specifics required) would you suggest I accounted for the clipboard / history cases without something like this?

Edit: mode -> model

Finding the marks doesn’t seem like it’d be the hard part — wiring this into history and clipboard functionality is where it gets difficult. Are you using regular marks (as in strong/em/link/etc) for this?

Yeah, that’s not particularly difficult, I just thought it might be nice not to rewrite (read: copy) that bit but it’s definitely not a deal breaker.

As for whether I’m using a regular mark, no. I’m using a custom mark that simply keeps an id attribute on it or data-comment-id depending on whether it’s in or out of the model. This allows me to parse any content new content from a clipboard / history action and rebuild my model using these ids.

The main challenge is keeping the models consistent with each other but I seem to have gotten past most of this.

Right, clearly, I meant whether it was a mark as in prosemirror-model.Mark, which I guess it is.

So yeah, it may be worthwhile to try and package your solution (specifically, the syncing part) up as a reusable module, but I’m not interested in adding such utilities to the main library.

Yeah, I didn’t want to PR the whole commenting into the library, just the bits I was cutting and pasting from source (e.g. the mark finding stuff you wrote for removeMark). Not particularly because it was difficult but because I’d rather reuse the canonical logic than making sure it survives any updates / breaking changes. Like I say, not a dealbreaker!