Skip to content

Commit ef0181c

Browse files
committed
Add comments explaining how ctySequenceDiff works
The logic behind this code took me a while to understand, so I wrote down what I understand to be the reasoning behind how it works. The trickiest part is rendering changing objects as updates. I think the other pieces are fairly common to LCS sequence diff rendering, so I didn't explain those in detail.
1 parent d0d9ee1 commit ef0181c

1 file changed

Lines changed: 25 additions & 0 deletions

File tree

‎internal/command/format/diff.go‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1814,7 +1814,27 @@ func ctySequenceDiff(old, new []cty.Value) []*plans.Change {
18141814
lcs := objchange.LongestCommonSubsequence(old, new)
18151815
var oldI, newI, lcsI int
18161816
for oldI < len(old) || newI < len(new) || lcsI < len(lcs) {
1817+
// We first process items in the old and new sequences which are not
1818+
// equal to the current common sequence item. Old items are marked as
1819+
// deletions, and new items are marked as additions.
1820+
//
1821+
// There is an exception for deleted & created object items, which we
1822+
// try to render as updates where that makes sense.
18171823
for oldI < len(old) && (lcsI >= len(lcs) || !old[oldI].RawEquals(lcs[lcsI])) {
1824+
// Render this as an object update if all of these are true:
1825+
//
1826+
// - the current old item is an object;
1827+
// - there's a current new item which is also an object;
1828+
// - either there are no common items left, or the current new item
1829+
// doesn't equal the current common item.
1830+
//
1831+
// Why do we need the the last clause? If we have current items in all
1832+
// three sequences, and the current new item is equal to a common item,
1833+
// then we should just need to advance the old item list and we'll
1834+
// eventually find a common item matching both old and new.
1835+
//
1836+
// This combination of conditions allows us to render an object update
1837+
// diff instead of a combination of delete old & create new.
18181838
isObjectDiff := old[oldI].Type().IsObjectType() && newI < len(new) && new[newI].Type().IsObjectType() && (lcsI >= len(lcs) || !new[newI].RawEquals(lcs[lcsI]))
18191839
if isObjectDiff {
18201840
ret = append(ret, &plans.Change{
@@ -1827,6 +1847,8 @@ func ctySequenceDiff(old, new []cty.Value) []*plans.Change {
18271847
continue
18281848
}
18291849

1850+
// Otherwise, this item is not part of the common sequence, so
1851+
// render as a deletion.
18301852
ret = append(ret, &plans.Change{
18311853
Action: plans.Delete,
18321854
Before: old[oldI],
@@ -1842,6 +1864,9 @@ func ctySequenceDiff(old, new []cty.Value) []*plans.Change {
18421864
})
18431865
newI++
18441866
}
1867+
1868+
// When we've exhausted the old & new sequences of items which are not
1869+
// in the common subsequence, we render a common item and continue.
18451870
if lcsI < len(lcs) {
18461871
ret = append(ret, &plans.Change{
18471872
Action: plans.NoOp,

0 commit comments

Comments
 (0)