pcmt/modules/template/template.go

145 lines
2.9 KiB
Go

// Copyright 2023 wanderer <a_mirre at utb dot cz>
// SPDX-License-Identifier: AGPL-3.0-only
package template
import (
"html/template"
"io/fs"
"os"
"strings"
"git.dotya.ml/mirre-mt/pcmt/app/settings"
"git.dotya.ml/mirre-mt/pcmt/modules/funcmap"
"git.dotya.ml/mirre-mt/pcmt/slogging"
"golang.org/x/exp/slog"
)
type tplMap map[string]*template.Template
var (
templateMap tplMap
// embedded templates.
tmplFS fs.FS
setting *settings.Settings
// global logger.
slogger *slogging.Slogger
// local logger copy.
log slogging.Slogger
// path to "templates" folder (empty if LiveMode).
tmplPath string
tmplSuffix = ".tmpl"
)
// Init saves settings and embedded templates to package-level state and also
// "initialises" template rendering.
func Init(s *settings.Settings, tmpls fs.FS) {
slogger = slogging.Logger()
log = *slogger // have a local copy.
log.Logger = log.Logger.With(
slog.Group("pcmt extra", slog.String("module", "modules/template")),
)
setting = s
tmplPath = setting.TemplatesPath() // will be empty if LiveMode.
initTemplates(tmpls)
log.Debug(Renderer.tmpls.DefinedTemplates())
}
// Get returns a template requested either from the tmplPath (in LiveMode) or
// from the pre-compiled tmpl list set directly to Renderer.
func Get(name string) *template.Template {
liveMode := setting.IsLive()
if liveMode {
log.Debug("re-reading tmpls") // TODO: only re-read the tmpl in question.
allTmpls := listAll(tmplSuffix)
// create fresh tmpl root.
t := template.New("")
for i, v := range allTmpls {
rawfile, err := os.ReadFile(v)
if err != nil {
panic(err)
}
allTmpls[i] = strings.TrimPrefix(v, tmplPath+"/")
t = t.New(allTmpls[i]).Funcs(funcmap.FuncMap())
template.Must(t.Parse(string(rawfile)))
}
Renderer.tmpls = t
}
return Renderer.tmpls.Lookup(name)
}
func initTemplates(f fs.FS) {
if !setting.IsLive() {
if f != nil || f != tmplFS {
tmplFS = f
}
}
allTmpls := listAll(tmplSuffix)
t := Renderer.tmpls
// ensure this fails at compile time, if at all ("Must").
if !setting.IsLive() {
for i, v := range allTmpls {
rawfile, err := fs.ReadFile(tmplFS, v)
if err != nil {
panic(err)
}
allTmpls[i] = strings.TrimPrefix(v, "templates/")
t := Renderer.tmpls.New(allTmpls[i]).Funcs(funcmap.FuncMap())
template.Must(t.Parse(string(rawfile)))
}
Renderer.tmpls = t
} else {
for i, v := range allTmpls {
rawfile, err := os.ReadFile(v)
if err != nil {
panic(err)
}
allTmpls[i] = strings.TrimPrefix(v, tmplPath+"/")
t = Renderer.tmpls.New(allTmpls[i]).Funcs(funcmap.FuncMap())
template.Must(t.Parse(string(rawfile)))
}
Renderer.tmpls = t
}
makeTplMap(Renderer.tmpls, allTmpls)
}
func makeTplMap(tpl *template.Template, tplList []string) {
allTmpls := tplList
var tp tplMap
if templateMap == nil {
tp = make(tplMap, len(allTmpls))
} else {
tp = templateMap
}
for _, v := range allTmpls {
tp[v] = tpl.Lookup(v)
}
templateMap = tp
}