1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
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
}
|