Skip to content
quarry Artifact [51a7e36c30]
Login

Artifact [51a7e36c30]

Artifact 51a7e36c300b597a9066a3048386dcea9b9c1d2036ad6610beea8004e6161d62:


// Package highlight is quarry's thin chroma wrapper (0002 §2 lists the
// Forgejo one as [COPY]; theirs is coupled to their settings and caches,
// so this is a smaller fresh write). Output uses CSS classes, never
// inline styles, so the two-theme story stays in one stylesheet.
package highlight

import (
	"bytes"
	"strings"

	"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"
)

var formatter = chromahtml.New(
	chromahtml.WithClasses(true),
	chromahtml.PreventSurroundingPre(false),
)

// Code highlights source for the given language hint and/or filename;
// either may be empty. ok is false when no lexer matched — callers fall
// back to an escaped <pre>.
func Code(code []byte, language, filename string) (string, bool) {
	var lexer chroma.Lexer
	if language != "" {
		lexer = lexers.Get(language)
	}
	if lexer == nil && filename != "" {
		lexer = lexers.Match(filename)
	}
	if lexer == nil {
		lexer = lexers.Analyse(string(code))
	}
	if lexer == nil {
		return "", false
	}
	lexer = chroma.Coalesce(lexer)
	it, err := lexer.Tokenise(nil, string(code))
	if err != nil {
		return "", false
	}
	var buf bytes.Buffer
	if err := formatter.Format(&buf, styles.Get("github"), it); err != nil {
		return "", false
	}
	return buf.String(), true
}

// CSS returns the chroma class rules for both themes: light rules bare,
// dark rules inside a prefers-color-scheme block — matching the page
// layout's theming (0002 §4 item 5: both themes).
func CSS() string {
	var light, dark strings.Builder
	formatter.WriteCSS(&light, styles.Get("github"))
	formatter.WriteCSS(&dark, styles.Get("github-dark"))
	return light.String() +
		"\n@media (prefers-color-scheme: dark) {\n" + dark.String() + "\n}\n"
}