Bläddra i källkod

refactor(markdown): export renderer and use type-safe config

ayn2op 5 månader sedan
förälder
incheckning
de52554f95
2 ändrade filer med 30 tillägg och 35 borttagningar
  1. 4 4
      cmd/messages_list.go
  2. 26 31
      internal/markdown/renderer.go

+ 4 - 4
cmd/messages_list.go

@@ -29,7 +29,6 @@ import (
 	"github.com/skratchdot/open-golang/open"
 	"github.com/yuin/goldmark/ast"
 	"github.com/yuin/goldmark/parser"
-	"github.com/yuin/goldmark/renderer"
 	"github.com/yuin/goldmark/text"
 	"golang.design/x/clipboard"
 )
@@ -39,6 +38,8 @@ type messagesList struct {
 	cfg               *config.Config
 	selectedMessageID discord.MessageID
 
+	renderer *markdown.Renderer
+
 	fetchingMembers struct {
 		mu    sync.Mutex
 		value bool
@@ -51,6 +52,7 @@ func newMessagesList(cfg *config.Config) *messagesList {
 	ml := &messagesList{
 		TextView: tview.NewTextView(),
 		cfg:      cfg,
+		renderer: markdown.NewRenderer(cfg.Theme.MessagesList),
 	}
 
 	ml.Box = ui.ConfigureBox(ml.Box, &cfg.Theme)
@@ -62,8 +64,6 @@ func newMessagesList(cfg *config.Config) *messagesList {
 		SetHighlightedFunc(ml.onHighlighted).
 		SetTitle("Messages").
 		SetInputCapture(ml.onInputCapture)
-
-	markdown.DefaultRenderer.AddOptions(renderer.WithOption("theme", cfg.Theme))
 	return ml
 }
 
@@ -168,7 +168,7 @@ func (ml *messagesList) drawContent(message discord.Message) {
 	c := []byte(tview.Escape(message.Content))
 	if app.cfg.Markdown {
 		ast := discordmd.ParseWithMessage(c, *discordState.Cabinet, &message, false)
-		markdown.DefaultRenderer.Render(ml, c, ast)
+		ml.renderer.Render(ml, c, ast)
 	} else {
 		ml.Write(c) // write the content as is
 	}

+ 26 - 31
internal/markdown/renderer.go

@@ -10,34 +10,24 @@ import (
 	"github.com/ayn2op/discordo/internal/config"
 	"github.com/ayn2op/tview"
 	"github.com/diamondburned/ningen/v3/discordmd"
-	"github.com/gdamore/tcell/v2"
 	"github.com/yuin/goldmark/ast"
 	gmr "github.com/yuin/goldmark/renderer"
 )
 
-var DefaultRenderer = newRenderer()
-
-type renderer struct {
-	config *gmr.Config
+type Renderer struct {
+	theme config.MessagesListTheme
 
 	listIx     *int
 	listNested int
 }
 
-func newRenderer() *renderer {
-	config := gmr.NewConfig()
-	return &renderer{config: config}
+func NewRenderer(theme config.MessagesListTheme) *Renderer {
+	return &Renderer{theme: theme}
 }
 
-// AddOptions implements renderer.Renderer.
-func (r *renderer) AddOptions(opts ...gmr.Option) {
-	for _, opt := range opts {
-		opt.SetConfig(r.config)
-	}
-}
+func (r *Renderer) AddOptions(opts ...gmr.Option) {}
 
-func (r *renderer) Render(w io.Writer, source []byte, node ast.Node) error {
-	theme := r.config.Options["theme"].(config.Theme)
+func (r *Renderer) Render(w io.Writer, source []byte, node ast.Node) error {
 	return ast.Walk(node, func(node ast.Node, entering bool) (ast.WalkStatus, error) {
 		switch node := node.(type) {
 		case *ast.Document:
@@ -49,9 +39,9 @@ func (r *renderer) Render(w io.Writer, source []byte, node ast.Node) error {
 		case *ast.FencedCodeBlock:
 			r.renderFencedCodeBlock(w, node, entering, source)
 		case *ast.AutoLink:
-			r.renderAutoLink(w, node, entering, source, theme.MessagesList.URLStyle.Style)
+			r.renderAutoLink(w, node, entering, source)
 		case *ast.Link:
-			r.renderLink(w, node, entering, theme.MessagesList.URLStyle.Style)
+			r.renderLink(w, node, entering)
 		case *ast.List:
 			r.renderList(w, node, entering)
 		case *ast.ListItem:
@@ -60,16 +50,16 @@ func (r *renderer) Render(w io.Writer, source []byte, node ast.Node) error {
 		case *discordmd.Inline:
 			r.renderInline(w, node, entering)
 		case *discordmd.Mention:
-			r.renderMention(w, node, entering, theme.MessagesList.MentionStyle.Style)
+			r.renderMention(w, node, entering)
 		case *discordmd.Emoji:
-			r.renderEmoji(w, node, entering, theme.MessagesList.EmojiStyle.Style)
+			r.renderEmoji(w, node, entering)
 		}
 
 		return ast.WalkContinue, nil
 	})
 }
 
-func (r *renderer) renderHeading(w io.Writer, node *ast.Heading, entering bool) {
+func (r *Renderer) renderHeading(w io.Writer, node *ast.Heading, entering bool) {
 	if entering {
 		io.WriteString(w, strings.Repeat("#", node.Level))
 		io.WriteString(w, " ")
@@ -78,7 +68,7 @@ func (r *renderer) renderHeading(w io.Writer, node *ast.Heading, entering bool)
 	}
 }
 
-func (r *renderer) renderFencedCodeBlock(w io.Writer, node *ast.FencedCodeBlock, entering bool, source []byte) {
+func (r *Renderer) renderFencedCodeBlock(w io.Writer, node *ast.FencedCodeBlock, entering bool, source []byte) {
 	io.WriteString(w, tview.NewLine)
 
 	if entering {
@@ -99,7 +89,9 @@ func (r *renderer) renderFencedCodeBlock(w io.Writer, node *ast.FencedCodeBlock,
 	}
 }
 
-func (r *renderer) renderAutoLink(w io.Writer, node *ast.AutoLink, entering bool, source []byte, urlStyle tcell.Style) {
+func (r *Renderer) renderAutoLink(w io.Writer, node *ast.AutoLink, entering bool, source []byte) {
+	urlStyle := r.theme.URLStyle
+
 	if entering {
 		fg, bg, _ := urlStyle.Decompose()
 		fmt.Fprintf(w, "[%s:%s]", fg, bg)
@@ -109,7 +101,8 @@ func (r *renderer) renderAutoLink(w io.Writer, node *ast.AutoLink, entering bool
 	}
 }
 
-func (r *renderer) renderLink(w io.Writer, node *ast.Link, entering bool, urlStyle tcell.Style) {
+func (r *Renderer) renderLink(w io.Writer, node *ast.Link, entering bool) {
+	urlStyle := r.theme.URLStyle
 	if entering {
 		fg, bg, _ := urlStyle.Decompose()
 		fmt.Fprintf(w, "[%s:%s::%s]", fg, bg, node.Destination)
@@ -118,7 +111,7 @@ func (r *renderer) renderLink(w io.Writer, node *ast.Link, entering bool, urlSty
 	}
 }
 
-func (r *renderer) renderList(w io.Writer, node *ast.List, entering bool) {
+func (r *Renderer) renderList(w io.Writer, node *ast.List, entering bool) {
 	if node.IsOrdered() {
 		r.listIx = &node.Start
 	} else {
@@ -133,7 +126,7 @@ func (r *renderer) renderList(w io.Writer, node *ast.List, entering bool) {
 	}
 }
 
-func (r *renderer) renderListItem(w io.Writer, entering bool) {
+func (r *Renderer) renderListItem(w io.Writer, entering bool) {
 	if entering {
 		io.WriteString(w, strings.Repeat("  ", r.listNested-1))
 
@@ -149,7 +142,7 @@ func (r *renderer) renderListItem(w io.Writer, entering bool) {
 	}
 }
 
-func (r *renderer) renderText(w io.Writer, node *ast.Text, entering bool, source []byte) {
+func (r *Renderer) renderText(w io.Writer, node *ast.Text, entering bool, source []byte) {
 	if entering {
 		w.Write(node.Segment.Value(source))
 		switch {
@@ -160,7 +153,7 @@ func (r *renderer) renderText(w io.Writer, node *ast.Text, entering bool, source
 		}
 	}
 }
-func (r *renderer) renderInline(w io.Writer, node *discordmd.Inline, entering bool) {
+func (r *Renderer) renderInline(w io.Writer, node *discordmd.Inline, entering bool) {
 	if start, end := attrToTag(node.Attr); entering && start != "" {
 		io.WriteString(w, start)
 	} else {
@@ -168,9 +161,10 @@ func (r *renderer) renderInline(w io.Writer, node *discordmd.Inline, entering bo
 	}
 }
 
-func (r *renderer) renderMention(w io.Writer, node *discordmd.Mention, entering bool, style tcell.Style) {
+func (r *Renderer) renderMention(w io.Writer, node *discordmd.Mention, entering bool) {
+	mentionStyle := r.theme.MentionStyle
 	if entering {
-		fg, bg, _ := style.Decompose()
+		fg, bg, _ := mentionStyle.Decompose()
 		fmt.Fprintf(w, "[%s:%s:b]", fg, bg)
 
 		switch {
@@ -191,7 +185,8 @@ func (r *renderer) renderMention(w io.Writer, node *discordmd.Mention, entering
 	}
 }
 
-func (r *renderer) renderEmoji(w io.Writer, node *discordmd.Emoji, entering bool, emojiStyle tcell.Style) {
+func (r *Renderer) renderEmoji(w io.Writer, node *discordmd.Emoji, entering bool) {
+	emojiStyle := r.theme.EmojiStyle
 	if entering {
 		fg, bg, _ := emojiStyle.Decompose()
 		fmt.Fprintf(w, "[%s:%s]", fg, bg)