aboutsummaryrefslogtreecommitdiffhomepage
path: root/tpl/templates/templates.go
diff options
context:
space:
mode:
Diffstat (limited to 'tpl/templates/templates.go')
-rw-r--r--tpl/templates/templates.go68
1 files changed, 67 insertions, 1 deletions
diff --git a/tpl/templates/templates.go b/tpl/templates/templates.go
index 8e40f3443..91e96ed8e 100644
--- a/tpl/templates/templates.go
+++ b/tpl/templates/templates.go
@@ -15,14 +15,24 @@
package templates
import (
+ "context"
+ "fmt"
+ "strconv"
+ "sync/atomic"
+
"github.com/gohugoio/hugo/deps"
+ "github.com/gohugoio/hugo/helpers"
+ "github.com/gohugoio/hugo/tpl"
+ "github.com/mitchellh/mapstructure"
)
// New returns a new instance of the templates-namespaced template functions.
func New(deps *deps.Deps) *Namespace {
- return &Namespace{
+ ns := &Namespace{
deps: deps,
}
+
+ return ns
}
// Namespace provides template functions for the "templates" namespace.
@@ -36,3 +46,59 @@ type Namespace struct {
func (ns *Namespace) Exists(name string) bool {
return ns.deps.Tmpl().HasTemplate(name)
}
+
+// Defer defers the execution of a template block.
+func (ns *Namespace) Defer(args ...any) (bool, error) {
+ // Prevent defer from being used in content adapters,
+ // that just doesn't work.
+ ns.deps.Site.CheckReady()
+
+ if len(args) != 0 {
+ return false, fmt.Errorf("Defer does not take any arguments")
+ }
+ return true, nil
+}
+
+var defferedIDCounter atomic.Uint64
+
+type DeferOpts struct {
+ // Optional cache key. If set, the deferred block will be executed
+ // once per unique key.
+ Key string
+
+ // Optional data context to use when executing the deferred block.
+ Data any
+}
+
+// DoDefer defers the execution of a template block.
+// For internal use only.
+func (ns *Namespace) DoDefer(ctx context.Context, id string, optsv any) string {
+ var opts DeferOpts
+ if optsv != nil {
+ if err := mapstructure.WeakDecode(optsv, &opts); err != nil {
+ panic(err)
+ }
+ }
+
+ templateName := id
+ var key string
+ if opts.Key != "" {
+ key = helpers.MD5String(opts.Key)
+ } else {
+ key = strconv.FormatUint(defferedIDCounter.Add(1), 10)
+ }
+
+ id = fmt.Sprintf("%s_%s%s", id, key, tpl.HugoDeferredTemplateSuffix)
+
+ _ = ns.deps.BuildState.DeferredExecutions.Executions.GetOrCreate(id,
+ func() *tpl.DeferredExecution {
+ return &tpl.DeferredExecution{
+ TemplateName: templateName,
+ Ctx: ctx,
+ Data: opts.Data,
+ Executed: false,
+ }
+ })
+
+ return id
+}