Fix Cursor blot restoration and selection preservation #2354
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR refixes issue #1019 and de0d564.
Repros for bugs addressed:
aa, click between the two A's, then do command-B, command-B, then typeb. You should get a plainabawith the cursor after theb. Added a functional test for this.aa, click between the two A's, then do command-B, typeb, command-B, typec. You should getabcawith a boldb. Added a functional test for a case similar to this.asdfasdf), click in the middle of it, then do command-B, command-B, and then click somewhere else in the text, before or after the first position. The text cursor should stay where you planted it (instead of e.g. jumping to the end of the line). This is equivalent to the unit test that was failing.Basically, to be correct,
cursor.restorehas to take a number of things into account:cursor.restoremay be a selection change from the user clicking in a different text node, such as that of an adjacent TextBlot, which may be optimized away. Therefore, selection preservation must operate even if the selection isn't in the Cursor blot's own textNode. This is the subject of repro 4 above. In this case, I also had to make sure that the return value ofcursor.restoreis always used by the caller!editor.update, but for full correctness there mustn't be any case ofcursor.restorethat uses the Cursor blot's own textNode, mutated by the user, as part of the document (outside of the Cursor blot which is removed), because then the "hack path" ineditor.updatewill think it has a green light and try to generate a delta based on the current value of the text node, which is not going to come out properly.The solution is for
cursor.restoreto optimize the surrounding text nodes on the spot and calculate an appropriate selection range if the old selection is anywhere in those text nodes.