Home | History | Annotate | Download | only in template
      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 	"fmt"
      9 	"reflect"
     10 	"sync"
     11 	"text/template/parse"
     12 )
     13 
     14 // common holds the information shared by related templates.
     15 type common struct {
     16 	tmpl   map[string]*Template // Map from name to defined templates.
     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 func (t *Template) New(name string) *Template {
     55 	t.init()
     56 	nt := &Template{
     57 		name:       name,
     58 		common:     t.common,
     59 		leftDelim:  t.leftDelim,
     60 		rightDelim: t.rightDelim,
     61 	}
     62 	return nt
     63 }
     64 
     65 // init guarantees that t has a valid common structure.
     66 func (t *Template) init() {
     67 	if t.common == nil {
     68 		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
     73 	}
     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.
     82 func (t *Template) Clone() (*Template, error) {
     83 	nt := t.copy(nil)
     84 	nt.init()
     85 	if t.common == nil {
     86 		return nt, nil
     87 	}
     88 	for k, v := range t.tmpl {
     89 		if k == t.name {
     90 			nt.tmpl[t.name] = nt
     91 			continue
     92 		}
     93 		// The associated templates share nt's common structure.
     94 		tmpl := v.copy(nt.common)
     95 		nt.tmpl[k] = tmpl
     96 	}
     97 	t.muFuncs.RLock()
     98 	defer t.muFuncs.RUnlock()
     99 	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.
    109 func (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 
    118 // 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.
    121 func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
    122 	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)
    128 	}
    129 	// 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 	}
    135 	return nt, nil
    136 }
    137 
    138 // Templates returns a slice of defined templates associated with t.
    139 func (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.
    156 func (t *Template) Delims(left, right string) *Template {
    157 	t.init()
    158 	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.
    167 func (t *Template) Funcs(funcMap FuncMap) *Template {
    168 	t.init()
    169 	t.muFuncs.Lock()
    170 	defer t.muFuncs.Unlock()
    171 	addValueFuncs(t.execFuncs, funcMap)
    172 	addFuncs(t.parseFuncs, funcMap)
    173 	return t
    174 }
    175 
    176 // 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.
    178 func (t *Template) Lookup(name string) *Template {
    179 	if t.common == nil {
    180 		return nil
    181 	}
    182 	return t.tmpl[name]
    183 }
    184 
    185 // Parse defines the template by parsing the text. Nested template definitions will be
    186 // 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.)
    192 func (t *Template) Parse(text string) (*Template, error) {
    193 	t.init()
    194 	t.muFuncs.RLock()
    195 	trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins)
    196 	t.muFuncs.RUnlock()
    197 	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 {
    202 		if _, err := t.AddParseTree(name, tree); err != nil {
    203 			return nil, err
    204 		}
    205 	}
    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.
    213 func (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 }
    232