[lexical] Bug Fix: Fix cache coherency issue with RangeSelection#extract#7836
[lexical] Bug Fix: Fix cache coherency issue with RangeSelection#extract#7836etrepum merged 6 commits intofacebook:mainfrom
RangeSelection#extract#7836Conversation
When `$isTextNode(firstNode)` is true above, it's possible to run `selectedNodes.shift()`. Then `lastIndex` is not longer the last index, but rather the index after the end of the array - resulting in this line appending to the current array rather than replacing as is intended. Use the current length of `selectedNodes` to avoid this edge case.
`selectedNodes` is a reference to `_cachedNodes`, so changes are reflected. Except, during `splitText`, `_cachedNodes` is reset to null, so later changes will not be reflected. (The reset is due to assigning to the `anchor`/`focus` of the current selection - `Point#set` resets `_cachedNodes` on the associated selection). It's very confusing that sometimes the selection will have its nodes updated on `extract` and not others. In fact, in this edge case, while the first run of `extract` will not update `_cachedNodes`, an immediate subsequent run will.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Please do add tests if you're fixing bugs. Without a test there's nothing stopping a future regression. |
|
Ah, will do. |
|
For what it's worth I think this probably has other bugs related to splitting and re-using the cached selection. I think a more reliable strategy would be to do any slicing of text nodes first, then get the extracted nodes. The caret APIs are better at dealing with this sort of thing, but nobody has refactored extract to use them. |
|
Makes sense. Regardless this fix is useful for avoiding a custom patch when I next update my repo from upstream. Adding a test should also ensure a future refactor doesn't regress and break me again. |
|
I think manually updating cachedNodes is not a good fix, setting it to null when the selection changes is what's supposed to happen, it will just be recomputed the next time getNodes is called. It's never really supposed to be updated in-place, the logic to maintain that sort of cache is very error-prone and hard to maintain. If this repo had good readonly hygiene the return type of getNodes would be a readonly array so you wouldn't be able to mutate it without copying first since it is a shared cache. It would make sense for The |
…des` Same as previous commits, `splitText` will set `_cachedNodes` to `null`, so we need to reset it here.
|
It's not expected behavior for
Both of these methods are kinda bad, which is a big reason why the caret APIs exist. Any fixes to them should be really precise, and I don't think this strategy (trying to force things into the cache that won't be computed the same way when the cache is cleared) is the right one. |
Unfortunately sometimes the changes aren't observable regardless, which is part of the issue I was hoping to solve. For example, if I remove the
So I'm not sure your suggestion would work since Overall, I'm just hoping to get the nicest behavior with minimal changes. Right now my repo will fail with a stale |
|
I don't think you quite follow what I'm saying here. The |
|
It would also make sense to make a copy of the result of |
RangeSelection#extractRangeSelection#extract
|
Nice, happy to see the tests passing with this style rather than modifying |
Description
Fix two bugs:
lastIndex- this is no longer accurate ifselectedNodes.shift()happens above.splitTextdoesn't reset the selection's anchor and focus itself correctly in all cases, especially when the RangeSelection isn't the editor's current selection. Manually setting the anchor and/or focus when splitText is called ensure that this happens.Test plan
New unit tests to cover edge cases with extract() and getNodes() when the anchor/focus are on TextNodes