git@cosmocr.at/gitweb.git @ main · summary refs log
main / internal / render / highlight.go /
internal/render/highlight.go · 1.6 KiB · raw
view: Source ☐ force
 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
}