renderer.go 3.1 KB

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