@@ -2,6 +2,7 @@ package common
4 "image/color"
4 "image/color"
6 "charm.land/glamour/v2"
7 "charm.land/glamour/v2"
7 "github.com/alecthomas/chroma/v2/formatters"
8 "github.com/alecthomas/chroma/v2/formatters"
@@ -18,24 +19,55 @@ func init() {
18 formatters.Register(formatterName, xchroma.Formatter(zero, nil))
19 formatters.Register(formatterName, xchroma.Formatter(zero, nil))
24+ mdCache = map[int]*glamour.TermRenderer{}
25+ quietMDCache = map[int]*glamour.TermRenderer{}
21// MarkdownRenderer returns a glamour [glamour.TermRenderer] configured with
28// MarkdownRenderer returns a glamour [glamour.TermRenderer] configured with
22−// the given styles and width.
29+// the given styles and width. Renderers are memoized per width and shared
30+// across callers; call InvalidateMarkdownRendererCache when the active
23func MarkdownRenderer(sty *styles.Styles, width int) *glamour.TermRenderer {
32func MarkdownRenderer(sty *styles.Styles, width int) *glamour.TermRenderer {
34+ defer mdCacheMu.Unlock()
35+ if r, ok := mdCache[width]; ok {
24 r, _ := glamour.NewTermRenderer(
38 r, _ := glamour.NewTermRenderer(
25 glamour.WithStyles(sty.Markdown),
39 glamour.WithStyles(sty.Markdown),
26 glamour.WithWordWrap(width),
40 glamour.WithWordWrap(width),
27 glamour.WithChromaFormatter(formatterName),
41 glamour.WithChromaFormatter(formatterName),
32// QuietMarkdownRenderer returns a glamour [glamour.TermRenderer] with no colors
47// QuietMarkdownRenderer returns a glamour [glamour.TermRenderer] with no colors
33−// (plain text with structure) and the given width.
48+// (plain text with structure) and the given width. Renderers are memoized per
49+// width and shared across callers.
34func QuietMarkdownRenderer(sty *styles.Styles, width int) *glamour.TermRenderer {
50func QuietMarkdownRenderer(sty *styles.Styles, width int) *glamour.TermRenderer {
52+ defer mdCacheMu.Unlock()
53+ if r, ok := quietMDCache[width]; ok {
35 r, _ := glamour.NewTermRenderer(
56 r, _ := glamour.NewTermRenderer(
36 glamour.WithStyles(sty.QuietMarkdown),
57 glamour.WithStyles(sty.QuietMarkdown),
37 glamour.WithWordWrap(width),
58 glamour.WithWordWrap(width),
38 glamour.WithChromaFormatter(formatterName),
59 glamour.WithChromaFormatter(formatterName),
61+ quietMDCache[width] = r
65+// InvalidateMarkdownRendererCache drops every cached renderer. Call this
66+// whenever the active styles change so subsequent renderers pick up the new
68+func InvalidateMarkdownRendererCache() {
70+ defer mdCacheMu.Unlock()
71+ mdCache = map[int]*glamour.TermRenderer{}
72+ quietMDCache = map[int]*glamour.TermRenderer{}