2023-05-20 20:15:57 +02:00
|
|
|
// Copyright 2023 wanderer <a_mirre at utb dot cz>
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
2023-05-11 04:32:39 +02:00
|
|
|
package template
|
|
|
|
|
|
|
|
import (
|
|
|
|
"html/template"
|
|
|
|
"io/fs"
|
|
|
|
"io/ioutil"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"git.dotya.ml/mirre-mt/pcmt/app/settings"
|
2023-05-11 18:16:15 +02:00
|
|
|
"git.dotya.ml/mirre-mt/pcmt/modules/funcmap"
|
2023-05-11 04:32:39 +02:00
|
|
|
"git.dotya.ml/mirre-mt/pcmt/slogging"
|
|
|
|
"golang.org/x/exp/slog"
|
|
|
|
)
|
|
|
|
|
|
|
|
type tplMap map[string]*template.Template
|
|
|
|
|
|
|
|
var (
|
|
|
|
templateMap tplMap
|
|
|
|
// embedded templates.
|
2023-05-11 18:16:15 +02:00
|
|
|
tmplFS fs.FS
|
|
|
|
setting *settings.Settings
|
2023-05-11 04:32:39 +02:00
|
|
|
// global logger.
|
2023-05-11 17:06:20 +02:00
|
|
|
slogger *slogging.Slogger
|
2023-05-11 04:32:39 +02:00
|
|
|
// local logger copy.
|
2023-05-11 17:06:20 +02:00
|
|
|
log slogging.Slogger
|
2023-05-11 04:32:39 +02:00
|
|
|
// 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) {
|
2023-05-11 17:06:20 +02:00
|
|
|
slogger = slogging.Logger()
|
2023-05-11 04:32:39 +02:00
|
|
|
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 := ioutil.ReadFile(v)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
allTmpls[i] = strings.TrimPrefix(v, tmplPath+"/")
|
|
|
|
|
2023-05-11 18:16:15 +02:00
|
|
|
t = t.New(allTmpls[i]).Funcs(funcmap.FuncMap())
|
2023-05-11 04:32:39 +02:00
|
|
|
|
|
|
|
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/")
|
|
|
|
|
2023-05-11 18:16:15 +02:00
|
|
|
t := Renderer.tmpls.New(allTmpls[i]).Funcs(funcmap.FuncMap())
|
2023-05-11 04:32:39 +02:00
|
|
|
template.Must(t.Parse(string(rawfile)))
|
|
|
|
}
|
|
|
|
|
|
|
|
Renderer.tmpls = t
|
|
|
|
} else {
|
|
|
|
for i, v := range allTmpls {
|
|
|
|
rawfile, err := ioutil.ReadFile(v)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
allTmpls[i] = strings.TrimPrefix(v, tmplPath+"/")
|
2023-05-11 18:16:15 +02:00
|
|
|
t = Renderer.tmpls.New(allTmpls[i]).Funcs(funcmap.FuncMap())
|
2023-05-11 04:32:39 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|