fix: treat moving a range to where it already sits as a no-op - #347
Open
wahidrizka wants to merge 1 commit into
Open
fix: treat moving a range to where it already sits as a no-op#347wahidrizka wants to merge 1 commit into
wahidrizka wants to merge 1 commit into
Conversation
move() already returns early when the range is the last chunk and the target is the end of the string, but it had no such check when an earlier move had already put the range right before the target index. The splice then made the range its own neighbour: the range vanished from toString() unless it was at the very start, and the chunk list got a backwards loop that could make lastChar(), lastLine() and trimEnd() run forever. It now returns early in that case too.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
move()returns early when the range is already the last chunk and the target is the end of the string. It has no such check when an earlier move has already put the range right before the target index, which is also a no-op, so it splices the range in next to itself.When the range is at the very start instead, the text survives but the first chunk becomes its own
previous.toString()walks forwards, so it looks fine, but anything that walks backwards never reaches the start:lastChar()andtrimEnd()get stuck the same way when the chunks they walk back over are empty or all whitespace.The fix adds the missing early return next to the existing one: if the chunk at
indexis already preceded by the range's last chunk, there is nothing to move. This is separate from the case thehasMovedChunkswalk handles (a range an earlier move has split), which is caught before this point and still throws.To check this is the only way
move()goes wrong here, I ran random sequences of moves against a small reference model (a list of original positions, where a move takes the run out and puts it back before the target). Before the fix, all 4,916 divergences in 50,000 sequences happened at a step the model says changes nothing, and none at a real move. After the fix there are none in 200,000 sequences (about 287,000 valid moves).Both new tests fail on the old code and pass now. The suite goes from 366 to 368, and
tsc(both configs) andeslintare clean.A side note on the tests:
IntegrityCheckingMagicStringis meant to runcheckIntegrity()after every call, which would have caught this, but it looks up methods withfor...in, and class methods are not enumerable, so it wraps none of the 43. The new tests callcheckIntegrity()directly so that on the old code they fail right away instead of hanging. With the loop switched toObject.getOwnPropertyNames, all 43 get wrapped and the full suite passes on this branch, so I can send that as a separate PR if you'd like.