summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2017-03-27 20:43:49 +0200
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2017-04-02 11:37:30 +0200
commit5c5efa03d2512749950b0d05a7d4bde35ecbdc37 (patch)
tree9f3e31a7e30c51fab5ed3f7c323393fcafadc5e8
parent73c1c7b69d8302000fa5c5b804ad3eeac36da12f (diff)
tpl: Rework to handle both text and HTML templates
Before this commit, Hugo used `html/template` for all Go templates. While this is a fine choice for HTML and maybe also RSS feeds, it is painful for plain text formats such as CSV, JSON etc. This commit fixes that by using the `IsPlainText` attribute on the output format to decide what to use. A couple of notes: * The above requires a nonambiguous template name to type mapping. I.e. `/layouts/_default/list.json` will only work if there is only one JSON output format, `/layouts/_default/list.mytype.json` will always work. * Ambiguous types will fall back to HTML. * Partials inherits the text vs HTML identificator of the container template. This also means that plain text templates can only include plain text partials. * Shortcode templates are, by definition, currently HTML templates only. Fixes #3221
-rw-r--r--deps/deps.go6
-rw-r--r--hugolib/alias.go27
-rw-r--r--hugolib/embedded_shortcodes_test.go8
-rw-r--r--hugolib/hugo_sites.go8
-rw-r--r--hugolib/page.go3
-rw-r--r--hugolib/page_output.go24
-rw-r--r--hugolib/shortcode.go16
-rw-r--r--hugolib/shortcode_test.go103
-rw-r--r--hugolib/site.go32
-rw-r--r--hugolib/site_output_test.go16
-rw-r--r--hugolib/site_test.go18
-rw-r--r--hugolib/sitemap_test.go2
-rw-r--r--hugolib/testhelpers_test.go4
-rw-r--r--output/layout.go28
-rw-r--r--output/layout_base.go19
-rw-r--r--output/layout_base_test.go6
-rw-r--r--output/layout_test.go4
-rw-r--r--output/outputFormat.go40
-rw-r--r--output/outputFormat_test.go27
-rw-r--r--tpl/template.go111
-rw-r--r--tpl/tplimpl/ace.go51
-rw-r--r--tpl/tplimpl/amber_compiler.go4
-rw-r--r--tpl/tplimpl/template.go770
-rw-r--r--tpl/tplimpl/templateFuncster.go86
-rw-r--r--tpl/tplimpl/templateProvider.go59
-rw-r--r--tpl/tplimpl/template_ast_transformers.go50
-rw-r--r--tpl/tplimpl/template_ast_transformers_test.go12
-rw-r--r--tpl/tplimpl/template_embedded.go57
-rw-r--r--tpl/tplimpl/template_funcs.go33
-rw-r--r--tpl/tplimpl/template_funcs_test.go66
-rw-r--r--tpl/tplimpl/template_test.go232
31 files changed, 1145 insertions, 777 deletions
diff --git a/deps/deps.go b/deps/deps.go
index 659f259dd..188863876 100644
--- a/deps/deps.go
+++ b/deps/deps.go
@@ -20,7 +20,7 @@ type Deps struct {
Log *jww.Notepad `json:"-"`
// The templates to use.
- Tmpl tpl.Template `json:"-"`
+ Tmpl tpl.TemplateHandler `json:"-"`
// The file systems to use.
Fs *hugofs.Fs `json:"-"`
@@ -40,7 +40,7 @@ type Deps struct {
Language *helpers.Language
templateProvider ResourceProvider
- WithTemplate func(templ tpl.Template) error `json:"-"`
+ WithTemplate func(templ tpl.TemplateHandler) error `json:"-"`
translationProvider ResourceProvider
}
@@ -158,7 +158,7 @@ type DepsCfg struct {
// Template handling.
TemplateProvider ResourceProvider
- WithTemplate func(templ tpl.Template) error
+ WithTemplate func(templ tpl.TemplateHandler) error
// i18n handling.
TranslationProvider ResourceProvider
diff --git a/hugolib/alias.go b/hugolib/alias.go
index d5eb35777..454744d9b 100644
--- a/hugolib/alias.go
+++ b/hugolib/alias.go
@@ -22,6 +22,8 @@ import (
"runtime"
"strings"
+ "github.com/spf13/hugo/tpl"
+
jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/hugo/helpers"
@@ -35,18 +37,19 @@ const (
var defaultAliasTemplates *template.Template
func init() {
+ //TODO(bep) consolidate
defaultAliasTemplates = template.New("")
template.Must(defaultAliasTemplates.New("alias").Parse(alias))
template.Must(defaultAliasTemplates.New("alias-xhtml").Parse(aliasXHtml))
}
type aliasHandler struct {
- Templates *template.Template
+ t tpl.TemplateHandler
log *jww.Notepad
allowRoot bool
}
-func newAliasHandler(t *template.Template, l *jww.Notepad, allowRoot bool) aliasHandler {
+func newAliasHandler(t tpl.TemplateHandler, l *jww.Notepad, allowRoot bool) aliasHandler {
return aliasHandler{t, l, allowRoot}
}
@@ -56,12 +59,19 @@ func (a aliasHandler) renderAlias(isXHTML bool, permalink string, page *Page) (i
t = "alias-xhtml"
}
- template := defaultAliasTemplates
- if a.Templates != nil {
- template = a.Templates
- t = "alias.html"
+ var templ *tpl.TemplateAdapter
+
+ if a.t != nil {
+ templ = a.t.Lookup("alias.html")
}
+ if templ == nil {
+ def := defaultAliasTemplates.Lookup(t)
+ if def != nil {
+ templ = &tpl.TemplateAdapter{def}
+ }
+
+ }
data := struct {
Permalink string
Page *Page
@@ -71,7 +81,7 @@ func (a aliasHandler) renderAlias(isXHTML bool, permalink string, page *Page) (i
}
buffer := new(bytes.Buffer)
- err := template.ExecuteTemplate(buffer, t, data)
+ err := templ.Execute(buffer, data)
if err != nil {
return nil, err
}
@@ -83,8 +93,7 @@ func (s *Site) writeDestAlias(path, permalink string, p *Page) (err error) {
}
func (s *Site) publishDestAlias(allowRoot bool, path, permalink string, p *Page) (err error) {
-
- handler := newAliasHandler(s.Tmpl.Lookup("alias.html"), s.Log, allowRoot)
+ handler := newAliasHandler(s.Tmpl, s.Log, allowRoot)
isXHTML := strings.HasSuffix(path, ".xhtml")
diff --git a/hugolib/embedded_shortcodes_test.go b/hugolib/embedded_shortcodes_test.go
index 92821d0ef..45de0bf09 100644
--- a/hugolib/embedded_shortcodes_test.go
+++ b/hugolib/embedded_shortcodes_test.go
@@ -335,8 +335,8 @@ func TestShortcodeTweet(t *testing.T) {
th = testHelper{cfg, fs, t}
)
- withTemplate := func(templ tpl.Template) error {
- templ.Funcs(tweetFuncMap)
+ withTemplate := func(templ tpl.TemplateHandler) error {
+ templ.(tpl.TemplateTestMocker).SetFuncs(tweetFuncMap)
return nil
}
@@ -390,8 +390,8 @@ func TestShortcodeInstagram(t *testing.T) {
th = testHelper{cfg, fs, t}
)
- withTemplate := func(templ tpl.Template) error {
- templ.Funcs(instagramFuncMap)
+ withTemplate := func(templ tpl.TemplateHandler) error {
+ templ.(tpl.TemplateTestMocker).SetFuncs(instagramFuncMap)
return nil
}
diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go
index 6c737f65a..1f090cf5e 100644
--- a/hugolib/hugo_sites.go
+++ b/hugolib/hugo_sites.go
@@ -127,11 +127,11 @@ func NewHugoSites(cfg deps.DepsCfg) (*HugoSites, error) {
return newHugoSites(cfg, sites...)
}
-func (s *Site) withSiteTemplates(withTemplates ...func(templ tpl.Template) error) func(templ tpl.Template) error {
- return func(templ tpl.Template) error {
- templ.LoadTemplates(s.PathSpec.GetLayoutDirPath())
+func (s *Site) withSiteTemplates(withTemplates ...func(templ tpl.TemplateHandler) error) func(templ tpl.TemplateHandler) error {
+ return func(templ tpl.TemplateHandler) error {
+ templ.LoadTemplates(s.PathSpec.GetLayoutDirPath(), "")
if s.PathSpec.ThemeSet() {
- templ.LoadTemplatesWithPrefix(s.PathSpec.GetThemeDir()+"/layouts", "theme")
+ templ.LoadTemplates(s.PathSpec.GetThemeDir()+"/layouts", "theme")
}
for _, wt := range withTemplates {
diff --git a/hugolib/page.go b/hugolib/page.go
index fa9f40922..5a04c6ce7 100644
--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -1384,13 +1384,14 @@ func (p *Page) prepareLayouts() error {
if p.Kind == KindPage {
if !p.IsRenderable() {
self := "__" + p.UniqueID()
- _, err := p.s.Tmpl.GetClone().New(self).Parse(string(p.Content))
+ err := p.s.Tmpl.AddLateTemplate(self, string(p.Content))
if err != nil {
return err
}
p.selfLayout = self
}
}
+
return nil
}
diff --git a/hugolib/page_output.go b/hugolib/page_output.go
index f47343cb5..58d09d688 100644
--- a/hugolib/page_output.go
+++ b/hugolib/page_output.go
@@ -110,9 +110,29 @@ func (p *PageOutput) Render(layout ...string) template.HTML {
l, err := p.layouts(layout...)
if err != nil {
helpers.DistinctErrorLog.Printf("in .Render: Failed to resolve layout %q for page %q", layout, p.pathOrTitle())
- return template.HTML("")
+ return ""
}
- return p.s.Tmpl.ExecuteTemplateToHTML(p, l...)
+
+ for _, layout := range l {
+ templ := p.s.Tmpl.Lookup(layout)
+ if templ == nil {
+ // This is legacy from when we had only one output format and
+ // HTML templates only. Some have references to layouts without suffix.
+ // We default to good old HTML.
+ templ = p.s.Tmpl.Lookup(layout + ".html")
+ }
+ if templ != nil {
+ res, err := templ.ExecuteToString(p)
+ if err != nil {
+ helpers.DistinctErrorLog.Printf("in .Render: Failed to execute template %q for page %q", layout, p.pathOrTitle())
+ return template.HTML("")
+ }
+ return template.HTML(res)
+ }
+ }
+
+ return ""
+
}
func (p *Page) Render(layout ...string) template.HTML {
diff --git a/hugolib/shortcode.go b/hugolib/shortcode.go
index d165c778b..d72a96faa 100644
--- a/hugolib/shortcode.go
+++ b/hugolib/shortcode.go
@@ -177,7 +177,7 @@ var isInnerShortcodeCache = struct {
// to avoid potential costly look-aheads for closing tags we look inside the template itself
// we could change the syntax to self-closing tags, but that would make users cry
// the value found is cached
-func isInnerShortcode(t *template.Template) (bool, error) {
+func isInnerShortcode(t tpl.TemplateExecutor) (bool, error) {
isInnerShortcodeCache.RLock()
m, ok := isInnerShortcodeCache.m[t.Name()]
isInnerShortcodeCache.RUnlock()
@@ -188,10 +188,7 @@ func isInnerShortcode(t *template.Template) (bool, error) {
isInnerShortcodeCache.Lock()
defer isInnerShortcodeCache.Unlock()
- if t.Tree == nil {
- return false, errors.New("Template failed to compile")
- }
- match, _ := regexp.MatchString("{{.*?\\.Inner.*?}}", t.Tree.Root.String())
+ match, _ := regexp.MatchString("{{.*?\\.Inner.*?}}", t.Tree())
isInnerShortcodeCache.m[t.Name()] = match
return match, nil
@@ -398,8 +395,6 @@ Loop:
case tScName:
sc.name = currItem.val
tmpl := getShortcodeTemplate(sc.name, p.s.Tmpl)
- {
- }
if tmpl == nil {
return sc, fmt.Errorf("Unable to locate template for shortcode %q in page %q", sc.name, p.Path())
}
@@ -570,7 +565,10 @@ func replaceShortcodeTokens(source []byte, prefix string, replacements map[strin
return source, nil
}
-func getShortcodeTemplate(name string, t tpl.Template) *template.Template {
+func getShortcodeTemplate(name string, t tpl.TemplateHandler) *tpl.TemplateAdapter {
+ isInnerShortcodeCache.RLock()
+ defer isInnerShortcodeCache.RUnlock()
+
if x := t.Lookup("shortcodes/" + name + ".html"); x != nil {
return x
}
@@ -580,7 +578,7 @@ func getShortcodeTemplate(name string, t tpl.Template) *template.Template {
return t.Lookup("_internal/shortcodes/" + name + ".html")
}
-func renderShortcodeWithPage(tmpl *template.Template, data *ShortcodeWithPage) string {
+func renderShortcodeWithPage(tmpl tpl.Template, data *ShortcodeWithPage) string {
buffer := bp.GetBuffer()
defer bp.PutBuffer(buffer)
diff --git a/hugolib/shortcode_test.go b/hugolib/shortcode_test.go
index 28b03aa9b..3d1922462 100644
--- a/hugolib/shortcode_test.go
+++ b/hugolib/shortcode_test.go
@@ -30,7 +30,7 @@ import (
)
// TODO(bep) remove
-func pageFromString(in, filename string, withTemplate ...func(templ tpl.Template) error) (*Page, error) {
+func pageFromString(in, filename string, withTemplate ...func(templ tpl.TemplateHandler) error) (*Page, error) {
s := newTestSite(nil)
if len(withTemplate) > 0 {
// Have to create a new site
@@ -47,11 +47,11 @@ func pageFromString(in, filename string, withTemplate ...func(templ tpl.Template
return s.NewPageFrom(strings.NewReader(in), filename)
}
-func CheckShortCodeMatch(t *testing.T, input, expected string, withTemplate func(templ tpl.Template) error) {
+func CheckShortCodeMatch(t *testing.T, input, expected string, withTemplate func(templ tpl.TemplateHandler) error) {
CheckShortCodeMatchAndError(t, input, expected, withTemplate, false)
}
-func CheckShortCodeMatchAndError(t *testing.T, input, expected string, withTemplate func(templ tpl.Template) error, expectError bool) {
+func CheckShortCodeMatchAndError(t *testing.T, input, expected string, withTemplate func(templ tpl.TemplateHandler) error, expectError bool) {
cfg, fs := newTestCfg()
@@ -100,8 +100,9 @@ func TestNonSC(t *testing.T) {
// Issue #929
func TestHyphenatedSC(t *testing.T) {
t.Parallel()
- wt := func(tem tpl.Template) error {
- tem.AddInternalShortcode("hyphenated-video.html", `Playing Video {{ .Get 0 }}`)
+ wt := func(tem tpl.TemplateHandler) error {
+
+ tem.AddTemplate("_internal/shortcodes/hyphenated-video.html", `Playing Video {{ .Get 0 }}`)
return nil
}
@@ -111,8 +112,8 @@ func TestHyphenatedSC(t *testing.T) {
// Issue #1753
func TestNoTrailingNewline(t *testing.T) {
t.Parallel()
- wt := func(tem tpl.Template) error {
- tem.AddInternalShortcode("a.html", `{{ .Get 0 }}`)
+ wt := func(tem tpl.TemplateHandler) error {
+ tem.AddTemplate("_internal/shortcodes/a.html", `{{ .Get 0 }}`)
return nil
}
@@ -121,8 +122,8 @@ func TestNoTrailingNewline(t *testing.T) {
func TestPositionalParamSC(t *testing.T) {
t.Parallel()
- wt := func(tem tpl.Template) error {
- tem.AddInternalShortcode("video.html", `Playing Video {{ .Get 0 }}`)
+ wt := func(tem tpl.TemplateHandler) error {
+ tem.AddTemplate("_internal/shortcodes/video.html", `Playing Video {{ .Get 0 }}`)
return nil
}
@@ -135,8 +136,8 @@ func TestPositionalParamSC(t *testing.T) {
func TestPositionalParamIndexOutOfBounds(t *testing.T) {
t.Parallel()
- wt := func(tem tpl.Template) error {
- tem.AddInternalShortcode("video.html", `Playing Video {{ .Get 1 }}`)
+ wt := func(tem tpl.TemplateHandler) error {
+ tem.AddTemplate("_internal/shortcodes/video.html", `Playing Video {{ .Get 1 }}`)
return nil
}
CheckShortCodeMatch(t, "{{< video 47238zzb >}}", "Playing Video error: index out of range for positional param at position 1", wt)
@@ -146,8 +147,8 @@ func TestPositionalParamIndexOutOfBounds(t *testing.T) {
func TestNamedParamSC(t *testing.T) {
t.Parallel()
- wt := func(tem tpl.Template) error {
- tem.AddInternalShortcode("img.html", `<img{{ with .Get "src" }} src="{{.}}"{{end}}{{with .Get "class"}} class="{{.}}"{{end}}>`)
+ wt := func(tem tpl.TemplateHandler) error {
+ tem.AddTemplate("_internal/shortcodes/img.html", `<img{{ with .Get "src" }} src="{{.}}"{{end}}{{with .Get "class"}} class="{{.}}"{{end}}>`)
return nil
}
CheckShortCodeMatch(t, `{{< img src="one" >}}`, `<img src="one">`, wt)
@@ -161,10 +162,10 @@ func TestNamedParamSC(t *testing.T) {
// Issue #2294
func TestNestedNamedMissingParam(t *testing.T) {
t.Parallel()
- wt := func(tem tpl.Template) error {
- tem.AddInternalShortcode("acc.html", `<div class="acc">{{ .Inner }}</div>`)
- tem.AddInternalShortcode("div.html", `<div {{with .Get "class"}} class="{{ . }}"{{ end }}>{{ .Inner }}</div>`)
- tem.AddInternalShortcode("div2.html", `<div {{with .Get 0}} class="{{ . }}"{{ end }}>{{ .Inner }}</div>`)
+ wt := func(tem tpl.TemplateHandler) error {
+ tem.AddTemplate("_internal/shortcodes/acc.html", `<div class="acc">{{ .Inner }}</div>`)
+ tem.AddTemplate("_internal/shortcodes/div.html", `<div {{with .Get "class"}} class="{{ . }}"{{ end }}>{{ .Inner }}</div>`)
+ tem.AddTemplate("_internal/shortcodes/div2.html", `<div {{with .Get 0}} class="{{ . }}"{{ end }}>{{ .Inner }}</div>`)
return nil
}
CheckShortCodeMatch(t,
@@ -174,10 +175,10 @@ func TestNestedNamedMissingParam(t *testing.T) {
func TestIsNamedParamsSC(t *testing.T) {
t.Parallel()
- wt := func(tem tpl.Template) error {
- tem.AddInternalShortcode("byposition.html", `<div id="{{ .Get 0 }}">`)
- tem.AddInternalShortcode("byname.html", `<div id="{{ .Get "id" }}">`)
- tem.AddInternalShortcode("ifnamedparams.html", `<div id="{{ if .IsNamedParams }}{{ .Get "id" }}{{ else }}{{ .Get 0 }}{{end}}">`)
+ wt := func(tem tpl.TemplateHandler) error {
+ tem.AddTemplate("_internal/shortcodes/byposition.html", `<div id="{{ .Get 0 }}">`)
+ tem.AddTemplate("_internal/shortcodes/byname.html", `<div id="{{ .Get "id" }}">`)
+ tem.AddTemplate("_internal/shortcodes/ifnamedparams.html", `<div id="{{ if .IsNamedParams }}{{ .Get "id" }}{{ else }}{{ .Get 0 }}{{end}}">`)
return nil
}
CheckShortCodeMatch(t, `{{< ifnamedparams id="name" >}}`, `<div id="name">`, wt)
@@ -190,8 +191,8 @@ func TestIsNamedParamsSC(t *testing.T) {
func TestInnerSC(t *testing.T) {
t.Parallel()
- wt := func(tem tpl.Template) error {
- tem.AddInternalShortcode("inside.html", `<div{{with .Get "class"}} class="{{.}}"{{end}}>{{ .Inner }}</div>`)
+ wt := func(tem tpl.TemplateHandler) error {
+ tem.AddTemplate("_internal/shortcodes/inside.html", `<div{{with .Get "class"}} class="{{.}}"{{end}}>{{ .Inner }}</div>`)
return nil
}
CheckShortCodeMatch(t, `{{< inside class="aspen" >}}`, `<div class="aspen"></div>`, wt)
@@ -201,8 +202,8 @@ func TestInnerSC(t *testing.T) {
func TestInnerSCWithMarkdown(t *testing.T) {
t.Parallel()
- wt := func(tem tpl.Template) error {
- tem.AddInternalShortcode("inside.html", `<div{{with .Get "class"}} class="{{.}}"{{end}}>{{ .Inner }}</div>`)
+ wt := func(tem tpl.TemplateHandler) error {
+ tem.AddTemplate("_internal/shortcodes/inside.html", `<div{{with .Get "class"}} class="{{.}}"{{end}}>{{ .Inner }}</div>`)
return nil
}
CheckShortCodeMatch(t, `{{% inside %}}
@@ -215,8 +216,8 @@ func TestInnerSCWithMarkdown(t *testing.T) {
func TestInnerSCWithAndWithoutMarkdown(t *testing.T) {
t.Parallel()
- wt := func(tem tpl.Template) error {
- tem.AddInternalShortcode("inside.html", `<div{{with .Get "class"}} class="{{.}}"{{end}}>{{ .Inner }}</div>`)
+ wt := func(tem tpl.TemplateHandler) error {
+ tem.AddTemplate("_internal/shortcodes/inside.html", `<div{{with .Get "class"}} class="{{.}}"{{end}}>{{ .Inner }}</div>`)
return nil
}
CheckShortCodeMatch(t, `{{% inside %}}
@@ -246,9 +247,9 @@ func TestEmbeddedSC(t *testing.T) {
func TestNestedSC(t *testing.T) {
t.Parallel()
- wt := func(tem tpl.Template) error {
- tem.AddInternalShortcode("scn1.html", `<div>Outer, inner is {{ .Inner }}</div>`)
- tem.AddInternalShortcode("scn2.html", `<div>SC2</div>`)
+ wt := func(tem tpl.TemplateHandler) error {
+ tem.AddTemplate("_internal/shortcodes/scn1.html", `<div>Outer, inner is {{ .Inner }}</div>`)
+ tem.AddTemplate("_internal/shortcodes/scn2.html", `<div>SC2</div>`)
return nil
}
CheckShortCodeMatch(t, `{{% scn1 %}}{{% scn2 %}}{{% /scn1 %}}`, "<div>Outer, inner is <div>SC2</div>\n</div>", wt)
@@ -258,10 +259,10 @@ func TestNestedSC(t *testing.T) {
func TestNestedComplexSC(t *testing.T) {
t.Parallel()
- wt := func(tem tpl.Template) error {
- tem.AddInternalShortcode("row.html", `-row-{{ .Inner}}-rowStop-`)
- tem.AddInternalShortcode("column.html", `-col-{{.Inner }}-colStop-`)
- tem.AddInternalShortcode("aside.html", `-aside-{{ .Inner }}-asideStop-`)
+ wt := func(tem tpl.TemplateHandler) error {
+ tem.AddTemplate("_internal/shortcodes/row.html", `-row-{{ .Inner}}-rowStop-`)
+ tem.AddTemplate("_internal/shortcodes/column.html", `-col-{{.Inner }}-colStop-`)
+ tem.AddTemplate("_internal/shortcodes/aside.html", `-aside-{{ .Inner }}-asideStop-`)
return nil
}
CheckShortCodeMatch(t, `{{< row >}}1-s{{% column %}}2-**s**{{< aside >}}3-**s**{{< /aside >}}4-s{{% /column %}}5-s{{< /row >}}6-s`,
@@ -274,10 +275,10 @@ func TestNestedComplexSC(t *testing.T) {
func TestParentShortcode(t *testing.T) {
t.Parallel()
- wt := func(tem tpl.Template) error {
- tem.AddInternalShortcode("r1.html", `1: {{ .Get "pr1" }} {{ .Inner }}`)
- tem.AddInternalShortcode("r2.html", `2: {{ .Parent.Get "pr1" }}{{ .Get "pr2" }} {{ .Inner }}`)
- tem.AddInternalShortcode("r3.html", `3: {{ .Parent.Parent.Get "pr1" }}{{ .Parent.Get "pr2" }}{{ .Get "pr3" }} {{ .Inner }}`)
+ wt := func(tem tpl.TemplateHandler) error {
+ tem.AddTemplate("_internal/shortcodes/r1.html", `1: {{ .Get "pr1" }} {{ .Inner }}`)
+ tem.AddTemplate("_internal/shortcodes/r2.html", `2: {{ .Parent.Get "pr1" }}{{ .Get "pr2" }} {{ .Inner }}`)
+ tem.AddTemplate("_internal/shortcodes/r3.html", `3: {{ .Parent.Parent.Get "pr1" }}{{ .Parent.Get "pr2" }}{{ .Get "pr3" }} {{ .Inner }}`)
return nil
}
CheckShortCodeMatch(t, `{{< r1 pr1="p1" >}}1: {{< r2 pr2="p2" >}}2: {{< r3 pr3="p3" >}}{{< /r3 >}}{{< /r2 >}}{{< /r1 >}}`,
@@ -342,13 +343,13 @@ func TestExtractShortcodes(t *testing.T) {
fmt.Sprintf("Hello %sworld%s. And that's it.", testScPlaceholderRegexp, testScPlaceholderRegexp), ""},
} {
- p, _ := pageFromString(simplePage, "simple.md", func(templ tpl.Template) error {
- templ.AddInternalShortcode("tag.html", `tag`)
- templ.AddInternalShortcode("sc1.html", `sc1`)
- templ.AddInternalShortcode("sc2.html", `sc2`)
- templ.AddInternalShortcode("inner.html", `{{with .Inner }}{{ . }}{{ end }}`)
- templ.AddInternalShortcode("inner2.html", `{{.Inner}}`)
- templ.AddInternalShortcode("inner3.html", `{{.Inner}}`)
+ p, _ := pageFromString(simplePage, "simple.md", func(templ tpl.TemplateHandler) error {
+ templ.AddTemplate("_internal/shortcodes/tag.html", `tag`)
+ templ.AddTemplate("_internal/shortcodes/sc1.html", `sc1`)
+ templ.AddTemplate("_internal/shortcodes/sc2.html", `sc2`)
+ templ.AddTemplate("_internal/shortcodes/inner.html", `{{with .Inner }}{{ . }}{{ end }}`)
+ templ.AddTemplate("_internal/shortcodes/inner2.html", `{{.Inner}}`)
+ templ.AddTemplate("_internal/shortcodes/inner3.html", `{{.Inner}}`)
return nil
})
@@ -517,14 +518,14 @@ tags:
sources[i] = source.ByteSource{Name: filepath.FromSlash(test.contentPath), Content: []byte(test.content)}
}
- addTemplates := func(templ tpl.Template) error {
+ addTemplates := func(templ tpl.TemplateHandler) error {
templ.AddTemplate("_default/single.html", "{{.Content}}")
- templ.AddInternalShortcode("b.html", `b`)
- templ.AddInternalShortcode("c.html", `c`)
- templ.AddInternalShortcode("d.html", `d`)
- templ.AddInternalShortcode("menu.html", `{{ len (index .Page.Menus "main").Children }}`)
- templ.AddInternalShortcode("tags.html", `{{ len .Page.Site.Taxonomies.tags }}`)
+ templ.AddTemplate("_internal/shortcodes/b.html", `b`)
+ templ.AddTemplate("_internal/shortcodes/c.html", `c`)
+ templ.AddTemplate("_internal/shortcodes/d.html", `d`)
+ templ.AddTemplate("_internal/shortcodes/menu.html", `{{ len (index .Page.Menus "main").Children }}`)
+ templ.AddTemplate("_internal/shortcodes/tags.html", `{{ len .Page.Site.Taxonomies.tags }}`)
return nil
diff --git a/hugolib/site.go b/hugolib/site.go
index f8a57dfa2..1808a090e 100644
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -193,7 +193,7 @@ func NewSite(cfg deps.DepsCfg) (*Site, error) {
// NewSiteDefaultLang creates a new site in the default language.
// The site will have a template system loaded and ready to use.
// Note: This is mainly used in single site tests.
-func NewSiteDefaultLang(withTemplate ...func(templ tpl.Template) error) (*Site, error) {
+func NewSiteDefaultLang(withTemplate ...func(templ tpl.TemplateHandler) error) (*Site, error) {
v := viper.New()
loadDefaultSettingsFor(v)
return newSiteForLang(helpers.NewDefaultLanguage(v), withTemplate...)
@@ -202,15 +202,15 @@ func NewSiteDefaultLang(withTemplate ...func(templ tpl.Template) error) (*Site,
// NewEnglishSite creates a new site in English language.
// The site will have a template system loaded and ready to use.
// Note: This is mainly used in single site tests.
-func NewEnglishSite(withTemplate ...func(templ tpl.Template) error) (*Site, error) {
+func NewEnglishSite(withTemplate ...func(templ tpl.TemplateHandler) error) (*Site, error) {
v := viper.New()
loadDefaultSettingsFor(v)
return newSiteForLang(helpers.NewLanguage("en", v), withTemplate...)
}
// newSiteForLang creates a new site in the given language.
-func newSiteForLang(lang *helpers.Language, withTemplate ...func(templ tpl.Template) error) (*Site, error) {
- withTemplates := func(templ tpl.Template) error {
+func newSiteForLang(lang *helpers.Language, withTemplate ...func(templ tpl.TemplateHandler) error) (*Site, error) {
+ withTemplates := func(templ tpl.TemplateHandler) error {
for _, wt := range withTemplate {
if err := wt(templ); err != nil {
return err
@@ -1911,14 +1911,14 @@ Your rendered home page is blank: /index.html is zero-length
}
func (s *Site) renderForLayouts(name string, d interface{}, w io.Writer, layouts ...string) error {
- layout, found := s.findFirstLayout(layouts...)
- if !found {
+ templ := s.findFirstTemplate(layouts...)
+ if templ == nil {
s.Log.WARN.Printf("[%s] Unable to locate layout for %s: %s\n", s.Language.Lang, name, layouts)
return nil
}</