hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

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 }