`)
for _, ln := range strings.Split(strings.TrimRight(p, "\n"), "\n") {
cls := "ctx"
switch {
case strings.HasPrefix(ln, "+++"), strings.HasPrefix(ln, "---"),
strings.HasPrefix(ln, "diff "), strings.HasPrefix(ln, "index "),
strings.HasPrefix(ln, "new file"), strings.HasPrefix(ln, "deleted file"),
strings.HasPrefix(ln, "similarity"), strings.HasPrefix(ln, "rename "):
cls = "meta"
case strings.HasPrefix(ln, "@@"):
cls = "hunk"
case strings.HasPrefix(ln, "+"):
cls = "add"
case strings.HasPrefix(ln, "-"):
cls = "del"
}
b.WriteString(`
`)
b.WriteString(template.HTMLEscapeString(ln))
b.WriteString("
")
}
b.WriteString(`
`)
return template.HTML(b.String())
}
// dict builds a map for passing named args to partials, mirroring Hugo's
// dict so shared partials stay portable later.
func dict(kv ...any) (map[string]any, error) {
if len(kv)%2 != 0 {
return nil, fmt.Errorf("dict: odd number of arguments")
}
m := make(map[string]any, len(kv)/2)
for i := 0; i < len(kv); i += 2 {
k, ok := kv[i].(string)
if !ok {
return nil, fmt.Errorf("dict: key %d is not a string", i)
}
m[k] = kv[i+1]
}
return m, nil
}
func humanBytes(n int64) string {
const unit = 1024
if n < unit {
return fmt.Sprintf("%d B", n)
}
div, exp := int64(unit), 0
for x := n / unit; x >= unit; x /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cB", float64(n)/float64(div), "KMGT"[exp])
}