Files
oddmu/diff.go
2025-12-06 14:10:20 +01:00

65 lines
1.6 KiB
Go

package main
import (
"bytes"
"html"
"html/template"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/sergi/go-diff/diffmatchpatch"
)
func diffHandler(w http.ResponseWriter, r *http.Request, name string) {
p, err := loadPage(name)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
p.handleTitle(true)
p.renderHTML()
renderTemplate(w, p.Dir(), "diff", p)
}
// Diff computes the diff for a page. At this point, renderHTML has already been called so the Name is escaped.
func (p *Page) Diff() template.HTML {
fp := filepath.FromSlash(p.Name)
a := fp + ".md~"
t1, err := os.ReadFile(a)
if err != nil {
return template.HTML("Cannot read " + a + ", so the page is new.")
}
b := fp + ".md"
t2, err := os.ReadFile(b)
if err != nil {
return template.HTML("Cannot read " + b + ", so the page was deleted.")
}
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(string(t1), string(t2), false)
return template.HTML(diff2html(dmp.DiffCleanupSemantic(diffs)))
}
func diff2html(diffs []diffmatchpatch.Diff) string {
var buf bytes.Buffer
for _, item := range diffs {
text := strings.ReplaceAll(html.EscapeString(item.Text), "\n", "<br>")
switch item.Type {
case diffmatchpatch.DiffInsert:
_, _ = buf.WriteString("<ins>")
_, _ = buf.WriteString(text)
_, _ = buf.WriteString("</ins>")
case diffmatchpatch.DiffDelete:
_, _ = buf.WriteString("<del>")
_, _ = buf.WriteString(text)
_, _ = buf.WriteString("</del>")
case diffmatchpatch.DiffEqual:
_, _ = buf.WriteString("<span>")
_, _ = buf.WriteString(text)
_, _ = buf.WriteString("</span>")
}
}
return buf.String()
}