Updating block-widgets // What is the order of the state update cycle, exactly?


I am running into kind of conundrum and want to stick as much to the optimal update flow as possible based on what CodeMirror does during an update. I’ve read and re-read the documentation and this forum for the past week to no avail.

For context, I have an extension, implemented as a StateField that provides a set of BlockWidget type Decoration.replacements. These are quite expensive to calculate, so I already adapted the StateFields update() method in such a way that I only actually create the new decorations/map existing decoration ranges as I need them.

However, I need the widgets to update, preferably with a function I control to keep the actual DOM updates as cheap as possible, and it appears to me as if the updateDOM function is never called on Block level widgets. Is this true? If so, what would be an appropriate place to let them update? The reason I’m asking is that, while I can actually update the DOM structure manually during the state update (in which Block level widgets, I think, can still be updated), they need a reference to the EditorView at some point. The reason is that they may, if the main selection range is within them, need to show a sub-EditorView (akin to the split view example) that gets hooked to receiving updates from the main view. This will happen outside the main view’s update cycle so that there’s no interference in the DOM writing stage. I have already thought about the following possibilities:

  1. Create a ViewPlugin in the provide function that calls the function manually during an update cycle. (But then this might change the editor height, so the function should really be called before the DOM update after which, I presume, the ViewPlugins will be updated?)
  2. Let the toDOM function in the widgets cache a reference to the EditorView, and call a custom function on the widgets during the state update. Since the widgets are bound to one specific view, this should be fine, no? It sounds reasonable, but feels very dirty to me – especially since there is the updateDOM function, and it feels wrong not to use it.
  3. Are there maybe other ways that I haven’t thought about?

So I have essentially two questions:

  1. What exactly is the update cycle of CodeMirror? When does what get executed? (This might actually be valuable information on the main page, next to the event → state update → view update cycle diagram.)
  2. How should I approach this problem?

Sorry for the lengthy post, but I hope that you may be able to help me out here.

Thanks already in advance!

This example shows how to use updateDOM. I suspect, from your message, that you’re mutating your decorations, and expecting the method to run then? That’s not how these work—they are immutable like everything else you store in your state. You replace them with a widget of the same type to have updateDOM called.

Thank you for the reply and also drafting an example! I really appreciate it.

In my testing, the updateDOM method was never called, even when I replaced widgets with same type but non-eq ones. I’ll have to double-check, but if it works I just had a good idea for doing so smartly.

I played around a little and found the problem: I set inclusive: false (which allegedly is the default according to the documentation), and once I removed that property, the editor started calling updateDOM again.

It only happens for replacement block Decorations. Are these set to inclusive: true by default? The documentation doesn’t seem to say anything about this behavior.

It’s not, for block widgets, if you read the docs more closely.

The failure to call updateDOM here was an issue in @codemirror/view. This patch should fix it.

Sorry, that sentence escaped my view – apologies. I was too fixated on the bug that you’ve just fixed. I can report that everything is working as expected now – sorry for bothering you, and thank you for your swift support!