blob: 3e80982123af54136be2d705b2c6b75ebf71f45e [file] [log] [blame]
Brent Austinba3052e2015-04-21 16:08:23 -07001// 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
5package template
6
7import (
8 "fmt"
9 "reflect"
Dan Willemsen09eb3b12015-09-16 14:34:17 -070010 "sync"
Brent Austinba3052e2015-04-21 16:08:23 -070011 "text/template/parse"
12)
13
14// common holds the information shared by related templates.
15type common struct {
Dan Willemsen09eb3b12015-09-16 14:34:17 -070016 tmpl map[string]*Template // Map from name to defined templates.
17 option option
Brent Austinba3052e2015-04-21 16:08:23 -070018 // 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.
Dan Willemsen09eb3b12015-09-16 14:34:17 -070021 muFuncs sync.RWMutex // protects parseFuncs and execFuncs
Brent Austinba3052e2015-04-21 16:08:23 -070022 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.
29type Template struct {
30 name string
31 *parse.Tree
32 *common
33 leftDelim string
34 rightDelim string
35}
36
Dan Willemsen09eb3b12015-09-16 14:34:17 -070037// New allocates a new, undefined template with the given name.
Brent Austinba3052e2015-04-21 16:08:23 -070038func New(name string) *Template {
Dan Willemsen09eb3b12015-09-16 14:34:17 -070039 t := &Template{
Brent Austinba3052e2015-04-21 16:08:23 -070040 name: name,
41 }
Dan Willemsen09eb3b12015-09-16 14:34:17 -070042 t.init()
43 return t
Brent Austinba3052e2015-04-21 16:08:23 -070044}
45
46// Name returns the name of the template.
47func (t *Template) Name() string {
48 return t.name
49}
50
Dan Willemsen09eb3b12015-09-16 14:34:17 -070051// New allocates a new, undefined template associated with the given one and with the same
Brent Austinba3052e2015-04-21 16:08:23 -070052// delimiters. The association, which is transitive, allows one template to
53// invoke another with a {{template}} action.
54func (t *Template) New(name string) *Template {
55 t.init()
Dan Willemsen09eb3b12015-09-16 14:34:17 -070056 nt := &Template{
Brent Austinba3052e2015-04-21 16:08:23 -070057 name: name,
58 common: t.common,
59 leftDelim: t.leftDelim,
60 rightDelim: t.rightDelim,
61 }
Dan Willemsen09eb3b12015-09-16 14:34:17 -070062 return nt
Brent Austinba3052e2015-04-21 16:08:23 -070063}
64
Dan Willemsen09eb3b12015-09-16 14:34:17 -070065// init guarantees that t has a valid common structure.
Brent Austinba3052e2015-04-21 16:08:23 -070066func (t *Template) init() {
67 if t.common == nil {
Dan Willemsen09eb3b12015-09-16 14:34:17 -070068 c := new(common)
69 c.tmpl = make(map[string]*Template)
70 c.parseFuncs = make(FuncMap)
71 c.execFuncs = make(map[string]reflect.Value)
72 t.common = c
Brent Austinba3052e2015-04-21 16:08:23 -070073 }
74}
75
76// Clone returns a duplicate of the template, including all associated
77// templates. The actual representation is not copied, but the name space of
78// associated templates is, so further calls to Parse in the copy will add
79// templates to the copy but not to the original. Clone can be used to prepare
80// common templates and use them with variant definitions for other templates
81// by adding the variants after the clone is made.
82func (t *Template) Clone() (*Template, error) {
83 nt := t.copy(nil)
84 nt.init()
Dan Willemsen09eb3b12015-09-16 14:34:17 -070085 if t.common == nil {
86 return nt, nil
87 }
Brent Austinba3052e2015-04-21 16:08:23 -070088 for k, v := range t.tmpl {
Dan Willemsen09eb3b12015-09-16 14:34:17 -070089 if k == t.name {
90 nt.tmpl[t.name] = nt
Brent Austinba3052e2015-04-21 16:08:23 -070091 continue
92 }
93 // The associated templates share nt's common structure.
94 tmpl := v.copy(nt.common)
95 nt.tmpl[k] = tmpl
96 }
Dan Willemsen09eb3b12015-09-16 14:34:17 -070097 t.muFuncs.RLock()
98 defer t.muFuncs.RUnlock()
Brent Austinba3052e2015-04-21 16:08:23 -070099 for k, v := range t.parseFuncs {
100 nt.parseFuncs[k] = v
101 }
102 for k, v := range t.execFuncs {
103 nt.execFuncs[k] = v
104 }
105 return nt, nil
106}
107
108// copy returns a shallow copy of t, with common set to the argument.
109func (t *Template) copy(c *common) *Template {
110 nt := New(t.name)
111 nt.Tree = t.Tree
112 nt.common = c
113 nt.leftDelim = t.leftDelim
114 nt.rightDelim = t.rightDelim
115 return nt
116}
117
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700118// AddParseTree adds parse tree for template with given name and associates it with t.
119// If the template does not already exist, it will create a new one.
120// It is an error to reuse a name except to overwrite an empty template.
Brent Austinba3052e2015-04-21 16:08:23 -0700121func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700122 t.init()
123 // If the name is the name of this template, overwrite this template.
124 // The associate method checks it's not a redefinition.
125 nt := t
126 if name != t.name {
127 nt = t.New(name)
Brent Austinba3052e2015-04-21 16:08:23 -0700128 }
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700129 // Even if nt == t, we need to install it in the common.tmpl map.
130 if replace, err := t.associate(nt, tree); err != nil {
131 return nil, err
132 } else if replace {
133 nt.Tree = tree
134 }
Brent Austinba3052e2015-04-21 16:08:23 -0700135 return nt, nil
136}
137
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700138// Templates returns a slice of defined templates associated with t.
Brent Austinba3052e2015-04-21 16:08:23 -0700139func (t *Template) Templates() []*Template {
140 if t.common == nil {
141 return nil
142 }
143 // Return a slice so we don't expose the map.
144 m := make([]*Template, 0, len(t.tmpl))
145 for _, v := range t.tmpl {
146 m = append(m, v)
147 }
148 return m
149}
150
151// Delims sets the action delimiters to the specified strings, to be used in
152// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template
153// definitions will inherit the settings. An empty delimiter stands for the
154// corresponding default: {{ or }}.
155// The return value is the template, so calls can be chained.
156func (t *Template) Delims(left, right string) *Template {
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700157 t.init()
Brent Austinba3052e2015-04-21 16:08:23 -0700158 t.leftDelim = left
159 t.rightDelim = right
160 return t
161}
162
163// Funcs adds the elements of the argument map to the template's function map.
164// It panics if a value in the map is not a function with appropriate return
165// type. However, it is legal to overwrite elements of the map. The return
166// value is the template, so calls can be chained.
167func (t *Template) Funcs(funcMap FuncMap) *Template {
168 t.init()
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700169 t.muFuncs.Lock()
170 defer t.muFuncs.Unlock()
Brent Austinba3052e2015-04-21 16:08:23 -0700171 addValueFuncs(t.execFuncs, funcMap)
172 addFuncs(t.parseFuncs, funcMap)
173 return t
174}
175
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700176// Lookup returns the template with the given name that is associated with t.
177// It returns nil if there is no such template or the template has no definition.
Brent Austinba3052e2015-04-21 16:08:23 -0700178func (t *Template) Lookup(name string) *Template {
179 if t.common == nil {
180 return nil
181 }
182 return t.tmpl[name]
183}
184
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700185// Parse defines the template by parsing the text. Nested template definitions will be
Brent Austinba3052e2015-04-21 16:08:23 -0700186// associated with the top-level template t. Parse may be called multiple times
187// to parse definitions of templates to associate with t. It is an error if a
188// resulting template is non-empty (contains content other than template
189// definitions) and would replace a non-empty template with the same name.
190// (In multiple calls to Parse with the same receiver template, only one call
191// can contain text other than space, comments, and template definitions.)
192func (t *Template) Parse(text string) (*Template, error) {
193 t.init()
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700194 t.muFuncs.RLock()
Brent Austinba3052e2015-04-21 16:08:23 -0700195 trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins)
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700196 t.muFuncs.RUnlock()
Brent Austinba3052e2015-04-21 16:08:23 -0700197 if err != nil {
198 return nil, err
199 }
200 // Add the newly parsed trees, including the one for t, into our common structure.
201 for name, tree := range trees {
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700202 if _, err := t.AddParseTree(name, tree); err != nil {
Brent Austinba3052e2015-04-21 16:08:23 -0700203 return nil, err
Brent Austinba3052e2015-04-21 16:08:23 -0700204 }
Brent Austinba3052e2015-04-21 16:08:23 -0700205 }
206 return t, nil
207}
208
209// associate installs the new template into the group of templates associated
210// with t. It is an error to reuse a name except to overwrite an empty
211// template. The two are already known to share the common structure.
212// The boolean return value reports wither to store this tree as t.Tree.
213func (t *Template) associate(new *Template, tree *parse.Tree) (bool, error) {
214 if new.common != t.common {
215 panic("internal error: associate not common")
216 }
217 name := new.name
218 if old := t.tmpl[name]; old != nil {
219 oldIsEmpty := parse.IsEmptyTree(old.Root)
220 newIsEmpty := parse.IsEmptyTree(tree.Root)
221 if newIsEmpty {
222 // Whether old is empty or not, new is empty; no reason to replace old.
223 return false, nil
224 }
225 if !oldIsEmpty {
226 return false, fmt.Errorf("template: redefinition of template %q", name)
227 }
228 }
229 t.tmpl[name] = new
230 return true, nil
231}