package render
import ( "bytes" "html/template"
"github.com/alecthomas/chroma/v2"
chromahtml "github.com/alecthomas/chroma/v2/formatters/html"
"github.com/alecthomas/chroma/v2/lexers"
"github.com/alecthomas/chroma/v2/styles"
)
// blobFormatter renders class-based HTML (no inline styles) with line numbers, // so the shared /_assets/chroma.css covers it and the strict CSP holds. var blobFormatter = chromahtml.New( chromahtml.WithClasses(true), chromahtml.WithLineNumbers(true), chromahtml.LineNumbersInTable(true), )
// IsBinary reports whether src looks like binary (non-text) content, in which // case it should not be highlighted but offered as a raw download. func IsBinary(src []byte) bool { if len(src) == 0 { return false } // A NUL byte in the first 8KiB is the classic binary heuristic (matches git). n := len(src) if n > 8192 { n = 8192 } return bytes.IndexByte(src[:n], 0) >= 0 }
// Highlight returns class-based syntax-highlighted HTML for a text blob. The // lexer is chosen by filename, then by content analysis, falling back to plain // text. Output uses only CSS classes (covered by CSS()), never inline styles. func Highlight(filename string, src []byte) (template.HTML, error) { lexer := lexers.Match(filename) if lexer == nil { lexer = lexers.Analyse(string(src)) } if lexer == nil { lexer = lexers.Fallback } lexer = chroma.Coalesce(lexer)
style := styles.Get(chromaStyle)
iterator, err := lexer.Tokenise(nil, string(src))
if err != nil {
return "", err
}
var buf bytes.Buffer
if err := blobFormatter.Format(&buf, style, iterator); err != nil {
return "", err
}
return template.HTML(buf.String()), nil
}