summaryrefslogtreecommitdiffstats
path: root/hugolib
diff options
context:
space:
mode:
Diffstat (limited to 'hugolib')
-rw-r--r--hugolib/content_factory.go3
-rw-r--r--hugolib/content_map_page.go2
-rw-r--r--hugolib/embedded_shortcodes_test.go3
-rw-r--r--hugolib/hugo_sites.go14
-rw-r--r--hugolib/hugo_sites_build.go2
-rw-r--r--hugolib/hugo_sites_build_errors_test.go2
-rw-r--r--hugolib/image_test.go153
-rw-r--r--hugolib/language_content_dir_test.go3
-rw-r--r--hugolib/page.go48
-rw-r--r--hugolib/page__content.go14
-rw-r--r--hugolib/page__menus.go7
-rw-r--r--hugolib/page__new.go3
-rw-r--r--hugolib/page__per_output.go219
-rw-r--r--hugolib/page__position.go6
-rw-r--r--hugolib/page_test.go53
-rw-r--r--hugolib/shortcode.go101
-rw-r--r--hugolib/shortcode_page.go41
-rw-r--r--hugolib/shortcode_test.go28
-rw-r--r--hugolib/site.go22
-rw-r--r--hugolib/site_render.go3
-rw-r--r--hugolib/site_test.go7
-rw-r--r--hugolib/testhelpers_test.go3
22 files changed, 394 insertions, 343 deletions
diff --git a/hugolib/content_factory.go b/hugolib/content_factory.go
index 017a0bc97..e22f46513 100644
--- a/hugolib/content_factory.go
+++ b/hugolib/content_factory.go
@@ -14,6 +14,7 @@
package hugolib
import (
+ "context"
"fmt"
"io"
"path/filepath"
@@ -83,7 +84,7 @@ func (f ContentFactory) ApplyArchetypeTemplate(w io.Writer, p page.Page, archety
return fmt.Errorf("failed to parse archetype template: %s: %w", err, err)
}
- result, err := executeToString(ps.s.Tmpl(), templ, d)
+ result, err := executeToString(context.TODO(), ps.s.Tmpl(), templ, d)
if err != nil {
return fmt.Errorf("failed to execute archetype template: %s: %w", err, err)
}
diff --git a/hugolib/content_map_page.go b/hugolib/content_map_page.go
index d8f28286c..70c5d6a27 100644
--- a/hugolib/content_map_page.go
+++ b/hugolib/content_map_page.go
@@ -171,7 +171,7 @@ func (m *pageMap) newPageFromContentNode(n *contentNode, parentBucket *pagesMapB
return nil, err
}
- ps.init.Add(func() (any, error) {
+ ps.init.Add(func(context.Context) (any, error) {
pp, err := newPagePaths(s, ps, metaProvider)
if err != nil {
return nil, err
diff --git a/hugolib/embedded_shortcodes_test.go b/hugolib/embedded_shortcodes_test.go
index 1707bcfa7..1e06494bf 100644
--- a/hugolib/embedded_shortcodes_test.go
+++ b/hugolib/embedded_shortcodes_test.go
@@ -14,6 +14,7 @@
package hugolib
import (
+ "context"
"encoding/json"
"fmt"
"html/template"
@@ -70,7 +71,7 @@ func doTestShortcodeCrossrefs(t *testing.T, relative bool) {
c.Assert(len(s.RegularPages()), qt.Equals, 1)
- content, err := s.RegularPages()[0].Content()
+ content, err := s.RegularPages()[0].Content(context.Background())
c.Assert(err, qt.IsNil)
output := cast.ToString(content)
diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go
index 569c27be5..cdc5d97fb 100644
--- a/hugolib/hugo_sites.go
+++ b/hugolib/hugo_sites.go
@@ -194,7 +194,7 @@ func (h *hugoSitesInit) Reset() {
}
func (h *HugoSites) Data() map[string]any {
- if _, err := h.init.data.Do(); err != nil {
+ if _, err := h.init.data.Do(context.Background()); err != nil {
h.SendError(fmt.Errorf("failed to load data: %w", err))
return nil
}
@@ -202,7 +202,7 @@ func (h *HugoSites) Data() map[string]any {
}
func (h *HugoSites) gitInfoForPage(p page.Page) (source.GitInfo, error) {
- if _, err := h.init.gitInfo.Do(); err != nil {
+ if _, err := h.init.gitInfo.Do(context.Background()); err != nil {
return source.GitInfo{}, err
}
@@ -214,7 +214,7 @@ func (h *HugoSites) gitInfoForPage(p page.Page) (source.GitInfo, error) {
}
func (h *HugoSites) codeownersForPage(p page.Page) ([]string, error) {
- if _, err := h.init.gitInfo.Do(); err != nil {
+ if _, err := h.init.gitInfo.Do(context.Background()); err != nil {
return nil, err
}
@@ -363,7 +363,7 @@ func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) {
donec: make(chan bool),
}
- h.init.data.Add(func() (any, error) {
+ h.init.data.Add(func(context.Context) (any, error) {
err := h.loadData(h.PathSpec.BaseFs.Data.Dirs)
if err != nil {
return nil, fmt.Errorf("failed to load data: %w", err)
@@ -371,7 +371,7 @@ func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) {
return nil, nil
})
- h.init.layouts.Add(func() (any, error) {
+ h.init.layouts.Add(func(context.Context) (any, error) {
for _, s := range h.Sites {
if err := s.Tmpl().(tpl.TemplateManager).MarkReady(); err != nil {
return nil, err
@@ -380,7 +380,7 @@ func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) {
return nil, nil
})
- h.init.translations.Add(func() (any, error) {
+ h.init.translations.Add(func(context.Context) (any, error) {
if len(h.Sites) > 1 {
allTranslations := pagesToTranslationsMap(h.Sites)
assignTranslationsToPages(allTranslations, h.Sites)
@@ -389,7 +389,7 @@ func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) {
return nil, nil
})
- h.init.gitInfo.Add(func() (any, error) {
+ h.init.gitInfo.Add(func(context.Context) (any, error) {
err := h.loadGitInfo()
if err != nil {
return nil, fmt.Errorf("failed to load Git info: %w", err)
diff --git a/hugolib/hugo_sites_build.go b/hugolib/hugo_sites_build.go
index 5eee564aa..66abf4f16 100644
--- a/hugolib/hugo_sites_build.go
+++ b/hugolib/hugo_sites_build.go
@@ -268,7 +268,7 @@ func (h *HugoSites) assemble(bcfg *BuildCfg) error {
}
func (h *HugoSites) render(config *BuildCfg) error {
- if _, err := h.init.layouts.Do(); err != nil {
+ if _, err := h.init.layouts.Do(context.Background()); err != nil {
return err
}
diff --git a/hugolib/hugo_sites_build_errors_test.go b/hugolib/hugo_sites_build_errors_test.go
index ffbfe1c17..f42b44461 100644
--- a/hugolib/hugo_sites_build_errors_test.go
+++ b/hugolib/hugo_sites_build_errors_test.go
@@ -396,7 +396,7 @@ line 4
}
-func TestErrorNestedShortocde(t *testing.T) {
+func TestErrorNestedShortcode(t *testing.T) {
t.Parallel()
files := `
diff --git a/hugolib/image_test.go b/hugolib/image_test.go
index ac18b9423..db1707c22 100644
--- a/hugolib/image_test.go
+++ b/hugolib/image_test.go
@@ -14,162 +14,9 @@
package hugolib
import (
- "io"
- "os"
- "path/filepath"
- "runtime"
- "strings"
"testing"
-
- "github.com/gohugoio/hugo/config"
- "github.com/gohugoio/hugo/htesting"
-
- qt "github.com/frankban/quicktest"
- "github.com/gohugoio/hugo/hugofs"
)
-// We have many tests for the different resize operations etc. in the resource package,
-// this is an integration test.
-func TestImageOps(t *testing.T) {
- c := qt.New(t)
- // Make this a real as possible.
- workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "image-resize")
- c.Assert(err, qt.IsNil)
- defer clean()
-
- newBuilder := func(timeout any) *sitesBuilder {
- v := config.NewWithTestDefaults()
- v.Set("workingDir", workDir)
- v.Set("baseURL", "https://example.org")
- v.Set("timeout", timeout)
-
- b := newTestSitesBuilder(t).WithWorkingDir(workDir)
- b.Fs = hugofs.NewDefault(v)
- b.WithViper(v)
- b.WithContent("mybundle/index.md", `
----
-title: "My bundle"
----
-
-{{< imgproc >}}
-
-`)
-
- b.WithTemplatesAdded(
- "shortcodes/imgproc.html", `
-{{ $img := resources.Get "images/sunset.jpg" }}
-{{ $r := $img.Resize "129x239" }}
-IMG SHORTCODE: {{ $r.RelPermalink }}/{{ $r.Width }}
-`,
- "index.html", `
-{{ $p := .Site.GetPage "mybundle" }}
-{{ $img1 := resources.Get "images/sunset.jpg" }}
-{{ $img2 := $p.Resources.GetMatch "sunset.jpg" }}
-{{ $img3 := resources.GetMatch "images/*.jpg" }}
-{{ $r := $img1.Resize "123x234" }}
-{{ $r2 := $r.Resize "12x23" }}
-{{ $b := $img2.Resize "345x678" }}
-{{ $b2 := $b.Resize "34x67" }}
-{{ $c := $img3.Resize "456x789" }}
-{{ $fingerprinted := $img1.Resize "350x" | fingerprint }}
-
-{{ $images := slice $r $r2 $b $b2 $c $fingerprinted }}
-
-{{ range $i, $r := $images }}
-{{ printf "Resized%d:" (add $i 1) }} {{ $r.Name }}|{{ $r.Width }}|{{ $r.Height }}|{{ $r.MediaType }}|{{ $r.RelPermalink }}|
-{{ end }}
-
-{{ $blurryGrayscale1 := $r | images.Filter images.Grayscale (images.GaussianBlur 8) }}
-BG1: {{ $blurryGrayscale1.RelPermalink }}/{{ $blurryGrayscale1.Width }}
-{{ $blurryGrayscale2 := $r.Filter images.Grayscale (images.GaussianBlur 8) }}
-BG2: {{ $blurryGrayscale2.RelPermalink }}/{{ $blurryGrayscale2.Width }}
-{{ $blurryGrayscale2_2 := $r.Filter images.Grayscale (images.GaussianBlur 8) }}
-BG2_2: {{ $blurryGrayscale2_2.RelPermalink }}/{{ $blurryGrayscale2_2.Width }}
-
-{{ $filters := slice images.Grayscale (images.GaussianBlur 9) }}
-{{ $blurryGrayscale3 := $r | images.Filter $filters }}
-BG3: {{ $blurryGrayscale3.RelPermalink }}/{{ $blurryGrayscale3.Width }}
-
-{{ $blurryGrayscale4 := $r.Filter $filters }}
-BG4: {{ $blurryGrayscale4.RelPermalink }}/{{ $blurryGrayscale4.Width }}
-
-{{ $p.Content }}
-
-`)
-
- return b
- }
-
- imageDir := filepath.Join(workDir, "assets", "images")
- bundleDir := filepath.Join(workDir, "content", "mybundle")
-
- c.Assert(os.MkdirAll(imageDir, 0777), qt.IsNil)
- c.Assert(os.MkdirAll(bundleDir, 0777), qt.IsNil)
- src, err := os.Open("testdata/sunset.jpg")
- c.Assert(err, qt.IsNil)
- out, err := os.Create(filepath.Join(imageDir, "sunset.jpg"))
- c.Assert(err, qt.IsNil)
- _, err = io.Copy(out, src)
- c.Assert(err, qt.IsNil)
- out.Close()
-
- src.Seek(0, 0)
-
- out, err = os.Create(filepath.Join(bundleDir, "sunset.jpg"))
- c.Assert(err, qt.IsNil)
- _, err = io.Copy(out, src)
- c.Assert(err, qt.IsNil)
- out.Close()
- src.Close()
-
- // First build it with a very short timeout to trigger errors.
- b := newBuilder("10ns")
-
- imgExpect := `
-Resized1: images/sunset.jpg|123|234|image/jpeg|/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_123x234_resize_q75_box.jpg|
-Resized2: images/sunset.jpg|12|23|image/jpeg|/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_ada4bb1a57f77a63306e3bd67286248e.jpg|
-Resized3: sunset.jpg|345|678|image/jpeg|/mybundle/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_345x678_resize_q75_box.jpg|
-Resized4: sunset.jpg|34|67|image/jpeg|/mybundle/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_44d8c928664d7c5a67377c6ec58425ce.jpg|
-Resized5: images/sunset.jpg|456|789|image/jpeg|/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_456x789_resize_q75_box.jpg|
-Resized6: images/sunset.jpg|350|219|image/jpeg|/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_350x0_resize_q75_box.a86fe88d894e5db613f6aa8a80538fefc25b20fa24ba0d782c057adcef616f56.jpg|
-BG1: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_2ae8bb993431ec1aec40fe59927b46b4.jpg/123
-BG2: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_2ae8bb993431ec1aec40fe59927b46b4.jpg/123
-BG3: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_ed7740a90b82802261c2fbdb98bc8082.jpg/123
-BG4: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_ed7740a90b82802261c2fbdb98bc8082.jpg/123
-IMG SHORTCODE: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_129x239_resize_q75_box.jpg/129
-`
-
- assertImages := func() {
- b.Helper()
- b.AssertFileContent("public/index.html", imgExpect)
- b.AssertImage(350, 219, "public/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_350x0_resize_q75_box.a86fe88d894e5db613f6aa8a80538fefc25b20fa24ba0d782c057adcef616f56.jpg")
- b.AssertImage(129, 239, "public/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_129x239_resize_q75_box.jpg")
- }
-
- err = b.BuildE(BuildCfg{})
- if runtime.GOOS != "windows" && !strings.Contains(runtime.GOARCH, "arm") && !htesting.IsGitHubAction() {
- // TODO(bep)
- c.Assert(err, qt.Not(qt.IsNil))
- }
-
- b = newBuilder(29000)
- b.Build(BuildCfg{})
-
- assertImages()
-
- // Truncate one image.
- imgInCache := filepath.Join(workDir, "resources/_gen/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_ed7740a90b82802261c2fbdb98bc8082.jpg")
- f, err := os.Create(imgInCache)
- c.Assert(err, qt.IsNil)
- f.Close()
-
- // Build it again to make sure we read images from file cache.
- b = newBuilder("30s")
- b.Build(BuildCfg{})
-
- assertImages()
-}
-
func TestImageResizeMultilingual(t *testing.T) {
b := newTestSitesBuilder(t).WithConfigFile("toml", `
baseURL="https://example.org"
diff --git a/hugolib/language_content_dir_test.go b/hugolib/language_content_dir_test.go
index 57cdab67b..23809f4df 100644
--- a/hugolib/language_content_dir_test.go
+++ b/hugolib/language_content_dir_test.go
@@ -14,6 +14,7 @@
package hugolib
import (
+ "context"
"fmt"
"os"
"path/filepath"
@@ -245,7 +246,7 @@ Content.
c.Assert(svP2.Language().Lang, qt.Equals, "sv")
c.Assert(nnP2.Language().Lang, qt.Equals, "nn")
- content, _ := nnP2.Content()
+ content, _ := nnP2.Content(context.Background())
contentStr := cast.ToString(content)
c.Assert(contentStr, qt.Contains, "SVP3-REF: https://example.org/sv/sect/p-sv-3/")
c.Assert(contentStr, qt.Contains, "SVP3-RELREF: /sv/sect/p-sv-3/")
diff --git a/hugolib/page.go b/hugolib/page.go
index 97f1ed351..40972d7c5 100644
--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -15,6 +15,7 @@ package hugolib
import (
"bytes"
+ "context"
"fmt"
"path"
"path/filepath"
@@ -24,8 +25,10 @@ import (
"go.uber.org/atomic"
"github.com/gohugoio/hugo/identity"
+ "github.com/gohugoio/hugo/related"
"github.com/gohugoio/hugo/markup/converter"
+ "github.com/gohugoio/hugo/markup/tableofcontents"
"github.com/gohugoio/hugo/tpl"
@@ -148,6 +151,43 @@ func (p *pageState) GetIdentity() identity.Identity {
return identity.NewPathIdentity(files.ComponentFolderContent, filepath.FromSlash(p.Pathc()))
}
+func (p *pageState) Fragments(ctx context.Context) *tableofcontents.Fragments {
+ p.s.initInit(ctx, p.cp.initToC, p)
+ if p.pageOutput.cp.tableOfContents == nil {
+ return tableofcontents.Empty
+ }
+ return p.pageOutput.cp.tableOfContents
+}
+
+func (p *pageState) HeadingsFiltered(context.Context) tableofcontents.Headings {
+ return nil
+}
+
+type pageHeadingsFiltered struct {
+ *pageState
+ headings tableofcontents.Headings
+}
+
+func (p *pageHeadingsFiltered) HeadingsFiltered(context.Context) tableofcontents.Headings {
+ return p.headings
+}
+
+func (p *pageHeadingsFiltered) page() page.Page {
+ return p.pageState
+}
+
+// For internal use by the related content feature.
+func (p *pageState) ApplyFilterToHeadings(ctx context.Context, fn func(*tableofcontents.Heading) bool) related.Document {
+ if p.pageOutput.cp.tableOfContents == nil {
+ return p
+ }
+ headings := p.pageOutput.cp.tableOfContents.Headings.FilterBy(fn)
+ return &pageHeadingsFiltered{
+ pageState: p,
+ headings: headings,
+ }
+}
+
func (p *pageState) GitInfo() source.GitInfo {
return p.gitInfo
}
@@ -351,7 +391,7 @@ func (p *pageState) String() string {
// IsTranslated returns whether this content file is translated to
// other language(s).
func (p *pageState) IsTranslated() bool {
- p.s.h.init.translations.Do()
+ p.s.h.init.translations.Do(context.Background())
return len(p.translations) > 0
}
@@ -375,13 +415,13 @@ func (p *pageState) TranslationKey() string {
// AllTranslations returns all translations, including the current Page.
func (p *pageState) AllTranslations() page.Pages {
- p.s.h.init.translations.Do()
+ p.s.h.init.translations.Do(context.Background())
return p.allTranslations
}
// Translations returns the translations excluding the current Page.
func (p *pageState) Translations() page.Pages {
- p.s.h.init.translations.Do()
+ p.s.h.init.translations.Do(context.Background())
return p.translations
}
@@ -461,7 +501,7 @@ func (p *pageState) initOutputFormat(isRenderingSite bool, idx int) error {
// Must be run after the site section tree etc. is built and ready.
func (p *pageState) initPage() error {
- if _, err := p.init.Do(); err != nil {
+ if _, err := p.init.Do(context.Background()); err != nil {
return err
}
return nil
diff --git a/hugolib/page__content.go b/hugolib/page__content.go
index a721d1fce..89c38bd84 100644
--- a/hugolib/page__content.go
+++ b/hugolib/page__content.go
@@ -14,6 +14,7 @@
package hugolib
import (
+ "context"
"fmt"
"github.com/gohugoio/hugo/output"
@@ -37,9 +38,9 @@ type pageContent struct {
}
// returns the content to be processed by Goldmark or similar.
-func (p pageContent) contentToRender(parsed pageparser.Result, pm *pageContentMap, renderedShortcodes map[string]string) []byte {
+func (p pageContent) contentToRender(ctx context.Context, parsed pageparser.Result, pm *pageContentMap, renderedShortcodes map[string]shortcodeRenderer) ([]byte, bool, error) {
source := parsed.Input()
-
+ var hasVariants bool
c := make([]byte, 0, len(source)+(len(source)/10))
for _, it := range pm.items {
@@ -57,7 +58,12 @@ func (p pageContent) contentToRender(parsed pageparser.Result, pm *pageContentMa
panic(fmt.Sprintf("rendered shortcode %q not found", v.placeholder))
}
- c = append(c, []byte(renderedShortcode)...)
+ b, more, err := renderedShortcode.renderShortcode(ctx)
+ if err != nil {
+ return nil, false, fmt.Errorf("failed to render shortcode: %w", err)
+ }
+ hasVariants = hasVariants || more
+ c = append(c, []byte(b)...)
} else {
// Insert the placeholder so we can insert the content after
@@ -69,7 +75,7 @@ func (p pageContent) contentToRender(parsed pageparser.Result, pm *pageContentMa
}
}
- return c
+ return c, hasVariants, nil
}
func (p pageContent) selfLayoutForOutput(f output.Format) string {
diff --git a/hugolib/page__menus.go b/hugolib/page__menus.go
index 49d392c2f..5bed2bc03 100644
--- a/hugolib/page__menus.go
+++ b/hugolib/page__menus.go
@@ -14,6 +14,7 @@
package hugolib
import (
+ "context"
"sync"
"github.com/gohugoio/hugo/navigation"
@@ -29,13 +30,13 @@ type pageMenus struct {
}
func (p *pageMenus) HasMenuCurrent(menuID string, me *navigation.MenuEntry) bool {
- p.p.s.init.menus.Do()
+ p.p.s.init.menus.Do(context.Background())
p.init()
return p.q.HasMenuCurrent(menuID, me)
}
func (p *pageMenus) IsMenuCurrent(menuID string, inme *navigation.MenuEntry) bool {
- p.p.s.init.menus.Do()
+ p.p.s.init.menus.Do(context.Background())
p.init()
return p.q.IsMenuCurrent(menuID, inme)
}
@@ -43,7 +44,7 @@ func (p *pageMenus) IsMenuCurrent(menuID string, inme *navigation.MenuEntry) boo
func (p *pageMenus) Menus() navigation.PageMenus {
// There is a reverse dependency here. initMenus will, once, build the
// site menus and update any relevant page.
- p.p.s.init.menus.Do()
+ p.p.s.init.menus.Do(context.Background())
return p.menus()
}
diff --git a/hugolib/page__new.go b/hugolib/page__new.go
index e52b9476b..3787cd2bd 100644
--- a/hugolib/page__new.go
+++ b/hugolib/page__new.go
@@ -14,6 +14,7 @@
package hugolib
import (
+ "context"
"html/template"
"strings"
@@ -121,7 +122,7 @@ func newPageFromMeta(
return nil, err
}
- ps.init.Add(func() (any, error) {
+ ps.init.Add(func(context.Context) (any, error) {
pp, err := newPagePaths(metaProvider.s, ps, metaProvider)
if err != nil {
return nil, err
diff --git a/hugolib/page__per_output.go b/hugolib/page__per_output.go
index 97e9cc465..827a6b792 100644
--- a/hugolib/page__per_output.go
+++ b/hugolib/page__per_output.go
@@ -18,7 +18,6 @@ import (
"context"
"fmt"
"html/template"
- "runtime/debug"
"strings"
"sync"
"unicode/utf8"
@@ -34,6 +33,7 @@ import (
"github.com/gohugoio/hugo/markup/converter/hooks"
"github.com/gohugoio/hugo/markup/highlight/chromalexers"
+ "github.com/gohugoio/hugo/markup/tableofcontents"
"github.com/gohugoio/hugo/markup/converter"
@@ -87,43 +87,35 @@ func newPageContentOutput(p *pageState, po *pageOutput) (*pageContentOutput, err
renderHooks: &renderHooks{},
}
- initContent := func() (err error) {
- p.s.h.IncrContentRender()
-
+ initToC := func(ctx context.Context) (err error) {
if p.cmap == nil {
// Nothing to do.
return nil
}
- defer func() {
- // See https://github.com/gohugoio/hugo/issues/6210
- if r := recover(); r != nil {
- err = fmt.Errorf("%s", r)
- p.s.Log.Errorf("[BUG] Got panic:\n%s\n%s", r, string(debug.Stack()))
- }
- }()
if err := po.cp.initRenderHooks(); err != nil {
return err
}
- var hasShortcodeVariants bool
-
f := po.f
- cp.contentPlaceholders, hasShortcodeVariants, err = p.shortcodeState.renderShortcodesForPage(p, f)
+ cp.contentPlaceholders, err = p.shortcodeState.prepareShortcodesForPage(ctx, p, f)
if err != nil {
return err
}
- if hasShortcodeVariants {
+ var hasVariants bool
+ cp.workContent, hasVariants, err = p.contentToRender(ctx, p.source.parsed, p.cmap, cp.contentPlaceholders)
+ if err != nil {
+ return err
+ }
+ if hasVariants {
p.pageOutputTemplateVariationsState.Store(2)
}
- cp.workContent = p.contentToRender(p.source.parsed, p.cmap, cp.contentPlaceholders)
-
isHTML := cp.p.m.markup == "html"
if !isHTML {
- r, err := po.contentRenderer.RenderContent(cp.workContent, true)
+ r, err := po.contentRenderer.RenderContent(ctx, cp.workContent, true)
if err != nil {
return err
}
@@ -132,8 +124,9 @@ func newPageContentOutput(p *pageState, po *pageOutput) (*pageContentOutput, err
if tocProvider, ok := r.(converter.TableOfContentsProvider); ok {
cfg := p.s.ContentSpec.Converters.GetMarkupConfig()
- cp.tableOfContents = template.HTML(
- tocProvider.TableOfContents().ToHTML(
+ cp.tableOfContents = tocProvider.TableOfContents()
+ cp.tableOfContentsHTML = template.HTML(
+ cp.tableOfContents.ToHTML(
cfg.TableOfContents.StartLevel,
cfg.TableOfContents.EndLevel,
cfg.TableOfContents.Ordered,
@@ -141,26 +134,60 @@ func newPageContentOutput(p *pageState, po *pageOutput) (*pageContentOutput, err
)
} else {
tmpContent, tmpTableOfContents := helpers.ExtractTOC(cp.workContent)
- cp.tableOfContents = helpers.BytesToHTML(tmpTableOfContents)
+ cp.tableOfContentsHTML = helpers.BytesToHTML(tmpTableOfContents)
+ cp.tableOfContents = tableofcontents.Empty
cp.workContent = tmpContent
}
}
- if cp.placeholdersEnabled {
- // ToC was accessed via .Page.TableOfContents in the shortcode,
- // at a time when the ToC wasn't ready.
- cp.contentPlaceholders[tocShortcodePlaceholder] = string(cp.tableOfContents)
+ return nil
+
+ }
+
+ initContent := func(ctx context.Context) (err error) {
+
+ p.s.h.IncrContentRender()
+
+ if p.cmap == nil {
+ // Nothing to do.
+ return nil
}
if p.cmap.hasNonMarkdownShortcode || cp.placeholdersEnabled {
// There are one or more replacement tokens to be replaced.
- cp.workContent, err = replaceShortcodeTokens(cp.workContent, cp.contentPlaceholders)
+ var hasShortcodeVariants bool
+ tokenHandler := func(ctx context.Context, token string) ([]byte, error) {
+ if token == tocShortcodePlaceholder {
+ // The Page's TableOfContents was accessed in a shortcode.
+ if cp.tableOfContentsHTML == "" {
+ cp.p.s.initInit(ctx, cp.initToC, cp.p)
+ }
+ return []byte(cp.tableOfContentsHTML), nil
+ }
+ renderer, found := cp.contentPlaceholders[token]
+ if found {
+ repl, more, err := renderer.renderShortcode(ctx)
+ if err != nil {
+ return nil, err
+ }
+ hasShortcodeVariants = hasShortcodeVariants || more
+ return repl, nil
+ }
+ // This should never happen.
+ return nil, fmt.Errorf("unknown shortcode token %q", token)
+ }
+
+ cp.workContent, err = expandShortcodeTokens(ctx, cp.workContent, tokenHandler)
if err != nil {
return err
}
+ if hasShortcodeVariants {
+ p.pageOutputTemplateVariationsState.Store(2)
+ }
}
if cp.p.source.hasSummaryDivider {
+ isHTML := cp.p.m.markup == "html"
if isHTML {
src := p.source.parsed.Input()
@@ -183,7 +210,7 @@ func newPageContentOutput(p *pageState, po *pageOutput) (*pageContentOutput, err
}
}
} else if cp.p.m.summary != "" {
- b, err := po.contentRenderer.RenderContent([]byte(cp.p.m.summary), false)
+ b, err := po.contentRenderer.RenderContent(ctx, []byte(cp.p.m.summary), false)
if err != nil {
return err
}
@@ -196,12 +223,16 @@ func newPageContentOutput(p *pageState, po *pageOutput) (*pageContentOutput, err
return nil
}
+ cp.initToC = parent.Branch(func(ctx context.Context) (any, error) {
+ return nil, initToC(ctx)
+ })
+
// There may be recursive loops in shortcodes and render hooks.
- cp.initMain = parent.BranchWithTimeout(p.s.siteCfg.timeout, func(ctx context.Context) (any, error) {
- return nil, initContent()
+ cp.initMain = cp.initToC.BranchWithTimeout(p.s.siteCfg.timeout, func(ctx context.Context) (any, error) {
+ return nil, initContent(ctx)
})
- cp.initPlain = cp.initMain.Branch(func() (any, error) {
+ cp.initPlain = cp.initMain.Branch(func(context.Context) (any, error) {
c