1package common
2
3import (
4 "image/color"
5 "sync"
6
7 "charm.land/glamour/v2"
8 "github.com/alecthomas/chroma/v2/formatters"
9 "github.com/charmbracelet/crush/internal/ui/styles"
10 "github.com/charmbracelet/crush/internal/ui/xchroma"
11)
12
13const formatterName = "crush"
14
15func init() {
16 // NOTE: Glamour does not offer us an option to pass the formatter
17 // implementation directly. We need to register and use by name.
18 var zero color.Color
19 formatters.Register(formatterName, xchroma.Formatter(zero, nil))
20}
21
22var (
23 mdCacheMu sync.Mutex
24 mdCache = map[int]*glamour.TermRenderer{}
25 quietMDCache = map[int]*glamour.TermRenderer{}
26)
27
28// MarkdownRenderer returns a glamour [glamour.TermRenderer] configured with
29// the given styles and width. Renderers are memoized per width and shared
30// across callers; call InvalidateMarkdownRendererCache when the active
31// styles change.
32func MarkdownRenderer(sty *styles.Styles, width int) *glamour.TermRenderer {
33 mdCacheMu.Lock()
34 defer mdCacheMu.Unlock()
35 if r, ok := mdCache[width]; ok {
36 return r
37 }
38 r, _ := glamour.NewTermRenderer(
39 glamour.WithStyles(sty.Markdown),
40 glamour.WithWordWrap(width),
41 glamour.WithChromaFormatter(formatterName),
42 )
43 mdCache[width] = r
44 return r
45}
46
47// QuietMarkdownRenderer returns a glamour [glamour.TermRenderer] with no colors
48// (plain text with structure) and the given width. Renderers are memoized per
49// width and shared across callers.
50func QuietMarkdownRenderer(sty *styles.Styles, width int) *glamour.TermRenderer {
51 mdCacheMu.Lock()
52 defer mdCacheMu.Unlock()
53 if r, ok := quietMDCache[width]; ok {
54 return r
55 }
56 r, _ := glamour.NewTermRenderer(
57 glamour.WithStyles(sty.QuietMarkdown),
58 glamour.WithWordWrap(width),
59 glamour.WithChromaFormatter(formatterName),
60 )
61 quietMDCache[width] = r
62 return r
63}
64
65// InvalidateMarkdownRendererCache drops every cached renderer. Call this
66// whenever the active styles change so subsequent renderers pick up the new
67// ansi.StyleConfig.
68func InvalidateMarkdownRendererCache() {
69 mdCacheMu.Lock()
70 defer mdCacheMu.Unlock()
71 mdCache = map[int]*glamour.TermRenderer{}
72 quietMDCache = map[int]*glamour.TermRenderer{}
73}