summaryrefslogtreecommitdiffstats
path: root/tpl/tplimpl/template.go
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/tplimpl/template.go
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/tplimpl/template.go')
-rw-r--r--tpl/tplimpl/template.go175
1 files changed, 112 insertions, 63 deletions
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 @@ func (t *templateHandler) wrapTextTemplate(tt *textTemplate) tpl.TemplateParseFi
tt,
new(nopLookupVariant),
}
-
}
type templateHandlerCommon struct {
@@ -771,6 +819,9 @@ type templateHandlerCommon struct {
// shortcodeTemplates type.
templateInfo map[string]tpl.Info
+ // Used to track templates during the AST transformations.
+ templateInfoTree map[string]*templateInfoTree
+
// text holds all the pure text templates.
text *textTemplates
html *htmlTemplates
@@ -795,9 +846,12 @@ type templatesCommon struct {
// Used to get proper filenames in errors
nameBaseTemplateName map[string]string
- // Holds names of the templates not found during the first AST transformation
+ // Holds names of the template definitions not found during the first AST transformation
// pass.
transformNotFound map[string]bool
+
+ // Holds identities of templates not found during first pass.
+ identityNotFound map[string][]identity.Manager
}
func (t templatesCommon) withNewHandler(h *templateHandler) *templatesCommon {
@@ -806,8 +860,9 @@ func (t templatesCommon) withNewHandler(h *templateHandler) *templatesCommon {
}
type textTemplate struct {
- mu sync.RWMutex
- t *texttemplate.Template
+ mu sync.RWMutex
+ t *texttemplate.Template
+ templates *textTemplates
}
func (t *textTemplate) Lookup(name string) (tpl.Template, bool) {
@@ -831,7 +886,7 @@ func (t *textTemplate) parseIn(tt *texttemplate.Template, name, tpl string) (*te
return nil, err
}
- if _, err := applyTemplateTransformersToTextTemplate(templateUndefined, templ); err != nil {
+ if _, err := t.templates.handler.applyTemplateTransformersToTextTemplate(templateUndefined, templ); err != nil {
return nil, err
}
return templ, nil
@@ -868,30 +923,24 @@ func (t *textTemplates) addTemplate(name, tpl string) (*templateContext, error)
return t.addTemplateIn(t.t, name, tpl)
}
-func (t *textTemplates) addTemplateIn(tt *texttemplate.Template, name, tpl string) (*templateContext, error) {
+func (t *textTemplates) addTemplateIn(tt *texttemplate.Template, name, tplstr string) (*templateContext, error) {
name = strings.TrimPrefix(name, textTmplNamePrefix)
- templ, err := t.parseIn(tt, name, tpl)
+ templ, err := t.parseIn(tt, name, tplstr)
if err != nil {
return nil, err
}
typ := resolveTemplateType(name)
- c, err := applyTemplateTransformersToTextTemplate(typ, templ)
+ c, err := t.handler.applyTemplateTransformersToTextTemplate(typ, templ)
if err != nil {
return nil, err
}
- for k := range c.notFound {
+ for k := range c.templateNotFound {
t.transformNotFound[k] = true
}
- if typ == templateShortcode {
- t.handler.addShortcodeVariant(name, c.Info, templ)
- } else {
- t.handler.templateInfo[name] = c.Info
- }
-
return c, nil
}
@@ -924,7 +973,7 @@ func (t *textTemplates) handleMaster(name, overlayFilename, masterFilename strin
}
overlayTpl = overlayTpl.Lookup(overlayTpl.Name())
- if _, err := applyTemplateTransformersToTextTemplate(templateUndefined, overlayTpl); err != nil {
+ if _, err := t.handler.applyTemplateTransformersToTextTemplate(templateUndefined, overlayTpl); err != nil {
return err
}
t.overlays[name] = overlayTpl