template.go (7385B)
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package template
6
7 import (
8 "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse"
9 "reflect"
10 "sync"
11 )
12
13 // common holds the information shared by related templates.
14 type common struct {
15 tmpl map[string]*Template // Map from name to defined templates.
16 muTmpl sync.RWMutex // protects tmpl
17 option option
18 // We use two maps, one for parsing and one for execution.
19 // This separation makes the API cleaner since it doesn't
20 // expose reflection to the client.
21 muFuncs sync.RWMutex // protects parseFuncs and execFuncs
22 parseFuncs FuncMap
23 execFuncs map[string]reflect.Value
24 }
25
26 // Template is the representation of a parsed template. The *parse.Tree
27 // field is exported only for use by html/template and should be treated
28 // as unexported by all other clients.
29 type Template struct {
30 name string
31 *parse.Tree
32 *common
33 leftDelim string
34 rightDelim string
35 }
36
37 // New allocates a new, undefined template with the given name.
38 func New(name string) *Template {
39 t := &Template{
40 name: name,
41 }
42 t.init()
43 return t
44 }
45
46 // Name returns the name of the template.
47 func (t *Template) Name() string {
48 return t.name
49 }
50
51 // New allocates a new, undefined template associated with the given one and with the same
52 // delimiters. The association, which is transitive, allows one template to
53 // invoke another with a {{template}} action.
54 //
55 // Because associated templates share underlying data, template construction
56 // cannot be done safely in parallel. Once the templates are constructed, they
57 // can be executed in parallel.
58 func (t *Template) New(name string) *Template {
59 t.init()
60 nt := &Template{
61 name: name,
62 common: t.common,
63 leftDelim: t.leftDelim,
64 rightDelim: t.rightDelim,
65 }
66 return nt
67 }
68
69 // init guarantees that t has a valid common structure.
70 func (t *Template) init() {
71 if t.common == nil {
72 c := new(common)
73 c.tmpl = make(map[string]*Template)
74 c.parseFuncs = make(FuncMap)
75 c.execFuncs = make(map[string]reflect.Value)
76 t.common = c
77 }
78 }
79
80 // Clone returns a duplicate of the template, including all associated
81 // templates. The actual representation is not copied, but the name space of
82 // associated templates is, so further calls to Parse in the copy will add
83 // templates to the copy but not to the original. Clone can be used to prepare
84 // common templates and use them with variant definitions for other templates
85 // by adding the variants after the clone is made.
86 func (t *Template) Clone() (*Template, error) {
87 nt := t.copy(nil)
88 nt.init()
89 if t.common == nil {
90 return nt, nil
91 }
92 t.muTmpl.RLock()
93 defer t.muTmpl.RUnlock()
94 for k, v := range t.tmpl {
95 if k == t.name {
96 nt.tmpl[t.name] = nt
97 continue
98 }
99 // The associated templates share nt's common structure.
100 tmpl := v.copy(nt.common)
101 nt.tmpl[k] = tmpl
102 }
103 t.muFuncs.RLock()
104 defer t.muFuncs.RUnlock()
105 for k, v := range t.parseFuncs {
106 nt.parseFuncs[k] = v
107 }
108 for k, v := range t.execFuncs {
109 nt.execFuncs[k] = v
110 }
111 return nt, nil
112 }
113
114 // copy returns a shallow copy of t, with common set to the argument.
115 func (t *Template) copy(c *common) *Template {
116 return &Template{
117 name: t.name,
118 Tree: t.Tree,
119 common: c,
120 leftDelim: t.leftDelim,
121 rightDelim: t.rightDelim,
122 }
123 }
124
125 // AddParseTree associates the argument parse tree with the template t, giving
126 // it the specified name. If the template has not been defined, this tree becomes
127 // its definition. If it has been defined and already has that name, the existing
128 // definition is replaced; otherwise a new template is created, defined, and returned.
129 func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
130 t.init()
131 t.muTmpl.Lock()
132 defer t.muTmpl.Unlock()
133 nt := t
134 if name != t.name {
135 nt = t.New(name)
136 }
137 // Even if nt == t, we need to install it in the common.tmpl map.
138 if t.associate(nt, tree) || nt.Tree == nil {
139 nt.Tree = tree
140 }
141 return nt, nil
142 }
143
144 // Templates returns a slice of defined templates associated with t.
145 func (t *Template) Templates() []*Template {
146 if t.common == nil {
147 return nil
148 }
149 // Return a slice so we don't expose the map.
150 t.muTmpl.RLock()
151 defer t.muTmpl.RUnlock()
152 m := make([]*Template, 0, len(t.tmpl))
153 for _, v := range t.tmpl {
154 m = append(m, v)
155 }
156 return m
157 }
158
159 // Delims sets the action delimiters to the specified strings, to be used in
160 // subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template
161 // definitions will inherit the settings. An empty delimiter stands for the
162 // corresponding default: {{ or }}.
163 // The return value is the template, so calls can be chained.
164 func (t *Template) Delims(left, right string) *Template {
165 t.init()
166 t.leftDelim = left
167 t.rightDelim = right
168 return t
169 }
170
171 // Funcs adds the elements of the argument map to the template's function map.
172 // It must be called before the template is parsed.
173 // It panics if a value in the map is not a function with appropriate return
174 // type or if the name cannot be used syntactically as a function in a template.
175 // It is legal to overwrite elements of the map. The return value is the template,
176 // so calls can be chained.
177 func (t *Template) Funcs(funcMap FuncMap) *Template {
178 t.init()
179 t.muFuncs.Lock()
180 defer t.muFuncs.Unlock()
181 addValueFuncs(t.execFuncs, funcMap)
182 addFuncs(t.parseFuncs, funcMap)
183 return t
184 }
185
186 // Lookup returns the template with the given name that is associated with t.
187 // It returns nil if there is no such template or the template has no definition.
188 func (t *Template) Lookup(name string) *Template {
189 if t.common == nil {
190 return nil
191 }
192 t.muTmpl.RLock()
193 defer t.muTmpl.RUnlock()
194 return t.tmpl[name]
195 }
196
197 // Parse parses text as a template body for t.
198 // Named template definitions ({{define ...}} or {{block ...}} statements) in text
199 // define additional templates associated with t and are removed from the
200 // definition of t itself.
201 //
202 // Templates can be redefined in successive calls to Parse.
203 // A template definition with a body containing only white space and comments
204 // is considered empty and will not replace an existing template's body.
205 // This allows using Parse to add new named template definitions without
206 // overwriting the main template body.
207 func (t *Template) Parse(text string) (*Template, error) {
208 t.init()
209 t.muFuncs.RLock()
210 trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins())
211 t.muFuncs.RUnlock()
212 if err != nil {
213 return nil, err
214 }
215 // Add the newly parsed trees, including the one for t, into our common structure.
216 for name, tree := range trees {
217 if _, err := t.AddParseTree(name, tree); err != nil {
218 return nil, err
219 }
220 }
221 return t, nil
222 }
223
224 // associate installs the new template into the group of templates associated
225 // with t. The two are already known to share the common structure.
226 // The boolean return value reports whether to store this tree as t.Tree.
227 func (t *Template) associate(new *Template, tree *parse.Tree) bool {
228 if new.common != t.common {
229 panic("internal error: associate not common")
230 }
231 if old := t.tmpl[new.name]; old != nil && parse.IsEmptyTree(tree.Root) && old.Tree != nil {
232 // If a template by that name exists,
233 // don't replace it with an empty template.
234 return false
235 }
236 t.tmpl[new.name] = new
237 return true
238 }