Skip to content

Commit

Permalink
Add Page.RenderShortcodes
Browse files Browse the repository at this point in the history
A layouts/shortcodes/include.html shortcode may look like this:

```html
{{ $p := site.GetPage (.Get 0) }}
{{ $p.RenderShortcodes }}
```

Fixes #7297
  • Loading branch information
bep committed Aug 3, 2023
1 parent 8fa8ce3 commit ade7ec8
Show file tree
Hide file tree
Showing 14 changed files with 434 additions and 89 deletions.
8 changes: 6 additions & 2 deletions hugolib/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ func (pa pageSiteAdapter) GetPage(ref string) (page.Page, error) {
}

type pageState struct {
// Incremented for each new page created.
// Note that this will change between builds for a given Page.
id int

// This slice will be of same length as the number of global slice of output
// formats (for all sites).
pageOutputs []*pageOutput
Expand Down Expand Up @@ -772,7 +776,7 @@ Loop:
currShortcode.pos = it.Pos()
currShortcode.length = iter.Current().Pos() - it.Pos()
if currShortcode.placeholder == "" {
currShortcode.placeholder = createShortcodePlaceholder("s", currShortcode.ordinal)
currShortcode.placeholder = createShortcodePlaceholder("s", p.id, currShortcode.ordinal)
}

if currShortcode.name != "" {
Expand All @@ -784,7 +788,7 @@ Loop:
currShortcode.params = s
}

currShortcode.placeholder = createShortcodePlaceholder("s", ordinal)
currShortcode.placeholder = createShortcodePlaceholder("s", p.id, ordinal)
ordinal++
s.shortcodes = append(s.shortcodes, currShortcode)

Expand Down
5 changes: 5 additions & 0 deletions hugolib/page__new.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,19 @@ import (
"github.com/gohugoio/hugo/resources/page"
)

var pageIdCounter atomic.Int64

func newPageBase(metaProvider *pageMeta) (*pageState, error) {
if metaProvider.s == nil {
panic("must provide a Site")
}

id := int(pageIdCounter.Add(1))

s := metaProvider.s

ps := &pageState{
id: id,
pageOutput: nopPageOutput,
pageOutputTemplateVariationsState: atomic.NewUint32(0),
pageCommon: &pageCommon{
Expand Down
2 changes: 2 additions & 0 deletions hugolib/page__output.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ type pageOutput struct {
page.ContentProvider
page.PageRenderProvider
page.TableOfContentsProvider
page.RenderShortcodesProvider

// May be nil.
cp *pageContentOutput
Expand All @@ -99,6 +100,7 @@ func (p *pageOutput) initContentProvider(cp *pageContentOutput) {
p.ContentProvider = cp
p.PageRenderProvider = cp
p.TableOfContentsProvider = cp
p.RenderShortcodesProvider = cp
p.cp = cp

}
Expand Down
81 changes: 81 additions & 0 deletions hugolib/page__per_output.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,30 @@ func newPageContentOutput(p *pageState, po *pageOutput) (*pageContentOutput, err
return err
}

ctxCallback := func(cp2 *pageContentOutput) {
cp.p.cmap.hasNonMarkdownShortcode = cp.p.cmap.hasNonMarkdownShortcode || cp2.p.cmap.hasNonMarkdownShortcode
// Merge content placeholders
for k, v := range cp2.contentPlaceholders {
cp.contentPlaceholders[k] = v
}

if p.s.watching() {
for _, s := range cp2.p.shortcodeState.shortcodes {
for _, templ := range s.templs {
dependencyTracker.Add(templ.(identity.Manager))
}
}
}

// Transfer shortcode names so HasShortcode works for shortcodes from included pages.
cp.p.shortcodeState.transferNames(cp2.p.shortcodeState)
if cp2.p.pageOutputTemplateVariationsState.Load() == 2 {
cp.p.pageOutputTemplateVariationsState.Store(2)
}
}

ctx = tpl.SetCallbackFunctionInContext(ctx, ctxCallback)

var hasVariants bool
cp.workContent, hasVariants, err = p.contentToRender(ctx, p.source.parsed, p.cmap, cp.contentPlaceholders)
if err != nil {
Expand Down Expand Up @@ -350,6 +374,63 @@ func (p *pageContentOutput) Fragments(ctx context.Context) *tableofcontents.Frag
return p.tableOfContents
}

func (p *pageContentOutput) RenderShortcodes(ctx context.Context) (template.HTML, error) {
p.p.s.initInit(ctx, p.initToC, p.p)
source := p.p.source.parsed.Input()
renderedShortcodes := p.contentPlaceholders
var insertPlaceholders bool
var hasVariants bool
var cb func(*pageContentOutput)
if v := tpl.GetCallbackFunctionFromContext(ctx); v != nil {
if fn, ok := v.(func(*pageContentOutput)); ok {
insertPlaceholders = true
cb = fn
}
}
c := make([]byte, 0, len(source)+(len(source)/10))
for _, it := range p.p.cmap.items {
switch v := it.(type) {
case pageparser.Item:
c = append(c, source[v.Pos():v.Pos()+len(v.Val(source))]...)
case pageContentReplacement:
// Ignore.
case *shortcode:
if !insertPlaceholders || !v.insertPlaceholder() {
// Insert the rendered shortcode.
renderedShortcode, found := renderedShortcodes[v.placeholder]
if !found {
// This should never happen.
panic(fmt.Sprintf("rendered shortcode %q not found", v.placeholder))
}

b, more, err := renderedShortcode.renderShortcode(ctx)
if err != nil {
return "", 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
// markdown processing.
c = append(c, []byte(v.placeholder)...)
}
default:
panic(fmt.Sprintf("unknown item type %T", it))
}
}

if hasVariants {
p.p.pageOutputTemplateVariationsState.Store(2)
}

if cb != nil {
cb(p)
}

return helpers.BytesToHTML(c), nil
}

func (p *pageContentOutput) TableOfContents(ctx context.Context) template.HTML {
p.p.s.initInit(ctx, p.initToC, p.p)
return p.tableOfContentsHTML
Expand Down
1 change: 0 additions & 1 deletion hugolib/page_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1998,7 +1998,6 @@ func TestRenderWithoutArgument(t *testing.T) {
IntegrationTestConfig{
T: t,
TxtarString: files,
Running: true,
},
).BuildE()

Expand Down
Loading

0 comments on commit ade7ec8

Please sign in to comment.