highlight.go

 1package common
 2
 3import (
 4	"bytes"
 5	"image/color"
 6
 7	"github.com/alecthomas/chroma/v2"
 8	"github.com/alecthomas/chroma/v2/formatters"
 9	"github.com/alecthomas/chroma/v2/lexers"
10	chromastyles "github.com/alecthomas/chroma/v2/styles"
11	"github.com/charmbracelet/crush/internal/ui/styles"
12)
13
14// SyntaxHighlight applies syntax highlighting to the given source code based
15// on the file name and background color. It returns the highlighted code as a
16// string.
17func SyntaxHighlight(st *styles.Styles, source, fileName string, bg color.Color) (string, error) {
18	// Determine the language lexer to use
19	l := lexers.Match(fileName)
20	if l == nil {
21		l = lexers.Analyse(source)
22	}
23	if l == nil {
24		l = lexers.Fallback
25	}
26	l = chroma.Coalesce(l)
27
28	// Get the formatter
29	f := formatters.Get("terminal16m")
30	if f == nil {
31		f = formatters.Fallback
32	}
33
34	style := chroma.MustNewStyle("crush", st.ChromaTheme())
35
36	// Modify the style to use the provided background
37	s, err := style.Builder().Transform(
38		func(t chroma.StyleEntry) chroma.StyleEntry {
39			r, g, b, _ := bg.RGBA()
40			t.Background = chroma.NewColour(uint8(r>>8), uint8(g>>8), uint8(b>>8))
41			return t
42		},
43	).Build()
44	if err != nil {
45		s = chromastyles.Fallback
46	}
47
48	// Tokenize and format
49	it, err := l.Tokenise(nil, source)
50	if err != nil {
51		return "", err
52	}
53
54	var buf bytes.Buffer
55	err = f.Format(&buf, s, it)
56	return buf.String(), err
57}