renderer.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package markdown
  2. import (
  3. "fmt"
  4. "io"
  5. "github.com/diamondburned/ningen/v3/discordmd"
  6. "github.com/yuin/goldmark/ast"
  7. gmr "github.com/yuin/goldmark/renderer"
  8. )
  9. var (
  10. DefaultRenderer = newRenderer()
  11. )
  12. type renderer struct {
  13. config *gmr.Config
  14. }
  15. func newRenderer() *renderer {
  16. config := gmr.NewConfig()
  17. return &renderer{config}
  18. }
  19. // AddOptions implements renderer.Renderer.
  20. func (r *renderer) AddOptions(opts ...gmr.Option) {
  21. for _, opt := range opts {
  22. opt.SetConfig(r.config)
  23. }
  24. }
  25. func (r *renderer) Render(w io.Writer, source []byte, n ast.Node) error {
  26. return ast.Walk(n, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
  27. switch n := n.(type) {
  28. case *ast.Document:
  29. // noop
  30. case *ast.Heading:
  31. io.WriteString(w, "\n")
  32. case *ast.FencedCodeBlock:
  33. io.WriteString(w, "\n")
  34. if entering {
  35. // body
  36. for i := 0; i < n.Lines().Len(); i++ {
  37. line := n.Lines().At(i)
  38. io.WriteString(w, "| ")
  39. w.Write(line.Value(source))
  40. }
  41. }
  42. case *ast.AutoLink:
  43. if entering {
  44. linkColor := r.config.Options["linkColor"].(string)
  45. io.WriteString(w, "["+linkColor+"]")
  46. w.Write(n.URL(source))
  47. } else {
  48. io.WriteString(w, "[-::]")
  49. }
  50. case *ast.Link:
  51. if entering {
  52. linkColor := r.config.Options["linkColor"].(string)
  53. io.WriteString(w, fmt.Sprintf("[%s:::%s]", linkColor, n.Destination))
  54. } else {
  55. io.WriteString(w, "[-:::-]")
  56. }
  57. case *ast.Text:
  58. if entering {
  59. w.Write(n.Segment.Value(source))
  60. switch {
  61. case n.HardLineBreak():
  62. io.WriteString(w, "\n\n")
  63. case n.SoftLineBreak():
  64. io.WriteString(w, "\n")
  65. }
  66. }
  67. case *discordmd.Inline:
  68. if entering {
  69. switch n.Attr {
  70. case discordmd.AttrBold:
  71. io.WriteString(w, "[::b]")
  72. case discordmd.AttrItalics:
  73. io.WriteString(w, "[::i]")
  74. case discordmd.AttrUnderline:
  75. io.WriteString(w, "[::u]")
  76. case discordmd.AttrStrikethrough:
  77. io.WriteString(w, "[::s]")
  78. case discordmd.AttrMonospace:
  79. io.WriteString(w, "[::r]")
  80. }
  81. } else {
  82. io.WriteString(w, "[::-]")
  83. }
  84. case *discordmd.Mention:
  85. if entering {
  86. io.WriteString(w, "[::b]")
  87. switch {
  88. case n.Channel != nil:
  89. io.WriteString(w, "#"+n.Channel.Name)
  90. case n.GuildUser != nil:
  91. io.WriteString(w, "@"+n.GuildUser.Username)
  92. case n.GuildRole != nil:
  93. io.WriteString(w, "@"+n.GuildRole.Name)
  94. }
  95. } else {
  96. io.WriteString(w, "[::-]")
  97. }
  98. case *discordmd.Emoji:
  99. if entering {
  100. emojiColor := r.config.Options["emojiColor"].(string)
  101. io.WriteString(w, "["+emojiColor+"]")
  102. io.WriteString(w, ":"+n.Name+":")
  103. } else {
  104. io.WriteString(w, "[::-]")
  105. }
  106. }
  107. return ast.WalkContinue, nil
  108. })
  109. }