// Copyright 2023 wanderer // 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 }