Make macros per-template-execution

This commit is contained in:
Elara 2023-10-30 21:06:17 -07:00
parent 17906cf329
commit 69e515326f
3 changed files with 32 additions and 18 deletions

View File

@ -30,17 +30,17 @@ func (mt macroTag) Run(tc *TagContext, block, args []ast.Node) error {
} }
if len(block) == 0 { if len(block) == 0 {
tc.t.ns.mu.Lock() tc.t.macroMtx.Lock()
macro, ok := tc.t.ns.macros[name] macro, ok := tc.t.macros[name]
if !ok { if !ok {
return ErrNoSuchMacro return ErrNoSuchMacro
} }
tc.t.ns.mu.Unlock() tc.t.macroMtx.Unlock()
return tc.Execute(macro, nil) return tc.Execute(macro, nil)
} else { } else {
tc.t.ns.mu.Lock() tc.t.macroMtx.Lock()
tc.t.ns.macros[name] = block tc.t.macros[name] = block
tc.t.ns.mu.Unlock() tc.t.macroMtx.Unlock()
} }
return nil return nil

View File

@ -21,26 +21,22 @@ package salix
import ( import (
"reflect" "reflect"
"sync" "sync"
"go.elara.ws/salix/ast"
) )
// Namespace represents a collection of templates that can include each other // Namespace represents a collection of templates that can include each other
type Namespace struct { type Namespace struct {
mu sync.Mutex mu sync.Mutex
tmpls map[string]*Template tmpls map[string]*Template
vars map[string]reflect.Value vars map[string]reflect.Value
tags map[string]Tag tags map[string]Tag
macros map[string][]ast.Node
} }
// New returns a new template namespace // New returns a new template namespace
func New() *Namespace { func New() *Namespace {
return &Namespace{ return &Namespace{
tmpls: map[string]*Template{}, tmpls: map[string]*Template{},
vars: map[string]reflect.Value{}, vars: map[string]reflect.Value{},
tags: map[string]Tag{}, tags: map[string]Tag{},
macros: map[string][]ast.Node{},
} }
} }

View File

@ -24,6 +24,7 @@ import (
"html" "html"
"io" "io"
"reflect" "reflect"
"sync"
"go.elara.ws/salix/ast" "go.elara.ws/salix/ast"
) )
@ -61,6 +62,9 @@ type Template struct {
tags map[string]Tag tags map[string]Tag
vars map[string]reflect.Value vars map[string]reflect.Value
macroMtx sync.Mutex
macros map[string][]ast.Node
} }
// WithVarMap returns a copy of the template with its variable map set to m. // WithVarMap returns a copy of the template with its variable map set to m.
@ -124,7 +128,21 @@ func (t *Template) WithEscapeHTML(b bool) *Template {
// Execute executes a parsed template and writes // Execute executes a parsed template and writes
// the result to w. // the result to w.
func (t *Template) Execute(w io.Writer) error { func (t *Template) Execute(w io.Writer) error {
return t.execute(w, t.ast, nil) // Create a new template to give each execution
// its own macros
tmpl := &Template{
ns: t.ns,
name: t.name,
ast: t.ast,
escapeHTML: t.escapeHTML,
tags: t.tags,
vars: t.vars,
macros: map[string][]ast.Node{},
}
return tmpl.execute(w, t.ast, nil)
} }
func (t *Template) execute(w io.Writer, nodes []ast.Node, local map[string]any) error { func (t *Template) execute(w io.Writer, nodes []ast.Node, local map[string]any) error {