1package common
2
3import (
4 "strings"
5
6 "github.com/alecthomas/chroma/lexers"
7 "github.com/charmbracelet/glamour"
8 gansi "github.com/charmbracelet/glamour/ansi"
9 "github.com/muesli/termenv"
10)
11
12var (
13 RenderCtx = DefaultRenderCtx()
14 Styles = DefaultStyles()
15)
16
17func DefaultStyles() gansi.StyleConfig {
18 noColor := ""
19 s := glamour.DarkStyleConfig
20 s.Document.StylePrimitive.Color = &noColor
21 s.CodeBlock.Chroma.Text.Color = &noColor
22 s.CodeBlock.Chroma.Name.Color = &noColor
23 return s
24}
25
26func DefaultRenderCtx() gansi.RenderContext {
27 return gansi.NewRenderContext(gansi.Options{
28 ColorProfile: termenv.TrueColor,
29 Styles: DefaultStyles(),
30 })
31}
32
33func NewRenderCtx(worldwrap int) gansi.RenderContext {
34 return gansi.NewRenderContext(gansi.Options{
35 ColorProfile: termenv.TrueColor,
36 Styles: DefaultStyles(),
37 WordWrap: worldwrap,
38 })
39}
40
41func Glamourize(w int, md string) (string, error) {
42 if w > GlamourMaxWidth {
43 w = GlamourMaxWidth
44 }
45 tr, err := glamour.NewTermRenderer(
46 glamour.WithStyles(DefaultStyles()),
47 glamour.WithWordWrap(w),
48 )
49
50 if err != nil {
51 return "", err
52 }
53 mdt, err := tr.Render(md)
54 if err != nil {
55 return "", err
56 }
57 return mdt, nil
58}
59
60func RenderFile(path, content string, width int) (string, error) {
61 lexer := lexers.Fallback
62 if path == "" {
63 lexer = lexers.Analyse(content)
64 } else {
65 lexer = lexers.Match(path)
66 }
67 lang := ""
68 if lexer != nil && lexer.Config() != nil {
69 lang = lexer.Config().Name
70 }
71 formatter := &gansi.CodeBlockElement{
72 Code: content,
73 Language: lang,
74 }
75 if lang == "markdown" {
76 md, err := Glamourize(width, content)
77 if err != nil {
78 return "", err
79 }
80 return md, nil
81 }
82 r := strings.Builder{}
83 err := formatter.Render(&r, RenderCtx)
84 if err != nil {
85 return "", err
86 }
87 return r.String(), nil
88}