feat(engine): match leaves across containers and preserve sibling moves - #64
Merged
Conversation
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.
Problem
MatchUnmatchedLeavesrequired leaves to share the exact same immediate parent container. When code was refactored across container types (like comments moving from anelifclause into anifblock, or aforloop refactored into a dictionary comprehension), unmatched leaves were skipped, so we ended up with spurious delete and insert pairs instead of clean structural moves.normalizeBareLiteralMovesin post-processing split any literal or identifierMoveinto aDelete+Insertwhenever its parent container was unmapped. So when aforloop moved into afor_in_clause,cookieandcjgot split into delete/insert actions whileforandinstayed as moves.mergeAllSpansiterated sequentially over line spans without grouping by action kind. Interleaved containerkindDeletespans blocked adjacentkindMovespans from merging, which left red background gaps inside blue move highlights.What Changed
SharedMatchedAncestorininternal/engine/utils.gosoMatchUnmatchedLeavescan pair leaves across container boundaries if they share an enclosing statement or block ancestor.RollupMatchedContainersininternal/engine/bottom-up.goto pair unmatched container nodes post-order when their mapped children belong to the same unmatched destination parent.LCSStructurewhen subtrees contain long leaf tokens (len > 3) andLeafSimilarityis 0, so distinct key-value pairs like status codes414vs422don't get falsely matched.normalizeBareLiteralMovesininternal/postprocess/normalize.gowithhasMovedSiblingFromSameParentto preserve literal and identifier moves when destination siblings also moved from the same source parent.actionKindininternal/tui/highlight.go(mergeAllSpans) so move spans merge smoothly across gaps without getting interrupted by container delete spans.tests/testdata/and added unit tests ininternal/engine/,internal/postprocess/, andinternal/tui/.Visual Comparison
1.
tests/testdata/py_requests_add_rfc9110Before
After
Insertactions for the newly added status codes.