Diffdown is a real-time collaborative Markdown editor/previewer built on the AT Protocol
diffdown.com
1package version
2
3import (
4 "strings"
5
6 difflib "github.com/sergi/go-diff/diffmatchpatch"
7)
8
9type DiffLine struct {
10 Type string `json:"type"` // equal, insert, delete
11 Content string `json:"content"`
12 OldNum int `json:"old_num,omitempty"`
13 NewNum int `json:"new_num,omitempty"`
14}
15
16func Diff(oldText, newText string) []DiffLine {
17 dmp := difflib.New()
18 diffs := dmp.DiffMain(oldText, newText, true)
19 diffs = dmp.DiffCleanupSemantic(diffs)
20
21 var lines []DiffLine
22 oldNum := 1
23 newNum := 1
24
25 for _, d := range diffs {
26 parts := strings.Split(d.Text, "\n")
27 for i, part := range parts {
28 if i == len(parts)-1 && part == "" {
29 continue
30 }
31 switch d.Type {
32 case difflib.DiffEqual:
33 lines = append(lines, DiffLine{
34 Type: "equal",
35 Content: part,
36 OldNum: oldNum,
37 NewNum: newNum,
38 })
39 oldNum++
40 newNum++
41 case difflib.DiffInsert:
42 lines = append(lines, DiffLine{
43 Type: "insert",
44 Content: part,
45 NewNum: newNum,
46 })
47 newNum++
48 case difflib.DiffDelete:
49 lines = append(lines, DiffLine{
50 Type: "delete",
51 Content: part,
52 OldNum: oldNum,
53 })
54 oldNum++
55 }
56 }
57 }
58 return lines
59}
60
61func Stats(oldText, newText string) (added, removed int) {
62 dmp := difflib.New()
63 diffs := dmp.DiffMain(oldText, newText, true)
64 for _, d := range diffs {
65 lineCount := strings.Count(d.Text, "\n")
66 if d.Text != "" && !strings.HasSuffix(d.Text, "\n") {
67 lineCount++
68 }
69 switch d.Type {
70 case difflib.DiffInsert:
71 added += lineCount
72 case difflib.DiffDelete:
73 removed += lineCount
74 }
75 }
76 return
77}