package render import ( "html/template" "strings" "github.com/go-git/go-git/v5/plumbing/format/diff" "github.com/go-git/go-git/v5/plumbing/object" ) // Diff renders a go-git commit patch as a class-tagged HTML table: a header row // per file then added/removed/context lines, each tagged with a CSS class // (.diff-add/.diff-del/.diff-ctx) defined in style.css. No inline styles, so // the strict CSP is preserved. func Diff(p *object.Patch) template.HTML { var b strings.Builder b.WriteString(`` + "\n") for _, fp := range p.FilePatches() { from, to := fp.Files() b.WriteString(`\n") if fp.IsBinary() { continue } for _, chunk := range fp.Chunks() { class, prefix := chunkStyle(chunk.Type()) lines := strings.Split(strings.TrimSuffix(chunk.Content(), "\n"), "\n") for _, line := range lines { b.WriteString(`\n") } } } b.WriteString("
`) b.WriteString(template.HTMLEscapeString(fileHeader(from, to, fp.IsBinary()))) b.WriteString("
` + prefix + ``) b.WriteString(template.HTMLEscapeString(line)) b.WriteString("
\n") return template.HTML(b.String()) } func chunkStyle(op diff.Operation) (class, prefix string) { switch op { case diff.Add: return "diff-add", "+" case diff.Delete: return "diff-del", "-" default: return "diff-ctx", " " } } func fileHeader(from, to diff.File, binary bool) string { var name string switch { case from == nil && to != nil: name = "added " + to.Path() case from != nil && to == nil: name = "deleted " + from.Path() case from != nil && to != nil && from.Path() != to.Path(): name = from.Path() + " → " + to.Path() case to != nil: name = to.Path() case from != nil: name = from.Path() } if binary { name += " (binary)" } return name }