...
Run Format

Source file src/text/template/template.go

     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	

View as plain text