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 }