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