diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2017-03-27 20:43:49 +0200 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2017-04-02 23:13:10 +0200 |
commit | 8b5b558bb515e80da640f5e114169874771b61e4 (patch) | |
tree | 5755e77efe3120963d012dccbd91d916180485e0 /tpl/template.go | |
parent | 27610ddd011e8172d00e02275f948c3f1ed43e4f (diff) |
tpl: Rework to handle both text and HTML templates
Before this commit, Hugo used `html/template` for all Go templates.
While this is a fine choice for HTML and maybe also RSS feeds, it is painful for plain text formats such as CSV, JSON etc.
This commit fixes that by using the `IsPlainText` attribute on the output format to decide what to use.
A couple of notes:
* The above requires a nonambiguous template name to type mapping. I.e. `/layouts/_default/list.json` will only work if there is only one JSON output format, `/layouts/_default/list.mytype.json` will always work.
* Ambiguous types will fall back to HTML.
* Partials inherits the text vs HTML identificator of the container template. This also means that plain text templates can only include plain text partials.
* Shortcode templates are, by definition, currently HTML templates only.
Fixes #3221
Diffstat (limited to 'tpl/template.go')
-rw-r--r-- | tpl/template.go | 111 |
1 files changed, 93 insertions, 18 deletions
diff --git a/tpl/template.go b/tpl/template.go index b94fc3242..617aa84ec 100644 --- a/tpl/template.go +++ b/tpl/template.go @@ -1,28 +1,103 @@ +// Copyright 2017-present 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. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package tpl import ( - "html/template" "io" + + "text/template/parse" + + "html/template" + texttemplate "text/template" + + bp "github.com/spf13/hugo/bufferpool" ) -// TODO(bep) make smaller -type Template interface { - ExecuteTemplate(wr io.Writer, name string, data interface{}) error - ExecuteTemplateToHTML(context interface{}, layouts ...string) template.HTML - Lookup(name string) *template.Template - Templates() []*template.Template - New(name string) *template.Template - GetClone() *template.Template - RebuildClone() *template.Template - LoadTemplates(absPath string) - LoadTemplatesWithPrefix(absPath, prefix string) +var ( + _ TemplateExecutor = (*TemplateAdapter)(nil) +) + +// TemplateHandler manages the collection of templates. +type TemplateHandler interface { + TemplateFinder AddTemplate(name, tpl string) error - AddTemplateFileWithMaster(name, overlayFilename, masterFilename string) error - AddAceTemplate(name, basePath, innerPath string, baseContent, innerContent []byte) error - AddInternalTemplate(prefix, name, tpl string) error - AddInternalShortcode(name, tpl string) error - Partial(name string, contextList ...interface{}) template.HTML + AddLateTemplate(name, tpl string) error + LoadTemplates(absPath, prefix string) PrintErrors() - Funcs(funcMap template.FuncMap) + MarkReady() + RebuildClone() +} + +// TemplateFinder finds templates. +type TemplateFinder interface { + Lookup(name string) *TemplateAdapter +} + +// Template is the common interface between text/template and html/template. +type Template interface { + Execute(wr io.Writer, data interface{}) error + Name() string +} + +// TemplateExecutor adds some extras to Template. +type TemplateExecutor interface { + Template + ExecuteToString(data interface{}) (string, error) + Tree() string +} + +// TemplateAdapter implements the TemplateExecutor interface. +type TemplateAdapter struct { + Template +} + +// ExecuteToString executes the current template and returns the result as a +// string. +func (t *TemplateAdapter) ExecuteToString(data interface{}) (string, error) { + b := bp.GetBuffer() + defer bp.PutBuffer(b) + if err := t.Execute(b, data); err != nil { + return "", err + } + return b.String(), nil +} + +// Tree returns the template Parse tree as a string. +// Note: this isn't safe for parallel execution on the same template +// vs Lookup and Execute. +func (t *TemplateAdapter) Tree() string { + var tree *parse.Tree + switch tt := t.Template.(type) { + case *template.Template: + tree = tt.Tree + case *texttemplate.Template: + tree = tt.Tree + default: + panic("Unknown template") + } + + if tree.Root == nil { + return "" + } + s := tree.Root.String() + + return s +} + +// TemplateTestMocker adds a way to override some template funcs during tests. +// The interface is named so it's not used in regular application code. +type TemplateTestMocker interface { + SetFuncs(funcMap map[string]interface{}) } |