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}