package markdown import ( "bytes" "sync" "github.com/yuin/goldmark" emoji "github.com/yuin/goldmark-emoji" highlighting "github.com/yuin/goldmark-highlighting/v2" "github.com/yuin/goldmark/extension" "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/renderer/html" ) var ( renderers = make(map[string]goldmark.Markdown) renderersMu sync.RWMutex ) func getRenderer(codeTheme string) goldmark.Markdown { if codeTheme == "" { codeTheme = "github" } renderersMu.RLock() if md, ok := renderers[codeTheme]; ok { renderersMu.RUnlock() return md } renderersMu.RUnlock() renderersMu.Lock() defer renderersMu.Unlock() if md, ok := renderers[codeTheme]; ok { return md } md := goldmark.New( goldmark.WithExtensions( extension.GFM, extension.Typographer, emoji.Emoji, highlighting.NewHighlighting( highlighting.WithStyle(codeTheme), ), ), goldmark.WithParserOptions( parser.WithAutoHeadingID(), ), goldmark.WithRendererOptions( html.WithHardWraps(), html.WithXHTML(), html.WithUnsafe(), ), ) renderers[codeTheme] = md return md } func Render(source string) (string, error) { return RenderWithTheme(source, "github") } func RenderWithTheme(source, codeTheme string) (string, error) { md := getRenderer(codeTheme) var buf bytes.Buffer if err := md.Convert([]byte(source), &buf); err != nil { return "", err } return buf.String(), nil }