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