diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2019-11-27 13:42:36 +0100 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2019-12-18 11:44:40 +0100 |
commit | e625088ef5a970388ad50e464e87db56b358dac4 (patch) | |
tree | f7b26dec1f3695411558d05ca7d0995817a42250 /tpl | |
parent | 67f3aa72cf9aaf3d6e447fa6bc12de704d46adf7 (diff) |
Add render template hooks for links and images
This commit also
* revises the change detection for templates used by content files in server mode.
* Adds a Page.RenderString method
Fixes #6545
Fixes #4663
Closes #6043
Diffstat (limited to 'tpl')
-rw-r--r-- | tpl/internal/go_templates/texttemplate/exec.go | 2 | ||||
-rw-r--r-- | tpl/internal/go_templates/texttemplate/hugo_template.go | 104 | ||||
-rw-r--r-- | tpl/internal/go_templates/texttemplate/hugo_template_test.go | 22 | ||||
-rw-r--r-- | tpl/partials/partials.go | 6 | ||||
-rw-r--r-- | tpl/template.go | 39 | ||||
-rw-r--r-- | tpl/template_info.go | 52 | ||||
-rw-r--r-- | tpl/tplimpl/shortcodes.go | 4 | ||||
-rw-r--r-- | tpl/tplimpl/shortcodes_test.go | 8 | ||||
-rw-r--r-- | tpl/tplimpl/template.go | 175 | ||||
-rw-r--r-- | tpl/tplimpl/templateProvider.go | 9 | ||||
-rw-r--r-- | tpl/tplimpl/template_ast_transformers.go | 166 | ||||
-rw-r--r-- | tpl/tplimpl/template_ast_transformers_test.go | 66 | ||||
-rw-r--r-- | tpl/tplimpl/template_funcs.go | 24 | ||||
-rw-r--r-- | tpl/tplimpl/template_info_test.go | 7 |
14 files changed, 502 insertions, 182 deletions
diff --git a/tpl/internal/go_templates/texttemplate/exec.go b/tpl/internal/go_templates/texttemplate/exec.go index db64edcb2..078bcf643 100644 --- a/tpl/internal/go_templates/texttemplate/exec.go +++ b/tpl/internal/go_templates/texttemplate/exec.go @@ -658,7 +658,7 @@ var ( // evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so // it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0] // as the function itself. -func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, args []parse.Node, final reflect.Value) reflect.Value { +func (s *state) evalCallOld(dot, fun reflect.Value, node parse.Node, name string, args []parse.Node, final reflect.Value) reflect.Value { if args != nil { args = args[1:] // Zeroth arg is function name/node; not passed to function. } diff --git a/tpl/internal/go_templates/texttemplate/hugo_template.go b/tpl/internal/go_templates/texttemplate/hugo_template.go index be8a5558f..a39f027fb 100644 --- a/tpl/internal/go_templates/texttemplate/hugo_template.go +++ b/tpl/internal/go_templates/texttemplate/hugo_template.go @@ -34,8 +34,9 @@ type Preparer interface { // ExecHelper allows some custom eval hooks. type ExecHelper interface { - GetFunc(name string) (reflect.Value, bool) - GetMapValue(receiver, key reflect.Value) (reflect.Value, bool) + GetFunc(tmpl Preparer, name string) (reflect.Value, bool) + GetMethod(tmpl Preparer, receiver reflect.Value, name string) (method reflect.Value, firstArg reflect.Value) + GetMapValue(tmpl Preparer, receiver, key reflect.Value) (reflect.Value, bool) } // Executer executes a given template. @@ -64,6 +65,7 @@ func (t *executer) Execute(p Preparer, wr io.Writer, data interface{}) error { state := &state{ helper: t.helper, + prep: p, tmpl: tmpl, wr: wr, vars: []variable{{"$", value}}, @@ -75,7 +77,6 @@ func (t *executer) Execute(p Preparer, wr io.Writer, data interface{}) error { // Prepare returns a template ready for execution. func (t *Template) Prepare() (*Template, error) { - return t, nil } @@ -95,6 +96,7 @@ func (t *Template) executeWithState(state *state, value reflect.Value) (err erro // can execute in parallel. type state struct { tmpl *Template + prep Preparer // Added for Hugo. helper ExecHelper // Added for Hugo. wr io.Writer node parse.Node // current node, for errors @@ -110,7 +112,7 @@ func (s *state) evalFunction(dot reflect.Value, node *parse.IdentifierNode, cmd var ok bool if s.helper != nil { // Added for Hugo. - function, ok = s.helper.GetFunc(name) + function, ok = s.helper.GetFunc(s.prep, name) } if !ok { @@ -148,9 +150,23 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, if ptr.Kind() != reflect.Interface && ptr.Kind() != reflect.Ptr && ptr.CanAddr() { ptr = ptr.Addr() } - if method := ptr.MethodByName(fieldName); method.IsValid() { + // Added for Hugo. + var first reflect.Value + var method reflect.Value + if s.helper != nil { + method, first = s.helper.GetMethod(s.prep, ptr, fieldName) + } else { + method = ptr.MethodByName(fieldName) + } + + if method.IsValid() { + if first != zero { + return s.evalCall(dot, method, node, fieldName, args, final, first) + } + return s.evalCall(dot, method, node, fieldName, args, final) } + hasArgs := len(args) > 1 || final != missingVal // It's not a method; must be a field of a struct or an element of a map. switch receiver.Kind() { @@ -177,7 +193,7 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, var result reflect.Value if s.helper != nil { // Added for Hugo. - result, _ = s.helper.GetMapValue(receiver, nameVal) + result, _ = s.helper.GetMapValue(s.prep, receiver, nameVal) } else { result = receiver.MapIndex(nameVal) } @@ -209,3 +225,79 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, s.errorf("can't evaluate field %s in type %s", fieldName, typ) panic("not reached") } + +// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so +// it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0] +// as the function itself. +func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, args []parse.Node, final reflect.Value, first ...reflect.Value) reflect.Value { + if args != nil { + args = args[1:] // Zeroth arg is function name/node; not passed to function. + } + typ := fun.Type() + numFirst := len(first) + numIn := len(args) + numFirst // // Added for Hugo + if final != missingVal { + numIn++ + } + numFixed := len(args) + len(first) + if typ.IsVariadic() { + numFixed = typ.NumIn() - 1 // last arg is the variadic one. + if numIn < numFixed { + s.errorf("wrong number of args for %s: want at least %d got %d", name, typ.NumIn()-1, len(args)) + } + } else if numIn != typ.NumIn() { + s.errorf("wrong number of args for %s: want %d got %d", name, typ.NumIn(), numIn) + } + if !goodFunc(typ) { + // TODO: This could still be a confusing error; maybe goodFunc should provide info. + s.errorf("can't call method/function %q with %d results", name, typ.NumOut()) + } + // Build the arg list. + argv := make([]reflect.Value, numIn) + // Args must be evaluated. Fixed args first. + i := len(first) + for ; i < numFixed && i < len(args)+numFirst; i++ { + argv[i] = s.evalArg(dot, typ.In(i), args[i-numFirst]) + } + // Now the ... args. + if typ.IsVariadic() { + argType := typ.In(typ.NumIn() - 1).Elem() // Argument is a slice. + for ; i < len(args)+numFirst; i++ { + argv[i] = s.evalArg(dot, argType, args[i-numFirst]) + } + + } + // Add final value if necessary. + if final != missingVal { + t := typ.In(typ.NumIn() - 1) + if typ.IsVariadic() { + if numIn-1 < numFixed { + // The added final argument corresponds to a fixed parameter of the function. + // Validate against the type of the actual parameter. + t = typ.In(numIn - 1) + } else { + // The added final argument corresponds to the variadic part. + // Validate against the type of the elements of the variadic slice. + t = t.Elem() + } + } + argv[i] = s.validateType(final, t) + } + + // Added for Hugo + for i := 0; i < len(first); i++ { + argv[i] = s.validateType(first[i], typ.In(i)) + } + + v, err := safeCall(fun, argv) + // If we have an error that is not nil, stop execution and return that + // error to the caller. + if err != nil { + s.at(node) + s.errorf("error calling %s: %v", name, err) + } + if v.Type() == reflectValueType { + v = v.Interface().(reflect.Value) + } + return v +} diff --git a/tpl/internal/go_templates/texttemplate/hugo_template_test.go b/tpl/internal/go_templates/texttemplate/hugo_template_test.go index 2424a0a48..98a2575eb 100644 --- a/tpl/internal/go_templates/texttemplate/hugo_template_test.go +++ b/tpl/internal/go_templates/texttemplate/hugo_template_test.go @@ -27,10 +27,18 @@ type TestStruct struct { M map[string]string } +func (t TestStruct) Hello1(arg string) string { + return arg +} + +func (t TestStruct) Hello2(arg1, arg2 string) string { + return arg1 + " " + arg2 +} + type execHelper struct { } -func (e *execHelper) GetFunc(name string) (reflect.Value, bool) { +func (e *execHelper) GetFunc(tmpl Preparer, name string) (reflect.Value, bool) { if name == "print" { return zero, false } @@ -39,11 +47,19 @@ func (e *execHelper) GetFunc(name string) (reflect.Value, bool) { }), true } -func (e *execHelper) GetMapValue(m, key reflect.Value) (reflect.Value, bool) { +func (e *execHelper) GetMapValue(tmpl Preparer, m, key reflect.Value) (reflect.Value, bool) { key = reflect.ValueOf(strings.ToLower(key.String())) return m.MapIndex(key), true } +func (e *execHelper) GetMethod(tmpl Preparer, receiver reflect.Value, name string) (method reflect.Value, firstArg reflect.Value) { + if name != "Hello1" { + return zero, zero + } + m := receiver.MethodByName("Hello2") + return m, reflect.ValueOf("v2") +} + func TestTemplateExecutor(t *testing.T) { c := qt.New(t) @@ -51,6 +67,7 @@ func TestTemplateExecutor(t *testing.T) { {{ print "foo" }} {{ printf "hugo" }} Map: {{ .M.A }} +Method: {{ .Hello1 "v1" }} `) @@ -67,5 +84,6 @@ Map: {{ .M.A }} c.Assert(got, qt.Contains, "foo") c.Assert(got, qt.Contains, "hello hugo") c.Assert(got, qt.Contains, "Map: av") + c.Assert(got, qt.Contains, "Method: v2 v1") } diff --git a/tpl/partials/partials.go b/tpl/partials/partials.go index bfc3a82d3..6f3ba2d13 100644 --- a/tpl/partials/partials.go +++ b/tpl/partials/partials.go @@ -116,9 +116,9 @@ func (ns *Namespace) Include(name string, contextList ...interface{}) (interface return "", fmt.Errorf("partial %q not found", name) } - var info tpl.Info - if ip, ok := templ.(tpl.TemplateInfoProvider); ok { - info = ip.TemplateInfo() + var info tpl.ParseInfo + if ip, ok := templ.(tpl.Info); ok { + info = ip.ParseInfo() } var w io.Writer diff --git a/tpl/template.go b/tpl/template.go index db715c306..0841236de 100644 --- a/tpl/template.go +++ b/tpl/template.go @@ -24,8 +24,6 @@ import ( texttemplate "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate" ) -var _ TemplateInfoProvider = (*TemplateInfo)(nil) - // TemplateManager manages the collection of templates. type TemplateManager interface { TemplateHandler @@ -34,7 +32,6 @@ type TemplateManager interface { AddLateTemplate(name, tpl string) error LoadTemplates(prefix string) error - MarkReady() error RebuildClone() } @@ -80,11 +77,6 @@ type Template interface { Prepare() (*texttemplate.Template, error) } -// TemplateInfoProvider provides some contextual information about a template. -type TemplateInfoProvider interface { - TemplateInfo() Info -} - // TemplateParser is used to parse ad-hoc templates, e.g. in the Resource chain. type TemplateParser interface { Parse(name, tpl string) (Template, error) @@ -101,10 +93,31 @@ type TemplateDebugger interface { Debug() } -// TemplateInfo wraps a Template with some additional information. -type TemplateInfo struct { +// templateInfo wraps a Template with some additional information. +type templateInfo struct { Template - Info Info + Info +} + +// templateInfo wraps a Template with some additional information. +type templateInfoManager struct { + Template + InfoManager +} + +// WithInfo wraps the info in a template. +func WithInfo(templ Template, info Info) Template { + if manager, ok := info.(InfoManager); ok { + return &templateInfoManager{ + Template: templ, + InfoManager: manager, + } + } + + return &templateInfo{ + Template: templ, + Info: info, + } } var baseOfRe = regexp.MustCompile("template: (.*?):") @@ -117,10 +130,6 @@ func extractBaseOf(err string) string { return "" } -func (t *TemplateInfo) TemplateInfo() Info { - return t.Info -} - // TemplateFuncGetter allows to find a template func by name. type TemplateFuncGetter interface { GetFunc(name string) (reflect.Value, bool) diff --git a/tpl/template_info.go b/tpl/template_info.go index be0566958..d9b438138 100644 --- a/tpl/template_info.go +++ b/tpl/template_info.go @@ -13,12 +13,44 @@ package tpl +import ( + "github.com/gohugoio/hugo/identity" +) + // Increments on breaking changes. const TemplateVersion = 2 -// Info holds some info extracted from a parsed template. -type Info struct { +type Info interface { + ParseInfo() ParseInfo + + // Identifies this template and its dependencies. + identity.Provider +} + +type InfoManager interface { + ParseInfo() ParseInfo + + // Identifies and manages this template and its dependencies. + identity.Manager +} + +type defaultInfo struct { + identity.Manager + parseInfo ParseInfo +} +func NewInfo(id identity.Manager, parseInfo ParseInfo) Info { + return &defaultInfo{ + Manager: id, + parseInfo: parseInfo, + } +} + +func (info *defaultInfo) ParseInfo() ParseInfo { + return info.parseInfo +} + +type ParseInfo struct { // Set for shortcode templates with any {{ .Inner }} IsInner bool @@ -26,17 +58,25 @@ type Info struct { HasReturn bool // Config extracted from template. - Config Config + Config ParseConfig } -func (info Info) IsZero() bool { +func (info ParseInfo) IsZero() bool { return info.Config.Version == 0 } -type Config struct { +// Info holds some info extracted from a parsed template. +type Info1 struct { +} + +type ParseConfig struct { Version int } -var DefaultConfig = Config{ +var DefaultParseConfig = ParseConfig{ Version: TemplateVersion, } + +var DefaultParseInfo = ParseInfo{ + Config: DefaultParseConfig, +} diff --git a/tpl/tplimpl/shortcodes.go b/tpl/tplimpl/shortcodes.go index e5dbabdd8..abef11e1e 100644 --- a/tpl/tplimpl/shortcodes.go +++ b/tpl/tplimpl/shortcodes.go @@ -83,10 +83,12 @@ func (s *shortcodeTemplates) fromVariantsSlice(variants []string) (shortcodeVari func (s *shortcodeTemplates) compareVariants(a, b []string) int { weight := 0 + k := len(a) for i, av := range a { bv := b[i] if av == bv { - weight++ + // Add more weight to the left side (language...). + weight = weight + k - i } else { weight-- } diff --git a/tpl/tplimpl/shortcodes_test.go b/tpl/tplimpl/shortcodes_test.go index 08200444d..4ef8c5cd7 100644 --- a/tpl/tplimpl/shortcodes_test.go +++ b/tpl/tplimpl/shortcodes_test.go @@ -53,10 +53,10 @@ func TestShortcodesTemplate(t *testing.T) { name2 string expected int }{ - {"Same suffix", "figure.html", "figure.html", 3}, - {"Same suffix and output format", "figure.html.html", "figure.html.html", 3}, - {"Same suffix, output format and language", "figure.no.html.html", "figure.no.html.html", 3}, - {"No suffix", "figure", "figure", 3}, + {"Same suffix", "figure.html", "figure.html", 6}, + {"Same suffix and output format", "figure.html.html", "figure.html.html", 6}, + {"Same suffix, output format and language", "figure.no.html.html", "figure.no.html.html", 6}, + {"No suffix", "figure", "figure", 6}, {"Different output format", "figure.amp.html", "figure.html.html", -1}, {"One with output format, one without", "figure.amp.html", "figure.html", -1}, } diff --git a/tpl/tplimpl/template.go b/tpl/tplimpl/template.go index dd8de9067..2d2a63cf9 100644 --- a/tpl/tplimpl/template.go +++ b/tpl/tplimpl/template.go @@ -20,6 +20,10 @@ import ( "regexp" "time" + "github.com/gohugoio/hugo/hugofs/files" + + "github.com/gohugoio/hugo/identity" + "github.com/gohugoio/hugo/common/herrors" "strings" @@ -27,7 +31,6 @@ import ( template "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate" texttemplate "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate" - "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse" "github.com/gohugoio/hugo/hugofs" "github.com/gohugoio/hugo/tpl/tplimpl/embedded" @@ -81,6 +84,7 @@ func newTemplateAdapter(deps *deps.Deps) *templateHandler { common := &templatesCommon{ nameBaseTemplateName: make(map[string]string), transformNotFound: make(map[string]bool), + identityNotFound: make(map[string][]identity.Manager), } htmlT := &htmlTemplates{ @@ -100,13 +104,16 @@ func newTemplateAdapter(deps *deps.Deps) *templateHandler { Deps: deps, layoutsFs: deps.BaseFs.Layouts.Fs, templateHandlerCommon: &templateHandlerCommon{ - shortcodes: make(map[string]*shortcodeTemplates), - templateInfo: make(map[string]tpl.Info), - html: htmlT, - text: textT, + shortcodes: make(map[string]*shortcodeTemplates), + templateInfo: make(map[string]tpl.Info), + templateInfoTree: make(map[string]*templateInfoTree), + html: htmlT, + text: textT, }, } + textT.textTemplate.templates = textT + textT.standalone.templates = textT common.handler = h return h @@ -152,27 +159,26 @@ func (t *htmlTemplates) addTemplate(name, tpl string) (*templateContext, error) return t.addTemplateIn(t.t, name, tpl) } -func (t *htmlTemplates) addTemplateIn(tt *template.Template, name, tpl string) (*templateContext, error) { - templ, err := tt.New(name).Parse(tpl) +func (t *htmlTemplates) addTemplateIn(tt *template.Template, name, templstr string) (*templateContext, error) { + templ, err := tt.New(name).Parse(templstr) if err != nil { return nil, err } typ := resolveTemplateType(name) - c, err := applyTemplateTransformersToHMLTTemplate(typ, templ) + c, err := t.handler.applyTemplateTransformersToHMLTTemplate(typ, templ) if err != nil { return nil, err } - for k := range c.notFound { + for k := range c.templateNotFound { t.transformNotFound[k] = true + t.identityNotFound[k] = append(t.identityNotFound[k], c.id) } - if typ == templateShortcode { - t.handler.addShortcodeVariant(name, c.Info, templ) - } else { - t.handler.templateInfo[name] = c.Info + for k := range c.identityNotFound { + t.identityNotFound[k] = append(t.identityNotFound[k], c.id) } return c, nil @@ -208,7 +214,7 @@ func (t *htmlTemplates) handleMaster(name, overlayFilename, masterFilename strin // * https://github.com/golang/go/issues/16101 // * https://github.com/gohugoio/hugo/issues/2549 overlayTpl = overlayTpl.Lookup(overlayTpl.Name()) - if _, err := applyTemplateTransformersToHMLTTemplate(templateUndefined, overlayTpl); err != nil { + if _, err := t.handler.applyTemplateTransformersToHMLTTemplate(templateUndefined, overlayTpl); err != nil { return err } @@ -253,6 +259,8 @@ func (l nopLookupVariant) LookupVariant(name string, variants tpl.TemplateVarian // It implements the templateLoader and tpl.TemplateHandler interfaces. // There is one templateHandler created per Site. type templateHandler struct { + ready bool + executor texttemplate.Executer funcs map[string]reflect.Value @@ -324,6 +332,7 @@ func (t *templateHandler) LoadTemplates(prefix string) error { // Lookup tries to find a template with the given name in both template // collections: First HTML, then the plain text template collection. func (t *templateHandler) Lookup(name string) (tpl.Template, bool) { + if strings.HasPrefix(name, textTmplNamePrefix) { // The caller has explicitly asked for a text template, so only look // in the text template collection. @@ -345,6 +354,9 @@ func (t *templateHandler) Lookup(name string) (tpl.Template, bool) { // This currently only applies to shortcodes and what we get here is the // shortcode name. func (t *templateHandler) LookupVariant(name string, variants tpl.TemplateVariants) (tpl.Template, bool, bool) { + if !t.ready { + panic("handler not ready") + } name = templateBaseName(templateShortcode, name) s, found := t.shortcodes[name] if !found { @@ -358,18 +370,17 @@ func (t *templateHandler) LookupVariant(name string, variants tpl.TemplateVarian more := len(s.variants) > 1 - return &tpl.TemplateInfo{ - Template: sv.templ, - Info: sv.info, - }, true, more + return tpl.WithInfo(sv.templ, sv.info), true, more } -// MarkReady marks the templates as "ready for execution". No changes allowed +// markReady marks the templates as "ready for execution". No changes allowed // after this is set. -// TODO(bep) if this proves to be resource heavy, we could detect -// earlier if we really need this, or make it lazy. -func (t *templateHandler) MarkReady() error { +func (t *templateHandler) markReady() error { + defer func() { + t.ready = true + }() + if err := t.postTransform(); err != nil { return err } @@ -483,6 +494,7 @@ func (t *templateHandler) addInternalTemplate(name, tpl string) error { } func (t *templateHandler) addShortcodeVariant(name string, info tpl.Info, templ tpl.Template) { + base := templateBaseName(templateShortcode, name) shortcodename, variants := templateNameAndVariants(base) @@ -561,18 +573,9 @@ func (t *templateHandler) addTemplateFile(name, baseTemplatePath, path string) e } func (t *templateHandler) applyTemplateInfo(templ tpl.Template, found bool) (tpl.Template, bool) { - if adapter, ok := templ.(*tpl.TemplateInfo); ok { - if adapter.Info.IsZero() { - if info, found := t.templateInfo[templ.Name()]; found { - adapter.Info = info - } - } - } else if templ != nil { + if templ != nil { if info, found := t.templateInfo[templ.Name()]; found { - return &tpl.TemplateInfo{ - Template: templ, - Info: info, - }, true + return tpl.WithInfo(templ, info), true } } @@ -586,7 +589,11 @@ func (t *templateHandler) checkState() { } func (t *templateHandler) clone(d *deps.Deps) *templateHandler { + if !t.ready { + panic("invalid state") + } c := &templateHandler{ + ready: true, Deps: d, layoutsFs: d.BaseFs.Layouts.Fs, } @@ -703,36 +710,69 @@ func (t *templateHandler) loadTemplates(prefix string) error { } -func (t *templateHandler) postTransform() error { - if len(t.html.transformNotFound) == 0 && len(t.text.transformNotFound) == 0 { - return nil +func (t *templateHandler) getOrCreateTemplateInfo(name string) (identity.Manager, tpl.ParseInfo) { + info, found := t.templateInfo[name] + if found { + return info.(identity.Manager), info.ParseInfo() } + return identity.NewManager(identity.NewPathIdentity(files.ComponentFolderLayouts, name)), tpl.DefaultParseInfo +} - defer func() { - t.text.transformNotFound = make(map[string]bool) - t.html.transformNotFound = make(map[string]bool) - }() +func (t *templateHandler) createTemplateInfo(name string) (identity.Manager, tpl.ParseInfo) { + _, found := t.templateInfo[name] + if found { + panic("already created: " + name) + } + + return identity.NewManager(identity.NewPathIdentity(files.ComponentFolderLayouts, name)), tpl.DefaultParseInfo +} + +func (t *templateHandler) postTransform() error { + for k, v := range t.templateInfoTree { + if v.id != nil { + info := tpl.NewInfo( + v.id, + v.info, + ) + t.templateInfo[k] = info + + if v.typ == templateShortcode { + t.addShortcodeVariant(k, info, v.templ) + } + } + } for _, s := range []struct { - lookup func(name string) *parse.Tree + lookup func(name string) *templateInfoTree transformNotFound map[string]bool + identityNotFound map[string][]identity.Manager }{ // html templates - {func(name string) *parse.Tree { + {func(name string) *templateInfoTree { templ := t.html.lookup(name) if templ == nil { return nil } - return templ.Tree - }, t.html.transformNotFound}, + id, info := t.getOrCreateTemplateInfo(name) + return &templateInfoTree{ + id: id, + info: info, + tree: templ.Tree, + } + }, t.html.transformNotFound, t.html.identityNotFound}, // text templates - {func(name string) *parse.Tree { + {func(name string) *templateInfoTree { templT := t.text.lookup(name) if templT == nil { return nil } - return templT.Tree - }, t.text.transformNotFound}, + id, info := t.getOrCreateTemplateInfo(name) + return &templateInfoTree{ + id: id, + info: info, + tree: templT.Tree, + } + }, t.text.transformNotFound, t.text.identityNotFound}, } { for name := range s.transformNotFound { templ := s.lookup(name) @@ -743,6 +783,15 @@ func (t *templateHandler) postTransform() error { } } } + + for k, v := range s.identityNotFound { + tmpl := s.lookup(k) + if tmpl != nil { + for _, im := range v { + im.Add(tmpl.id) + } + } + } } return nil @@ -758,7 +807,6 @@ |