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}