summaryrefslogtreecommitdiffstats
path: root/tpl
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2019-11-27 13:42:36 +0100
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2019-12-18 11:44:40 +0100
commite625088ef5a970388ad50e464e87db56b358dac4 (patch)
treef7b26dec1f3695411558d05ca7d0995817a42250 /tpl
parent67f3aa72cf9aaf3d6e447fa6bc12de704d46adf7 (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.go2
-rw-r--r--tpl/internal/go_templates/texttemplate/hugo_template.go104
-rw-r--r--tpl/internal/go_templates/texttemplate/hugo_template_test.go22
-rw-r--r--tpl/partials/partials.go6
-rw-r--r--tpl/template.go39
-rw-r--r--tpl/template_info.go52
-rw-r--r--tpl/tplimpl/shortcodes.go4
-rw-r--r--tpl/tplimpl/shortcodes_test.go8
-rw-r--r--tpl/tplimpl/template.go175
-rw-r--r--tpl/tplimpl/templateProvider.go9
-rw-r--r--tpl/tplimpl/template_ast_transformers.go166
-rw-r--r--tpl/tplimpl/template_ast_transformers_test.go66
-rw-r--r--tpl/tplimpl/template_funcs.go24
-rw-r--r--tpl/tplimpl/template_info_test.go7
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 @@