7 "github.com/sergi/go-diff/diffmatchpatch"
16 func (v *Variant) String() string {
18 case len(v.New) == 0 && len(v.Ref) == 1:
19 return fmt.Sprintf("%ddel", v.Position)
21 return fmt.Sprintf("%d_%ddel", v.Position, v.Position+len(v.Ref)-1)
22 case len(v.Ref) == 1 && len(v.New) == 1:
23 return fmt.Sprintf("%d%s>%s", v.Position, v.Ref, v.New)
25 return fmt.Sprintf("%d_%dins%s", v.Position-1, v.Position, v.New)
26 case len(v.Ref) == 1 && len(v.New) > 0:
27 return fmt.Sprintf("%ddelins%s", v.Position, v.New)
29 return fmt.Sprintf("%d_%ddelins%s", v.Position, v.Position+len(v.Ref)-1, v.New)
33 func Diff(a, b string) []Variant {
34 dmp := diffmatchpatch.New()
35 diffs := cleanup(dmp.DiffCleanupEfficiency(dmp.DiffBisect(a, b, time.Time{})))
37 var variants []Variant
38 for i := 0; i < len(diffs); i++ {
39 switch diffs[i].Type {
40 case diffmatchpatch.DiffEqual:
41 pos += len(diffs[i].Text)
42 case diffmatchpatch.DiffDelete:
43 if i+1 < len(diffs) && diffs[i+1].Type == diffmatchpatch.DiffInsert {
44 // deletion followed by insertion
45 variants = append(variants, Variant{Position: pos, Ref: diffs[i].Text, New: diffs[i+1].Text})
46 pos += len(diffs[i].Text)
49 variants = append(variants, Variant{Position: pos, Ref: diffs[i].Text})
50 pos += len(diffs[i].Text)
52 case diffmatchpatch.DiffInsert:
53 if i+1 < len(diffs) && diffs[i+1].Type == diffmatchpatch.DiffDelete {
54 // insertion followed by deletion
55 variants = append(variants, Variant{Position: pos, Ref: diffs[i+1].Text, New: diffs[i].Text})
56 pos += len(diffs[i+1].Text)
59 variants = append(variants, Variant{Position: pos, New: diffs[i].Text})
66 func cleanup(in []diffmatchpatch.Diff) (out []diffmatchpatch.Diff) {
67 for i := 0; i < len(in); i++ {
69 for i < len(in)-1 && in[i].Type == in[i+1].Type {
70 d.Text += in[i+1].Text