Restoring history without blowing up extensions state

Hi, i’m writing an application that uses codemirror 6. The application has multiple tabs and switching from one tab to another obviosuly changes the code in the editor.

When switching from one tab to another i keep track of the EditorState inside a map and i restore that state whenever the user switch again to that tab. This is to keep the history related to a specific tab.

However if i set the new state without reconfiguring the extensions every extension is removed. But reconfiguring the extensions also means that every state associated with a specific extension is lost. This is not a problem in most cases but there are specific extensions where loosing the state it’s very user unfriendly (for example the vim extension will revert back to normal mode whenever the state is reassigned).

Is there a way to prevent this behavior?

What kind of extension state do you mean? Everything tracked in the actual EditorState should be preserved. ViewPlugins will indeed be recreated, which is why extensions shouldn’t store anything important in there.

The example i proposed is the best one. The vim plugin stores the mode (either normal, insert or visual) and that get’s reset whenever we reset the state on tab switch.

For reference what we do is store the state in a map and then

    EditorState.fromJSON(state, { extensions, doc: state.doc }, { history: historyField })
    changes: { from: 0, to: $cmInstance.view.state.doc.length, insert: state.doc },
    effects: [StateEffect.reconfigure.of($cmInstance.extensions ?? [])]

Do you need to serialize the state in order to put it on the server? If not, just don’t do the fromJSON/toJSON stuff.

If you do, you’re responsible for adding back the extensions when calling EditorState.fromJSON, and for extensions that don’t support serialization of their state you will indeed lose the state.

Mmm i think i found what the problem is…the package we are using seems to not store the state for the Extension in a facet (and hence in the codemirror state). Can you confirm that’s the case? Here’s the snippet of code that shows the state for example

updateStatus() {
      let dom =;
      let vim =;
      if (!dom || !vim) return;
      let dialog =;
      if (dialog) {
        if (dialog.parentElement != dom) {
          dom.textContent = "";
      } else {
        dom.textContent = ""
        var status = (vim.mode || "normal").toUpperCase();
        if (vim.insertModeReturn) status += "(C-O)"
        this.statusButton.textContent = `--${status}--`;

      this.dom.textContent = vim.status;

I don’t know what this is, but it is not using the library as intended (seems to be randomly adding properties to the state object). Is this code from the vim plugin?

Yeah that was my tought as well. Would you mind giving a rapid look at this github repo to confirm i’m not crazy?

The object in question here doesn’t seem to be an actual CodeMirror EditorView, and state is just an object, not an EditorState. So it’s not as wrong as it initially looks.

Still, that code doesn’t appear to be very well integrated with the CodeMirror update cycle so I’m not very surprised its state doesn’t survive view changes.