summaryrefslogtreecommitdiffstats
path: root/hugolib/shortcode.go
diff options
context:
space:
mode:
Diffstat (limited to 'hugolib/shortcode.go')
-rw-r--r--hugolib/shortcode.go101
1 files changed, 68 insertions, 33 deletions
diff --git a/hugolib/shortcode.go b/hugolib/shortcode.go
index 2951a1436..a82caff43 100644
--- a/hugolib/shortcode.go
+++ b/hugolib/shortcode.go
@@ -15,6 +15,7 @@ package hugolib
import (
"bytes"
+ "context"
"fmt"
"html/template"
"path"
@@ -302,13 +303,44 @@ const (
innerCleanupExpand = "$1"
)
-func renderShortcode(
+func prepareShortcode(
+ ctx context.Context,
level int,
s *Site,
tplVariants tpl.TemplateVariants,
sc *shortcode,
parent *ShortcodeWithPage,
- p *pageState) (string, bool, error) {
+ p *pageState) (shortcodeRenderer, error) {
+
+ toParseErr := func(err error) error {
+ return p.parseError(fmt.Errorf("failed to render shortcode %q: %w", sc.name, err), p.source.parsed.Input(), sc.pos)
+ }
+
+ // Allow the caller to delay the rendering of the shortcode if needed.
+ var fn shortcodeRenderFunc = func(ctx context.Context) ([]byte, bool, error) {
+ r, err := doRenderShortcode(ctx, level, s, tplVariants, sc, parent, p)
+ if err != nil {
+ return nil, false, toParseErr(err)
+ }
+ b, hasVariants, err := r.renderShortcode(ctx)
+ if err != nil {
+ return nil, false, toParseErr(err)
+ }
+ return b, hasVariants, nil
+ }
+
+ return fn, nil
+
+}
+
+func doRenderShortcode(
+ ctx context.Context,
+ level int,
+ s *Site,
+ tplVariants tpl.TemplateVariants,
+ sc *shortcode,
+ parent *ShortcodeWithPage,
+ p *pageState) (shortcodeRenderer, error) {
var tmpl tpl.Template
// Tracks whether this shortcode or any of its children has template variations
@@ -319,7 +351,7 @@ func renderShortcode(
if sc.isInline {
if !p.s.ExecHelper.Sec().EnableInlineShortcodes {
- return "", false, nil
+ return zeroShortcode, nil
}
templName := path.Join("_inline_shortcode", p.File().Path(), sc.name)
if sc.isClosing {
@@ -332,7 +364,7 @@ func renderShortcode(
pos := fe.Position()
pos.LineNumber += p.posOffset(sc.pos).LineNumber
fe = fe.UpdatePosition(pos)
- return "", false, p.wrapError(fe)
+ return zeroShortcode, p.wrapError(fe)
}
} else {
@@ -340,7 +372,7 @@ func renderShortcode(
var found bool
tmpl, found = s.TextTmpl().Lookup(templName)
if !found {
- return "", false, fmt.Errorf("no earlier definition of shortcode %q found", sc.name)
+ return zeroShortcode, fmt.Errorf("no earlier definition of shortcode %q found", sc.name)
}
}
} else {
@@ -348,7 +380,7 @@ func renderShortcode(
tmpl, found, more = s.Tmpl().LookupVariant(sc.name, tplVariants)
if !found {
s.Log.Errorf("Unable to locate template for shortcode %q in page %q", sc.name, p.File().Path())
- return "", false, nil
+ return zeroShortcode, nil
}
hasVariants = hasVariants || more
}
@@ -365,16 +397,20 @@ func renderShortcode(
case string:
inner += innerData
case *shortcode:
- s, more, err := renderShortcode(level+1, s, tplVariants, innerData, data, p)
+ s, err := prepareShortcode(ctx, level+1, s, tplVariants, innerData, data, p)
if err != nil {
- return "", false, err
+ return zeroShortcode, err
}
+ ss, more, err := s.renderShortcodeString(ctx)
hasVariants = hasVariants || more
- inner += s
+ if err != nil {
+ return zeroShortcode, err
+ }
+ inner += ss
default:
s.Log.Errorf("Illegal state on shortcode rendering of %q in page %q. Illegal type in inner data: %s ",
sc.name, p.File().Path(), reflect.TypeOf(innerData))
- return "", false, nil
+ return zeroShortcode, nil
}
}
@@ -382,9 +418,9 @@ func renderShortcode(
// shortcode.
if sc.doMarkup && (level > 0 || sc.configVersion() == 1) {
var err error
- b, err := p.pageOutput.contentRenderer.RenderContent([]byte(inner), false)
+ b, err := p.pageOutput.contentRenderer.RenderContent(ctx, []byte(inner), false)
if err != nil {
- return "", false, err
+ return zeroShortcode, err
}
newInner := b.Bytes()
@@ -418,14 +454,14 @@ func renderShortcode(
}
- result, err := renderShortcodeWithPage(s.Tmpl(), tmpl, data)
+ result, err := renderShortcodeWithPage(ctx, s.Tmpl(), tmpl, data)
if err != nil && sc.isInline {
fe := herrors.NewFileErrorFromName(err, p.File().Filename())
pos := fe.Position()
pos.LineNumber += p.posOffset(sc.pos).LineNumber
fe = fe.UpdatePosition(pos)
- return "", false, fe
+ return zeroShortcode, fe
}
if len(sc.inner) == 0 && len(sc.indentation) > 0 {
@@ -444,7 +480,7 @@ func renderShortcode(
bp.PutBuffer(b)
}
- return result, hasVariants, err
+ return prerenderedShortcode{s: result, hasVariants: hasVariants}, err
}
func (s *shortcodeHandler) hasShortcodes() bool {
@@ -473,28 +509,24 @@ func (s *shortcodeHandler) hasName(name string) bool {
return ok
}
-func (s *shortcodeHandler) renderShortcodesForPage(p *pageState, f output.Format) (map[string]string, bool, error) {
- rendered := make(map[string]string)
+func (s *shortcodeHandler) prepareShortcodesForPage(ctx context.Context, p *pageState, f output.Format) (map[string]shortcodeRenderer, error) {
+ rendered := make(map[string]shortcodeRenderer)
tplVariants := tpl.TemplateVariants{
Language: p.Language().Lang,
OutputFormat: f,
}
- var hasVariants bool
-
for _, v := range s.shortcodes {
- s, more, err := renderShortcode(0, s.s, tplVariants, v, nil, p)
+ s, err := prepareShortcode(ctx, 0, s.s, tplVariants, v, nil, p)
if err != nil {
- err = p.parseError(fmt.Errorf("failed to render shortcode %q: %w", v.name, err), p.source.parsed.Input(), v.pos)
- return nil, false, err
+ return nil, err
}
- hasVariants = hasVariants || more
rendered[v.placeholder] = s
}
- return rendered, hasVariants, nil
+ return rendered, nil
}
func (s *shortcodeHandler) parseError(err error, input []byte, pos int) error {
@@ -668,11 +700,11 @@ Loop:
// Replace prefixed shortcode tokens with the real content.
// Note: This function will rewrite the input slice.
-func replaceShortcodeTokens(source []byte, replacements map[string]string) ([]byte, error) {
- if len(replacements) == 0 {
- return source, nil
- }
-
+func expandShortcodeTokens(
+ ctx context.Context,
+ source []byte,
+ tokenHandler func(ctx context.Context, token string) ([]byte, error),
+) ([]byte, error) {
start := 0
pre := []byte(shortcodePlaceholderPrefix)
@@ -691,8 +723,11 @@ func replaceShortcodeTokens(source []byte, replacements map[string]string) ([]by
}
end := j + postIdx + 4
-
- newVal := []byte(replacements[string(source[j:end])])
+ key := string(source[j:end])
+ newVal, err := tokenHandler(ctx, key)
+ if err != nil {
+ return nil, err
+ }
// Issue #1148: Check for wrapping p-tags <p>
if j >= 3 && bytes.Equal(source[j-3:j], pStart) {
@@ -712,11 +747,11 @@ func replaceShortcodeTokens(source []byte, replacements map[string]string) ([]by
return source, nil
}
-func renderShortcodeWithPage(h tpl.TemplateHandler, tmpl tpl.Template, data *ShortcodeWithPage) (string, error) {
+func renderShortcodeWithPage(ctx context.Context, h tpl.TemplateHandler, tmpl tpl.Template, data *ShortcodeWithPage) (string, error) {
buffer := bp.GetBuffer()
defer bp.PutBuffer(buffer)
- err := h.Execute(tmpl, buffer, data)
+ err := h.ExecuteWithContext(ctx, tmpl, buffer, data)
if err != nil {
return "", fmt.Errorf("failed to process shortcode: %w", err)
}