This repository has been archived by the owner on Sep 30, 2020. It is now read-only.
/
diff.go
102 lines (91 loc) · 2.38 KB
/
diff.go
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
90
91
92
93
94
95
96
97
98
99
100
101
102
package root
import (
"bytes"
"encoding/json"
"fmt"
"github.com/aryann/difflib"
"github.com/mgutz/ansi"
"math"
"strings"
)
func diffJson(current, desired string, context int) (string, error) {
var currentBytes bytes.Buffer
err := json.Indent(¤tBytes, []byte(current), "", " ")
if err != nil {
return "", err
}
var desiredBytes bytes.Buffer
err = json.Indent(&desiredBytes, []byte(desired), "", " ")
if err != nil {
return "", err
}
return diffText(currentBytes.String(), desiredBytes.String(), context)
}
func diffText(current, desired string, context int) (string, error) {
stackDiffs := difflib.Diff(strings.Split(current, "\n"), strings.Split(desired, "\n"))
stackDiffOutputs := []string{}
if context >= 0 {
distances := calculateDistances(stackDiffs)
omitting := false
for i, r := range stackDiffs {
if distances[i] > context {
if !omitting {
stackDiffOutputs = append(stackDiffOutputs, "...")
omitting = true
}
} else {
omitting = false
stackDiffOutputs = append(stackDiffOutputs, sprintDiffRecord(r))
}
}
} else {
for _, r := range stackDiffs {
stackDiffOutputs = append(stackDiffOutputs, sprintDiffRecord(r))
}
}
return strings.Join(stackDiffOutputs, ""), nil
}
// Calculate distance of every diff-line to the closest change
func calculateDistances(diffs []difflib.DiffRecord) map[int]int {
distances := map[int]int{}
// Iterate forwards through diffs, set 'distance' based on closest 'change' before this line
change := -1
for i, diff := range diffs {
if diff.Delta != difflib.Common {
change = i
}
distance := math.MaxInt32
if change != -1 {
distance = i - change
}
distances[i] = distance
}
// Iterate backwards through diffs, reduce 'distance' based on closest 'change' after this line
change = -1
for i := len(diffs) - 1; i >= 0; i-- {
diff := diffs[i]
if diff.Delta != difflib.Common {
change = i
}
if change != -1 {
distance := change - i
if distance < distances[i] {
distances[i] = distance
}
}
}
return distances
}
func sprintDiffRecord(diff difflib.DiffRecord) string {
text := diff.Payload
var res string
switch diff.Delta {
case difflib.RightOnly:
res = fmt.Sprintf("%s\n", ansi.Color("+ "+text, "green"))
case difflib.LeftOnly:
res = fmt.Sprintf("%s\n", ansi.Color("- "+text, "red"))
case difflib.Common:
res = fmt.Sprintf("%s\n", " "+text)
}
return res
}