-
Notifications
You must be signed in to change notification settings - Fork 9
/
diff.go
79 lines (63 loc) · 2.19 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
package diff
import (
"github.com/j-keck/go-diff/diffmatchpatch"
"github.com/j-keck/zfs-snap-diff/pkg/fs"
)
type Diff struct {
Deltas []Deltas `json:"deltas"`
Patches []string `json:"patches"`
SideBySideDiffHTMLFragment []string `json:"sideBySideDiffHTMLFragment"`
InlineDiffHTMLFragment []string `json:"inlineDiffHTMLFragment"`
PrettyTextDiff string
}
func NewDiff(from, target string, contextSize int) Diff {
// init diff-match-patch and create the (diff-match-patch) diff
dmp := diffmatchpatch.New()
// dmp.DiffEditCost = 10
// make a line based diff - for side by side
fromLines, targetLines, lines := dmp.DiffLinesToChars(from, target)
lineBasedDiffs := dmp.DiffMain(fromLines, targetLines, false)
if len(lineBasedDiffs) == 1 && lineBasedDiffs[0].Type == 0 {
// cancel if no differences found
return Diff{[]Deltas{}, []string{}, []string{}, []string{}, ""}
}
lineBasedDiffs = dmp.DiffCleanupSemantic(lineBasedDiffs)
lineBasedDiffs = dmp.DiffCharsToLines(lineBasedDiffs, lines)
lineBasedDeltas := createDeltasFromDiffs(lineBasedDiffs, contextSize)
// make a char based diff - for inline diff
charBasedDiffs := dmp.DiffMain(from, target, true)
charBasedDiffs = dmp.DiffCleanupSemantic(charBasedDiffs)
charBasedDeltas := createDeltasFromDiffs(charBasedDiffs, contextSize)
// deltas
deltas := splitDeltasByContext(lineBasedDeltas)
// create patches from char based -> smaller patches
var patches []string
for _, patch := range dmp.PatchMake(charBasedDiffs) {
patches = append(patches, patch.String())
}
return Diff{
deltas,
patches,
createSideBySideDiffHTMLFragment(lineBasedDeltas),
createInlineDiffHTMLFragment(charBasedDeltas),
dmp.DiffPrettyText(lineBasedDiffs),
}
}
func NewDiffFromPath(from, target string, contextSize int) (Diff, error) {
fromContent, err := readTextFile(from)
if err != nil {
return Diff{}, err
}
targetContent, err := readTextFile(target)
if err != nil {
return Diff{}, err
}
return NewDiff(fromContent, targetContent, contextSize), nil
}
func readTextFile(path string) (string, error) {
fh, err := fs.GetFileHandle(path)
if err != nil {
return "", err
}
return fh.ReadString()
}