This repository was archived by the owner on Jul 8, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdiff.go
More file actions
89 lines (74 loc) · 2.02 KB
/
Copy pathdiff.go
File metadata and controls
89 lines (74 loc) · 2.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package main
import (
"slices"
"strings"
)
// renderDiff highlights words in `output` that were added/changed relative to `input`.
func renderDiff(input, output string) string {
before := strings.Fields(input)
after := strings.Fields(output)
lcs := wordLCS(before, after)
inLCS := make([]bool, len(after))
beforeIdx, afterIdx := 0, 0
for _, word := range lcs {
for beforeIdx < len(before) && before[beforeIdx] != word {
beforeIdx++
}
for afterIdx < len(after) && after[afterIdx] != word {
afterIdx++
}
if afterIdx < len(after) {
inLCS[afterIdx] = true
beforeIdx++
afterIdx++
}
}
words := make([]string, len(after))
for idx, word := range after {
if inLCS[idx] {
words[idx] = word
} else {
words[idx] = addedStyle.Render(word)
}
}
return strings.Join(words, " ")
}
// lcsTable builds the dynamic-programming table for the longest common subsequence length.
func lcsTable(before, after []string) [][]int {
table := make([][]int, len(before)+1)
for i := range table {
table[i] = make([]int, len(after)+1)
}
for beforeIdx, wordBefore := range slices.Backward(before) {
for afterIdx, wordAfter := range slices.Backward(after) {
switch {
case wordBefore == wordAfter:
table[beforeIdx][afterIdx] = table[beforeIdx+1][afterIdx+1] + 1
case table[beforeIdx+1][afterIdx] >= table[beforeIdx][afterIdx+1]:
table[beforeIdx][afterIdx] = table[beforeIdx+1][afterIdx]
default:
table[beforeIdx][afterIdx] = table[beforeIdx][afterIdx+1]
}
}
}
return table
}
// wordLCS returns the longest common subsequence of words between before and after.
func wordLCS(before, after []string) []string {
table := lcsTable(before, after)
var lcs []string
beforeIdx, afterIdx := 0, 0
for beforeIdx < len(before) && afterIdx < len(after) {
switch {
case before[beforeIdx] == after[afterIdx]:
lcs = append(lcs, before[beforeIdx])
beforeIdx++
afterIdx++
case table[beforeIdx+1][afterIdx] >= table[beforeIdx][afterIdx+1]:
beforeIdx++
default:
afterIdx++
}
}
return lcs
}