Fix output format handling for render hooks
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Tue, 9 Mar 2021 09:26:44 +0000 (10:26 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Tue, 9 Mar 2021 12:26:39 +0000 (13:26 +0100)
Fixes #8176

hugolib/content_render_hooks_test.go
hugolib/page.go
hugolib/page__output.go
hugolib/page__per_output.go
markup/converter/converter.go
markup/converter/hooks/hooks.go
markup/goldmark/render_hooks.go

index 218ad918b58515094561a1b01bca2ad9c721de7d..9791683052961ecae337356b48c76b599edc6a7b 100644 (file)
@@ -315,8 +315,10 @@ func TestRenderHooksRSS(t *testing.T) {
 
        b.WithTemplates("index.html", `
 {{ $p := site.GetPage "p1.md" }}
+{{ $p2 := site.GetPage "p2.md" }}
 
 P1: {{ $p.Content }}
+P2: {{ $p2.Content }}
        
        `, "index.xml", `
 
@@ -330,6 +332,8 @@ P3: {{ $p3.Content }}
        `,
                "_default/_markup/render-link.html", `html-link: {{ .Destination | safeURL }}|`,
                "_default/_markup/render-link.rss.xml", `xml-link: {{ .Destination | safeURL }}|`,
+               "_default/_markup/render-heading.html", `html-heading: {{ .Text }}|`,
+               "_default/_markup/render-heading.rss.xml", `xml-heading: {{ .Text }}|`,
        )
 
        b.WithContent("p1.md", `---
@@ -337,12 +341,14 @@ title: "p1"
 ---
 P1. [I'm an inline-style link](https://www.gohugo.io)
 
+# Heading in p1
 
 `, "p2.md", `---
 title: "p2"
 ---
 P1. [I'm an inline-style link](https://www.bep.is)
 
+# Heading in p2
 
 `,
                "p3.md", `---
@@ -356,10 +362,15 @@ P3. [I'm an inline-style link](https://www.example.org)
 
        b.Build(BuildCfg{})
 
-       b.AssertFileContent("public/index.html", "P1: <p>P1. html-link: https://www.gohugo.io|</p>")
+       b.AssertFileContent("public/index.html", `
+P1: <p>P1. html-link: https://www.gohugo.io|</p>
+html-heading: Heading in p1|
+html-heading: Heading in p2|
+`)
        b.AssertFileContent("public/index.xml", `
 P2: <p>P1. xml-link: https://www.bep.is|</p>
 P3: <p>P3. xml-link: https://www.example.org|</p>
+xml-heading: Heading in p2|
 `)
 }
 
index 6c177b6878fb462d8340ba6c9f82a5a5a1ba81c5..6099fb21a5f7e68477311f7177fe0b4294d22c64 100644 (file)
@@ -390,7 +390,7 @@ func (ps *pageState) initCommonProviders(pp pagePaths) error {
        return nil
 }
 
-func (p *pageState) createRenderHooks(f output.Format) (*hooks.Renderers, error) {
+func (p *pageState) createRenderHooks(f output.Format) (hooks.Renderers, error) {
        layoutDescriptor := p.getLayoutDescriptor()
        layoutDescriptor.RenderingHook = true
        layoutDescriptor.LayoutOverride = false
@@ -401,7 +401,7 @@ func (p *pageState) createRenderHooks(f output.Format) (*hooks.Renderers, error)
        layoutDescriptor.Kind = "render-link"
        templ, templFound, err := p.s.Tmpl().LookupLayout(layoutDescriptor, f)
        if err != nil {
-               return nil, err
+               return renderers, err
        }
        if templFound {
                renderers.LinkRenderer = hookRenderer{
@@ -414,7 +414,7 @@ func (p *pageState) createRenderHooks(f output.Format) (*hooks.Renderers, error)
        layoutDescriptor.Kind = "render-image"
        templ, templFound, err = p.s.Tmpl().LookupLayout(layoutDescriptor, f)
        if err != nil {
-               return nil, err
+               return renderers, err
        }
        if templFound {
                renderers.ImageRenderer = hookRenderer{
@@ -427,7 +427,7 @@ func (p *pageState) createRenderHooks(f output.Format) (*hooks.Renderers, error)
        layoutDescriptor.Kind = "render-heading"
        templ, templFound, err = p.s.Tmpl().LookupLayout(layoutDescriptor, f)
        if err != nil {
-               return nil, err
+               return renderers, err
        }
        if templFound {
                renderers.HeadingRenderer = hookRenderer{
@@ -437,7 +437,7 @@ func (p *pageState) createRenderHooks(f output.Format) (*hooks.Renderers, error)
                }
        }
 
-       return &renderers, nil
+       return renderers, nil
 }
 
 func (p *pageState) getLayoutDescriptor() output.LayoutDescriptor {
index a3235db49dede3fefd96b66896932c73057ebf6b..377e16df522191f1972976db34899d28d39b473d 100644 (file)
@@ -107,12 +107,39 @@ func (o *pageOutput) initRenderHooks() error {
                h, err := ps.createRenderHooks(o.f)
                if err != nil {
                        initErr = err
-               }
-               if h == nil {
                        return
                }
-
                o.cp.renderHooks.hooks = h
+
+               if !o.cp.renderHooksHaveVariants || h.IsZero() {
+                       // Check if there is a different render hooks template
+                       // for any of the other page output formats.
+                       // If not, we can reuse this.
+                       for _, po := range ps.pageOutputs {
+                               if po.f.Name != o.f.Name {
+                                       h2, err := ps.createRenderHooks(po.f)
+                                       if err != nil {
+                                               initErr = err
+                                               return
+                                       }
+
+                                       if h2.IsZero() {
+                                               continue
+                                       }
+
+                                       if o.cp.renderHooks.hooks.IsZero() {
+                                               o.cp.renderHooks.hooks = h2
+                                       }
+
+                                       o.cp.renderHooksHaveVariants = !h2.Eq(o.cp.renderHooks.hooks)
+
+                                       if o.cp.renderHooksHaveVariants {
+                                               break
+                                       }
+
+                               }
+                       }
+               }
        })
 
        return initErr
index dfc82c062737ab069e806ada9b5700ffaa5bb0cc..f59b5f9b545ee3538a6a30b204f49913b67063a0 100644 (file)
@@ -226,7 +226,7 @@ func newPageContentOutput(p *pageState, po *pageOutput) (*pageContentOutput, err
 }
 
 type renderHooks struct {
-       hooks *hooks.Renderers
+       hooks hooks.Renderers
        init  sync.Once
 }
 
index d7e3d4639a5396daa137e510e02e766065e6ad3e..3fa3bea39bb5d0be58588b1ec819bc9dae087080 100644 (file)
@@ -127,7 +127,7 @@ type DocumentContext struct {
 type RenderContext struct {
        Src         []byte
        RenderTOC   bool
-       RenderHooks *hooks.Renderers
+       RenderHooks hooks.Renderers
 }
 
 var FeatureRenderHooks = identity.NewPathIdentity("markup", "renderingHooks")
index 6f08a2161f9a07dd0f252bd9256babccffe574c0..d36dad288069f4f7a78ec195a890573f2eec2094 100644 (file)
@@ -14,7 +14,9 @@
 package hooks
 
 import (
+       "fmt"
        "io"
+       "strings"
 
        "github.com/gohugoio/hugo/identity"
 )
@@ -67,26 +69,64 @@ type Renderers struct {
        HeadingRenderer HeadingRenderer
 }
 
-func (r *Renderers) Eq(other interface{}) bool {
-       ro, ok := other.(*Renderers)
+func (r Renderers) Eq(other interface{}) bool {
+       ro, ok := other.(Renderers)
        if !ok {
                return false
        }
-       if r == nil || ro == nil {
-               return r == nil
+
+       if r.IsZero() || ro.IsZero() {
+               return r.IsZero() && ro.IsZero()
        }
 
-       if r.ImageRenderer.GetIdentity() != ro.ImageRenderer.GetIdentity() {
+       var b1, b2 bool
+       b1, b2 = r.ImageRenderer == nil, ro.ImageRenderer == nil
+       if (b1 || b2) && (b1 != b2) {
+               return false
+       }
+       if !b1 && r.ImageRenderer.GetIdentity() != ro.ImageRenderer.GetIdentity() {
                return false
        }
 
-       if r.LinkRenderer.GetIdentity() != ro.LinkRenderer.GetIdentity() {
+       b1, b2 = r.LinkRenderer == nil, ro.LinkRenderer == nil
+       if (b1 || b2) && (b1 != b2) {
+               return false
+       }
+       if !b1 && r.LinkRenderer.GetIdentity() != ro.LinkRenderer.GetIdentity() {
                return false
        }
 
-       if r.HeadingRenderer.GetIdentity() != ro.HeadingRenderer.GetIdentity() {
+       b1, b2 = r.HeadingRenderer == nil, ro.HeadingRenderer == nil
+       if (b1 || b2) && (b1 != b2) {
+               return false
+       }
+       if !b1 && r.HeadingRenderer.GetIdentity() != ro.HeadingRenderer.GetIdentity() {
                return false
        }
 
        return true
 }
+
+func (r Renderers) IsZero() bool {
+       return r.HeadingRenderer == nil && r.LinkRenderer == nil && r.ImageRenderer == nil
+}
+
+func (r Renderers) String() string {
+       if r.IsZero() {
+               return "<zero>"
+       }
+
+       var sb strings.Builder
+
+       if r.LinkRenderer != nil {
+               sb.WriteString(fmt.Sprintf("LinkRenderer<%s>|", r.LinkRenderer.GetIdentity()))
+       }
+       if r.HeadingRenderer != nil {
+               sb.WriteString(fmt.Sprintf("HeadingRenderer<%s>|", r.HeadingRenderer.GetIdentity()))
+       }
+       if r.ImageRenderer != nil {
+               sb.WriteString(fmt.Sprintf("ImageRenderer<%s>|", r.ImageRenderer.GetIdentity()))
+       }
+
+       return sb.String()
+}
index 41db4011bd3c6056d4008966f77f3a56d45ebffc..5e0865a70b69e92e25575fda817247c5d0904e14 100644 (file)
@@ -206,12 +206,12 @@ func (r *hookedRenderer) renderDefaultImage(w util.BufWriter, source []byte, nod
 
 func (r *hookedRenderer) renderImage(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
        n := node.(*ast.Image)
-       var h *hooks.Renderers
+       var h hooks.Renderers
 
        ctx, ok := w.(*renderContext)
        if ok {
                h = ctx.RenderContext().RenderHooks
-               ok = h != nil && h.ImageRenderer != nil
+               ok = h.ImageRenderer != nil
        }
 
        if !ok {
@@ -267,12 +267,12 @@ func (r *hookedRenderer) renderDefaultLink(w util.BufWriter, source []byte, node
 
 func (r *hookedRenderer) renderLink(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
        n := node.(*ast.Link)
-       var h *hooks.Renderers
+       var h hooks.Renderers
 
        ctx, ok := w.(*renderContext)
        if ok {
                h = ctx.RenderContext().RenderHooks
-               ok = h != nil && h.LinkRenderer != nil
+               ok = h.LinkRenderer != nil
        }
 
        if !ok {
@@ -326,12 +326,12 @@ func (r *hookedRenderer) renderDefaultHeading(w util.BufWriter, source []byte, n
 
 func (r *hookedRenderer) renderHeading(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
        n := node.(*ast.Heading)
-       var h *hooks.Renderers
+       var h hooks.Renderers
 
        ctx, ok := w.(*renderContext)
        if ok {
                h = ctx.RenderContext().RenderHooks
-               ok = h != nil && h.HeadingRenderer != nil
+               ok = h.HeadingRenderer != nil
        }
 
        if !ok {