URI: 
       Add support for inline partials - hugo - [fork] hugo port for 9front
  HTML git clone git@git.drkhsh.at/hugo.git
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
   DIR commit 4a3efea7efe59cd3de7d0eb352836ab395a2b6b3
   DIR parent c66dc6c74fa3bbe308ccaade8c76071b49908129
  HTML Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
       Date:   Wed,  1 Jul 2020 10:43:17 +0200
       
       Add support for inline partials
       
       Fixes #7444
       
       Diffstat:
         M docs/content/en/templates/partials… |      15 +++++++++++++++
         M hugolib/hugo_sites_build_errors_te… |       5 ++---
         M hugolib/template_test.go            |      80 +++++++++++++++++++++++++++++++
         M tpl/tplimpl/template.go             |      79 ++++++++++++++++++++++++++++++-
       
       4 files changed, 175 insertions(+), 4 deletions(-)
       ---
   DIR diff --git a/docs/content/en/templates/partials.md b/docs/content/en/templates/partials.md
       @@ -81,6 +81,21 @@ This means the partial will *only* be able to access those variables. The partia
        
        In addition to outputting markup, partials can be used to return a value of any type. In order to return a value, a partial must include a lone `return` statement.
        
       +## Inline partials
       +
       +{{< new-in "0.74.0" >}}
       +
       +You can also define partials inline in the template. But remember that template namespace is global, so you need to make sure that the names are unique to avoid conflicts.
       +
       +```go-html-template
       +Value: {{ partial "my-inline-partial" . }}
       +
       +{{ define "partials/my-inline-partial" }}
       +{{ $value := 32 }}
       +{{ return $value }}
       +{{ end }}
       +```
       +
        ### Example GetFeatured
        ```go-html-template
        {{/* layouts/partials/GetFeatured.html */}}
   DIR diff --git a/hugolib/hugo_sites_build_errors_test.go b/hugolib/hugo_sites_build_errors_test.go
       @@ -65,8 +65,7 @@ func TestSiteBuildErrors(t *testing.T) {
                                fileFixer: func(content string) string {
                                        return strings.Replace(content, ".Title }}", ".Title }", 1)
                                },
       -                        // Base templates gets parsed at build time.
       -                        assertBuildError: func(a testSiteBuildErrorAsserter, err error) {
       +                        assertCreateError: func(a testSiteBuildErrorAsserter, err error) {
                                        a.assertLineNumber(4, err)
                                },
                        },
       @@ -91,7 +90,7 @@ func TestSiteBuildErrors(t *testing.T) {
                                        a.c.Assert(fe.Position().LineNumber, qt.Equals, 5)
                                        a.c.Assert(fe.Position().ColumnNumber, qt.Equals, 1)
                                        a.c.Assert(fe.ChromaLexer, qt.Equals, "go-html-template")
       -                                a.assertErrorMessage("\"layouts/foo/single.html:5:1\": parse failed: template: foo/single.html:5: unexpected \"}\" in operand", fe.Error())
       +                                a.assertErrorMessage("\"layouts/_default/single.html:5:1\": parse failed: template: _default/single.html.___b:5: unexpected \"}\" in operand", fe.Error())
        
                                },
                        },
   DIR diff --git a/hugolib/template_test.go b/hugolib/template_test.go
       @@ -597,3 +597,83 @@ func collectIdentities(set map[identity.Identity]bool, provider identity.Provide
        func ident(level int) string {
                return strings.Repeat(" ", level)
        }
       +
       +func TestPartialInline(t *testing.T) {
       +
       +        b := newTestSitesBuilder(t)
       +
       +        b.WithContent("p1.md", "")
       +
       +        b.WithTemplates(
       +                "index.html", `
       +
       +{{ $p1 := partial "p1" . }}
       +{{ $p2 := partial "p2" . }}
       +
       +P1: {{ $p1 }}
       +P2: {{ $p2 }}
       +
       +{{ define "partials/p1" }}Inline: p1{{ end }}
       +
       +{{ define "partials/p2" }}
       +{{ $value := 32 }}
       +{{ return $value }}
       +{{ end }}
       +
       +
       +`,
       +        )
       +
       +        b.CreateSites().Build(BuildCfg{})
       +
       +        b.AssertFileContent("public/index.html",
       +                `
       +P1: Inline: p1
       +P2: 32`,
       +        )
       +
       +}
       +
       +func TestPartialInlineBase(t *testing.T) {
       +
       +        b := newTestSitesBuilder(t)
       +
       +        b.WithContent("p1.md", "")
       +
       +        b.WithTemplates(
       +                "baseof.html", `{{ $p3 := partial "p3" . }}P3: {{ $p3 }}
       +{{ block "main" . }}{{ end }}{{ define "partials/p3" }}Inline: p3{{ end }}`,
       +                "index.html", `
       +{{ define "main" }}
       +
       +{{ $p1 := partial "p1" . }}
       +{{ $p2 := partial "p2" . }}
       +
       +P1: {{ $p1 }}
       +P2: {{ $p2 }}
       +
       +{{ end }}
       +
       +
       +{{ define "partials/p1" }}Inline: p1{{ end }}
       +
       +{{ define "partials/p2" }}
       +{{ $value := 32 }}
       +{{ return $value }}
       +{{ end }}
       +
       +
       +`,
       +        )
       +
       +        b.CreateSites().Build(BuildCfg{})
       +
       +        b.AssertFileContent("public/index.html",
       +                `
       +P1: Inline: p1
       +P2: 32
       +P3: Inline: p3
       +`,
       +        )
       +
       +}
   DIR diff --git a/tpl/tplimpl/template.go b/tpl/tplimpl/template.go
       @@ -553,12 +553,24 @@ func (t *templateHandler) addTemplateFile(name, path string) error {
                if isBaseTemplatePath(name) {
                        // Store it for later.
                        t.baseof[name] = tinfo
       +                // Also parse and add it on its own to make sure we reach the inline partials.
       +                tinfo.name = name + ".___b"
       +                _, err := t.addTemplateTo(tinfo, t.main)
       +                if err != nil {
       +                        return tinfo.errWithFileContext("parse failed", err)
       +                }
                        return nil
                }
        
                needsBaseof := !t.noBaseNeeded(name) && needsBaseTemplate(tinfo.template)
                if needsBaseof {
                        t.needsBaseof[name] = tinfo
       +                // Also parse and add it on its own to make sure we reach the inline partials.
       +                tinfo.name = name + ".___b"
       +                _, err := t.addTemplateTo(tinfo, t.main)
       +                if err != nil {
       +                        return tinfo.errWithFileContext("parse failed", err)
       +                }
                        return nil
                }
        
       @@ -720,10 +732,51 @@ func (t *templateHandler) noBaseNeeded(name string) bool {
        }
        
        func (t *templateHandler) postTransform() error {
       +        defineCheckedHTML := false
       +        defineCheckedText := false
       +
                for _, v := range t.main.templates {
                        if v.typ == templateShortcode {
                                t.addShortcodeVariant(v)
                        }
       +
       +                if defineCheckedHTML && defineCheckedText {
       +                        continue
       +                }
       +
       +                isText := isText(v.Template)
       +                if isText {
       +                        if defineCheckedText {
       +                                continue
       +                        }
       +                        defineCheckedText = true
       +                } else {
       +                        if defineCheckedHTML {
       +                                continue
       +                        }
       +                        defineCheckedHTML = true
       +                }
       +
       +                templs := templates(v.Template)
       +                for _, templ := range templs {
       +                        if templ.Name() == "" || !strings.HasPrefix(templ.Name(), "partials/") {
       +                                continue
       +                        }
       +
       +                        ts := newTemplateState(templ, templateInfo{name: templ.Name()})
       +                        ts.typ = templatePartial
       +
       +                        if _, found := t.main.templates[templ.Name()]; !found {
       +                                // This is a template defined inline.
       +
       +                                _, err := applyTemplateTransformers(ts, t.main.newTemplateLookup(ts))
       +                                if err != nil {
       +                                        return err
       +                                }
       +                                t.main.templates[templ.Name()] = ts
       +
       +                        }
       +                }
                }
        
                for name, source := range t.transformNotFound {
       @@ -872,8 +925,13 @@ func (t *templateState) ParseInfo() tpl.ParseInfo {
        }
        
        func (t *templateState) isText() bool {
       -        _, isText := t.Template.(*texttemplate.Template)
       +        return isText(t.Template)
       +}
       +
       +func isText(templ tpl.Template) bool {
       +        _, isText := templ.(*texttemplate.Template)
                return isText
       +
        }
        
        type templateStateMap struct {
       @@ -960,3 +1018,22 @@ func unwrap(templ tpl.Template) tpl.Template {
                }
                return templ
        }
       +
       +func templates(in tpl.Template) []tpl.Template {
       +        var templs []tpl.Template
       +        in = unwrap(in)
       +        if textt, ok := in.(*texttemplate.Template); ok {
       +                for _, t := range textt.Templates() {
       +                        templs = append(templs, t)
       +                }
       +        }
       +
       +        if htmlt, ok := in.(*htmltemplate.Template); ok {
       +                for _, t := range htmlt.Templates() {
       +                        templs = append(templs, t)
       +                }
       +        }
       +
       +        return templs
       +
       +}