diff --git a/hugolib/page__common.go b/hugolib/page__common.go index bf11ae7d6..0294393e4 100644 --- a/hugolib/page__common.go +++ b/hugolib/page__common.go @@ -60,6 +60,9 @@ type pageCommon struct { // Lazily initialized dependencies. init *lazy.Init + // Store holds state that survives server rebuilds. + store *maps.Scratch + // All of these represents the common parts of a page.Page maps.Scratcher navigation.PageMenusProvider @@ -134,6 +137,10 @@ type pageCommon struct { forceRender bool } +func (p *pageCommon) Store() *maps.Scratch { + return p.store +} + type pagePages struct { pagesInit sync.Once pages page.Pages diff --git a/hugolib/page__new.go b/hugolib/page__new.go index 5efebe4f5..918477843 100644 --- a/hugolib/page__new.go +++ b/hugolib/page__new.go @@ -41,6 +41,7 @@ func newPageBase(metaProvider *pageMeta) (*pageState, error) { FileProvider: metaProvider, AuthorProvider: metaProvider, Scratcher: maps.NewScratcher(), + store: maps.NewScratch(), Positioner: page.NopPage, InSectionPositioner: page.NopPage, ResourceMetaProvider: metaProvider, diff --git a/hugolib/page_test.go b/hugolib/page_test.go index 6b35e4814..1edef622b 100644 --- a/hugolib/page_test.go +++ b/hugolib/page_test.go @@ -1769,7 +1769,7 @@ Summary: In Chinese, 好 means good. b.AssertFileContent("public/p6/index.html", "WordCount: 7\nFuzzyWordCount: 100\nReadingTime: 1\nLen Plain: 638\nLen PlainWords: 7\nTruncated: false\nLen Summary: 637\nLen Content: 652") } -func TestScratchSite(t *testing.T) { +func TestScratch(t *testing.T) { t.Parallel() b := newTestSitesBuilder(t) @@ -1796,6 +1796,50 @@ title: Scratch Me! b.AssertFileContent("public/scratchme/index.html", "C: cv") } +func TestScratchRebuild(t *testing.T) { + t.Parallel() + + files := ` +-- config.toml -- +-- content/p1.md -- +--- +title: "p1" +--- +{{< scratchme >}} +-- layouts/shortcodes/foo.html -- +notused +-- layouts/shortcodes/scratchme.html -- +{{ .Page.Scratch.Set "scratch" "foo" }} +{{ .Page.Store.Set "scratch" "bar" }} +-- layouts/_default/single.html -- +{{ .Content }} +Scratch: {{ .Scratch.Get "scratch" }}| +Store: {{ .Store.Get "scratch" }}| +` + + b := NewIntegrationTestBuilder( + IntegrationTestConfig{ + T: t, + TxtarString: files, + Running: true, + }, + ).Build() + + b.AssertFileContent("public/p1/index.html", ` +Scratch: foo| +Store: bar| + `) + + b.EditFiles("layouts/shortcodes/foo.html", "edit") + + b.Build() + + b.AssertFileContent("public/p1/index.html", ` +Scratch: | +Store: bar| + `) +} + func TestPageParam(t *testing.T) { t.Parallel() diff --git a/resources/page/page.go b/resources/page/page.go index d1790806e..1ad536e94 100644 --- a/resources/page/page.go +++ b/resources/page/page.go @@ -261,7 +261,15 @@ type PageWithoutContent interface { // Helper methods ShortcodeInfoProvider compare.Eqer + + // Scratch returns a Scratch that can be used to store temporary state. + // Note that this Scratch gets reset on server rebuilds. See Store() for a variant that survives. maps.Scratcher + + // Store returns a Scratch that can be used to store temporary state. + // In contrast to Scratch(), this Scratch is not reset on server rebuilds. + Store() *maps.Scratch + RelatedKeywordsProvider // GetTerms gets the terms of a given taxonomy, diff --git a/resources/page/page_nop.go b/resources/page/page_nop.go index 011fabfc0..fd706f994 100644 --- a/resources/page/page_nop.go +++ b/resources/page/page_nop.go @@ -418,6 +418,10 @@ func (p *nopPage) Scratch() *maps.Scratch { return nil } +func (p *nopPage) Store() *maps.Scratch { + return nil +} + func (p *nopPage) RelatedKeywords(cfg related.IndexConfig) ([]related.Keyword, error) { return nil, nil } diff --git a/resources/page/testhelpers_test.go b/resources/page/testhelpers_test.go index 57077ecf8..df4e79db4 100644 --- a/resources/page/testhelpers_test.go +++ b/resources/page/testhelpers_test.go @@ -498,6 +498,10 @@ func (p *testPage) Scratch() *maps.Scratch { panic("not implemented") } +func (p *testPage) Store() *maps.Scratch { + panic("not implemented") +} + func (p *testPage) RelatedKeywords(cfg related.IndexConfig) ([]related.Keyword, error) { v, err := p.Param(cfg.Name) if err != nil {