Selection not re-drawn correctly after window resize.

I updated from cm/view 0.19.14 to 0.19.37 the other day. After the update, the selections are not re-drawn correctly, after I resize the window.

This only happens, if the resize does not directly affect the dimension of the .cm-line DOM elements. If the .cm-line measurements change due to resizing, the selection updates properly.

Why move the selection, if .cm-line doesn’t change, you might ask. Well, .cm-line has a fixed max-width inside a full-width .cm-content and is centered via margin: 0 auto;. So it moves every time the window width changes. I need to center at .cm-line level and cannot center the whole .cm-content or .cm-scroller elements due to several styling requirements.

This worked with a previous version of CM (based on cm/view 0.19.14). However, I can only speculate, tha issue lying inside cm/view, since I updated all CM dependencies.

Arbitrary styling of elements inside the editor is not generally supported—this will likely break other things beyond redrawing selections after resize, such as coordinate-to-position mapping.

I was afraid, you’d say that. And I 100 % understand.

Unfortunately, in my case, I have no choice right now. Can you probably pinpoint the commit that may have changed the resize behavior since 0.19.14 out of the back of your head? This would give my a chance to apply a manual patch.

I’ve already searched through the Commits on GitHub, but the ones I found, don’t seem to have caused the change.

Nothing specific comes to mind, but git bisect might help with this.

1 Like

Didn’t know about git bisect. Pretty useful. Thanks for that. Using it, I found the version(s) which broke things for me.

Just to give you a little background about my kind of arbitrary styling of elements inside the editor: I need to produce a full screen CM6 editor with limited text-width but scrollbars always at the right of the screen.

I am doing a couple of other styling tricks, too. But this might be the big one that could be of any relevance to others or CM6 in general.

So here’s a summary of what I found out about selection re-draw when resizing:

  • Last well working version: 0.19.20
  • Last working version with animation stutters: 0.19.21
  • First not working version: 0.19.22

Looking a the commits between 20 and 22 I took a closer look at these two:

ddc2ae4 doesn’t break it, yet. However, selection replacement stutters during resize animations. Probably due to interval increase from 50 to 75 ms?

1e8c471 is a candidate of the commit that may have broken things for me. However, the stuff going on in there is quite a bit above my understanding of CM internals.

So, if you could spare the time to give me a hint, I’d be a happy dev. If this is too much to ask, I’d totally understand. Just ignore it, then. :slight_smile:

Have you tried making the editor resize to fit its content and putting the scrollbar on another element?

This came up in another context in this issue, and should be fixed in @codemirror/view 0.19.39.

Wouldn’t this negate all the viewport optimizations internal to cm6 with respect to large documents?

No, CM6 will also use the window viewport to limit the amount of code it renders.

Ah good to know, thanks!

Wait, does this mean that cm6 takes global event listeners that does not get automatically garbage collected when the cm6 object and DOM elements are removed? I.e. there’s a memory leak if a user simply detaches the DOM element of the editor and de-references the cm6 EditorView?

Ah got my answer after some digging here: view/domobserver.ts at 60b0f10a90fc90305238be01097ed511d07dcbbb · codemirror/view · GitHub

It seems that cm6 is indeed hooking event handlers outside of its element and must be lifecycle-managed and properly destroyed to avoid leaks.

This is great news! Can confirm. This fixes my issue, as well.

This is an appealing approach worth considering to make things more resilient. Is EditorView.contentHeight the right metric to apply to the editor height?

Interesting insight. Is delete edtorView the proper way to do that?

Based on my limited understanding, one needs to call editorView.destroy() to have it properly cleaned up.

Yes, the editor has to have destroy called on it to properly clean up.