renderer.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // Package renderer renders the given AST to certain formats.
  2. package renderer
  3. import (
  4. "bufio"
  5. "io"
  6. "sync"
  7. "github.com/yuin/goldmark/ast"
  8. "github.com/yuin/goldmark/util"
  9. )
  10. // A Config struct is a data structure that holds configuration of the Renderer.
  11. type Config struct {
  12. Options map[OptionName]interface{}
  13. NodeRenderers util.PrioritizedSlice
  14. }
  15. // NewConfig returns a new Config.
  16. func NewConfig() *Config {
  17. return &Config{
  18. Options: map[OptionName]interface{}{},
  19. NodeRenderers: util.PrioritizedSlice{},
  20. }
  21. }
  22. // An OptionName is a name of the option.
  23. type OptionName string
  24. // An Option interface is a functional option type for the Renderer.
  25. type Option interface {
  26. SetConfig(*Config)
  27. }
  28. type withNodeRenderers struct {
  29. value []util.PrioritizedValue
  30. }
  31. func (o *withNodeRenderers) SetConfig(c *Config) {
  32. c.NodeRenderers = append(c.NodeRenderers, o.value...)
  33. }
  34. // WithNodeRenderers is a functional option that allow you to add
  35. // NodeRenderers to the renderer.
  36. func WithNodeRenderers(ps ...util.PrioritizedValue) Option {
  37. return &withNodeRenderers{ps}
  38. }
  39. type withOption struct {
  40. name OptionName
  41. value interface{}
  42. }
  43. func (o *withOption) SetConfig(c *Config) {
  44. c.Options[o.name] = o.value
  45. }
  46. // WithOption is a functional option that allow you to set
  47. // an arbitrary option to the parser.
  48. func WithOption(name OptionName, value interface{}) Option {
  49. return &withOption{name, value}
  50. }
  51. // A SetOptioner interface sets given option to the object.
  52. type SetOptioner interface {
  53. // SetOption sets given option to the object.
  54. // Unacceptable options may be passed.
  55. // Thus implementations must ignore unacceptable options.
  56. SetOption(name OptionName, value interface{})
  57. }
  58. // NodeRendererFunc is a function that renders a given node.
  59. type NodeRendererFunc func(writer util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error)
  60. // A NodeRenderer interface offers NodeRendererFuncs.
  61. type NodeRenderer interface {
  62. // RendererFuncs registers NodeRendererFuncs to given NodeRendererFuncRegisterer.
  63. RegisterFuncs(NodeRendererFuncRegisterer)
  64. }
  65. // A NodeRendererFuncRegisterer registers given NodeRendererFunc to this object.
  66. type NodeRendererFuncRegisterer interface {
  67. // Register registers given NodeRendererFunc to this object.
  68. Register(ast.NodeKind, NodeRendererFunc)
  69. }
  70. // A Renderer interface renders given AST node to given
  71. // writer with given Renderer.
  72. type Renderer interface {
  73. Render(w io.Writer, source []byte, n ast.Node) error
  74. // AddOptions adds given option to this renderer.
  75. AddOptions(...Option)
  76. }
  77. type renderer struct {
  78. config *Config
  79. options map[OptionName]interface{}
  80. nodeRendererFuncsTmp map[ast.NodeKind]NodeRendererFunc
  81. maxKind int
  82. nodeRendererFuncs []NodeRendererFunc
  83. initSync sync.Once
  84. }
  85. // NewRenderer returns a new Renderer with given options.
  86. func NewRenderer(options ...Option) Renderer {
  87. config := NewConfig()
  88. for _, opt := range options {
  89. opt.SetConfig(config)
  90. }
  91. r := &renderer{
  92. options: map[OptionName]interface{}{},
  93. config: config,
  94. nodeRendererFuncsTmp: map[ast.NodeKind]NodeRendererFunc{},
  95. }
  96. return r
  97. }
  98. func (r *renderer) AddOptions(opts ...Option) {
  99. for _, opt := range opts {
  100. opt.SetConfig(r.config)
  101. }
  102. }
  103. func (r *renderer) Register(kind ast.NodeKind, v NodeRendererFunc) {
  104. r.nodeRendererFuncsTmp[kind] = v
  105. if int(kind) > r.maxKind {
  106. r.maxKind = int(kind)
  107. }
  108. }
  109. // Render renders the given AST node to the given writer with the given Renderer.
  110. func (r *renderer) Render(w io.Writer, source []byte, n ast.Node) error {
  111. r.initSync.Do(func() {
  112. r.options = r.config.Options
  113. r.config.NodeRenderers.Sort()
  114. l := len(r.config.NodeRenderers)
  115. for i := l - 1; i >= 0; i-- {
  116. v := r.config.NodeRenderers[i]
  117. nr, _ := v.Value.(NodeRenderer)
  118. if se, ok := v.Value.(SetOptioner); ok {
  119. for oname, ovalue := range r.options {
  120. se.SetOption(oname, ovalue)
  121. }
  122. }
  123. nr.RegisterFuncs(r)
  124. }
  125. r.nodeRendererFuncs = make([]NodeRendererFunc, r.maxKind+1)
  126. for kind, nr := range r.nodeRendererFuncsTmp {
  127. r.nodeRendererFuncs[kind] = nr
  128. }
  129. r.config = nil
  130. r.nodeRendererFuncsTmp = nil
  131. })
  132. writer, ok := w.(util.BufWriter)
  133. if !ok {
  134. writer = bufio.NewWriter(w)
  135. }
  136. err := ast.Walk(n, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
  137. s := ast.WalkStatus(ast.WalkContinue)
  138. var err error
  139. f := r.nodeRendererFuncs[n.Kind()]
  140. if f != nil {
  141. s, err = f(writer, source, n, entering)
  142. }
  143. return s, err
  144. })
  145. if err != nil {
  146. return err
  147. }
  148. return writer.Flush()
  149. }