mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-29 22:29:56 +02:00
Reimplement and simplify Hugo's template system
See #13541 for details. Fixes #13545 Fixes #13515 Closes #7964 Closes #13365 Closes #12988 Closes #4891
This commit is contained in:
134
tpl/template.go
134
tpl/template.go
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2025 The Hugo Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -16,9 +16,6 @@ package tpl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"unicode"
|
||||
@@ -27,140 +24,18 @@ import (
|
||||
"github.com/gohugoio/hugo/common/hcontext"
|
||||
"github.com/gohugoio/hugo/identity"
|
||||
"github.com/gohugoio/hugo/langs"
|
||||
"github.com/gohugoio/hugo/output/layouts"
|
||||
|
||||
"github.com/gohugoio/hugo/output"
|
||||
|
||||
htmltemplate "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate"
|
||||
texttemplate "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate"
|
||||
)
|
||||
|
||||
// TemplateManager manages the collection of templates.
|
||||
type TemplateManager interface {
|
||||
TemplateHandler
|
||||
TemplateFuncGetter
|
||||
AddTemplate(name, tpl string) error
|
||||
}
|
||||
|
||||
// TemplateVariants describes the possible variants of a template.
|
||||
// All of these may be empty.
|
||||
type TemplateVariants struct {
|
||||
Language string
|
||||
OutputFormat output.Format
|
||||
}
|
||||
|
||||
// TemplateFinder finds templates.
|
||||
type TemplateFinder interface {
|
||||
TemplateLookup
|
||||
TemplateLookupVariant
|
||||
}
|
||||
|
||||
// UnusedTemplatesProvider lists unused templates if the build is configured to track those.
|
||||
type UnusedTemplatesProvider interface {
|
||||
UnusedTemplates() []FileInfo
|
||||
}
|
||||
|
||||
// TemplateHandlers holds the templates needed by Hugo.
|
||||
type TemplateHandlers struct {
|
||||
Tmpl TemplateHandler
|
||||
TxtTmpl TemplateParseFinder
|
||||
}
|
||||
|
||||
type TemplateExecutor interface {
|
||||
ExecuteWithContext(ctx context.Context, t Template, wr io.Writer, data any) error
|
||||
}
|
||||
|
||||
// TemplateHandler finds and executes templates.
|
||||
type TemplateHandler interface {
|
||||
TemplateFinder
|
||||
TemplateExecutor
|
||||
LookupLayout(d layouts.LayoutDescriptor, f output.Format) (Template, bool, error)
|
||||
HasTemplate(name string) bool
|
||||
GetIdentity(name string) (identity.Identity, bool)
|
||||
}
|
||||
|
||||
type TemplateLookup interface {
|
||||
Lookup(name string) (Template, bool)
|
||||
}
|
||||
|
||||
type TemplateLookupVariant interface {
|
||||
// TODO(bep) this currently only works for shortcodes.
|
||||
// We may unify and expand this variant pattern to the
|
||||
// other templates, but we need this now for the shortcodes to
|
||||
// quickly determine if a shortcode has a template for a given
|
||||
// output format.
|
||||
// It returns the template, if it was found or not and if there are
|
||||
// alternative representations (output format, language).
|
||||
// We are currently only interested in output formats, so we should improve
|
||||
// this for speed.
|
||||
LookupVariant(name string, variants TemplateVariants) (Template, bool, bool)
|
||||
LookupVariants(name string) []Template
|
||||
}
|
||||
|
||||
// Template is the common interface between text/template and html/template.
|
||||
type Template interface {
|
||||
Name() string
|
||||
Prepare() (*texttemplate.Template, error)
|
||||
}
|
||||
|
||||
// AddIdentity checks if t is an identity.Identity and returns it if so.
|
||||
// Else it wraps it in a templateIdentity using its name as the base.
|
||||
func AddIdentity(t Template) Template {
|
||||
if _, ok := t.(identity.IdentityProvider); ok {
|
||||
return t
|
||||
}
|
||||
return templateIdentityProvider{
|
||||
Template: t,
|
||||
id: identity.StringIdentity(t.Name()),
|
||||
}
|
||||
}
|
||||
|
||||
type templateIdentityProvider struct {
|
||||
Template
|
||||
id identity.Identity
|
||||
}
|
||||
|
||||
func (t templateIdentityProvider) GetIdentity() identity.Identity {
|
||||
return t.id
|
||||
}
|
||||
|
||||
// TemplateParser is used to parse ad-hoc templates, e.g. in the Resource chain.
|
||||
type TemplateParser interface {
|
||||
Parse(name, tpl string) (Template, error)
|
||||
}
|
||||
|
||||
// TemplateParseFinder provides both parsing and finding.
|
||||
type TemplateParseFinder interface {
|
||||
TemplateParser
|
||||
TemplateFinder
|
||||
}
|
||||
|
||||
// TemplateDebugger prints some debug info to stdout.
|
||||
type TemplateDebugger interface {
|
||||
Debug()
|
||||
}
|
||||
|
||||
// TemplatesProvider as implemented by deps.Deps.
|
||||
type TemplatesProvider interface {
|
||||
Tmpl() TemplateHandler
|
||||
TextTmpl() TemplateParseFinder
|
||||
}
|
||||
|
||||
var baseOfRe = regexp.MustCompile("template: (.*?):")
|
||||
|
||||
func extractBaseOf(err string) string {
|
||||
m := baseOfRe.FindStringSubmatch(err)
|
||||
if len(m) == 2 {
|
||||
return m[1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// TemplateFuncGetter allows to find a template func by name.
|
||||
type TemplateFuncGetter interface {
|
||||
GetFunc(name string) (reflect.Value, bool)
|
||||
}
|
||||
|
||||
// RenderingContext represents the currently rendered site/language.
|
||||
type RenderingContext struct {
|
||||
Site site
|
||||
SiteOutIdx int
|
||||
@@ -201,7 +76,9 @@ type site interface {
|
||||
}
|
||||
|
||||
const (
|
||||
// HugoDeferredTemplatePrefix is the prefix for placeholders for deferred templates.
|
||||
HugoDeferredTemplatePrefix = "__hdeferred/"
|
||||
// HugoDeferredTemplateSuffix is the suffix for placeholders for deferred templates.
|
||||
HugoDeferredTemplateSuffix = "__d="
|
||||
)
|
||||
|
||||
@@ -243,10 +120,11 @@ func StripHTML(s string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
// DeferredExecution holds the template and data for a deferred execution.
|
||||
type DeferredExecution struct {
|
||||
Mu sync.Mutex
|
||||
Ctx context.Context
|
||||
TemplateName string
|
||||
TemplatePath string
|
||||
Data any
|
||||
|
||||
Executed bool
|
||||
|
Reference in New Issue
Block a user