diff options
Diffstat (limited to 'tpl/templates/templates.go')
-rw-r--r-- | tpl/templates/templates.go | 68 |
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 +} |