RangeError: Selection points outside of document

I have a case where I am running the following code:

removeViewText({ from, to }: { from: number; to: number }) {
    this.cm.dispatch(
        this.cm.state.update({
            changes: { from, to, insert: '' },
        }),
    );
}

And it is giving me the error:

Uncaught RangeError: Selection points outside of document
    at checkSelection (index.js:1542:19)
    at new Transaction (index.js:2243:13)
    at Transaction.create (index.js:2251:16)
    at resolveTransaction (index.js:2424:26)
    at EditorState.update (index.js:2596:16)
    at EditorView.dispatch (index.js:6358:26)
    at MouseSelection.select (index.js:3676:23)
    at new MouseSelection (index.js:3613:18)
    at handlers.mousedown (index.js:3807:45)
    at handleEvent (index.js:3420:17)

This happens when I am simultaneously:

  1. Clicking at the end of my editor (So there is a MouseEvent being triggered)
  2. AND this logic runs (this logic basically runs when I focus away from my codemirror widget)

I tried explicitly setting selections as:

selection: EditorSelection.create([
    EditorSelection.cursor(Math.min(from)),
]).asSingle(),

But I realized this won’t stop the MouseEvent from triggering …
Is there a way for me to tell CodeMirror to process these events in the correct squence so that first the removeViewText is called and then the MouseEvent (by my mouse click) moves the cursor to the end of the new document ?

If you make them two separate extensions, then it should execute the first extension before the second extension. You can even make them appear in the same overall extension by putting them both in [ ]'s.

Hi Bjorn, thanks a lot for the reply !

I only have 1 plugin which adds some decorations (and on click runs the removeViewText to remove some text)

The second event MouseEvent is the standard codemirror event handler.

And I have a limit of only 1 line in codemirror. My editor is not multi line.

So what I think is happening is:

  • I type 5 characters
  • Now I click at position 5 (at the end)
  • My plugin decided to remove the characters between position 4 to 5 (because of some focus event). Now, The new docLength is 4
  • Codemirror had registered a Mouse event at position 5 and tries to handle it. But it cannot move the cursor to position 5 cause it was deleted

Hmm, it’s hard to determine without viewing the source code, could you make a minimum viable example?

I was able to reproduce it here:

This is an example where I want to show a inputbox or dropdown for all the “valid variables” and if the user does not enter a valid variable - I want to remove that variable

Here are the steps to reproduce it:
untitled

This is possibly because you are storing the varRange in the widget, but comparing only by varName, allowing a widget that was created for another range to be reused when the widget’s position changes, and thus end up with an invalid range.

Hi marijn, thanks for the response !

I don’t think it could be a reuse issue because even if I only create 1 widget, the issue still occurs.

Also, removeViewText gets called only once - so there aren’t any orphans.

Plus, I tried making varName a property that is computed using view + varRange and the same still happens.

Found the issue, which was indeed a library problem.

The storing of positions in widgets wasn’t causing this crash, but it is definitely unsafe—even if there’s only a single widget. When the document changes while the widget is alive, that position will become invalid. You can use view.posAtDOM(this.dom) to find the position of the widget in the document in a reliable way.

Phew ! Glad that the issue was caught - this has been bugging my users with the page getting frozen for a few seconds when this happens :slight_smile:

Ah - I was not aware of this function and was sending the positions in as a workaround to achieve my need. Will try this function out

Appreciate all the help @marijn ! And hope this gets released in a version soon