URI: 
        all: Refactor to nonglobal template handling - hugo - [fork] hugo port for 9front
  HTML git clone git@git.drkhsh.at/hugo.git
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
   DIR commit d6000a208c7687ca3a3efd6961ac941ce325e199
   DIR parent 4ea4359ac17a3b5304fb0d73773f99a07975ee1e
  HTML Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
       Date:   Tue, 10 Jan 2017 01:36:59 +0100
       
        all: Refactor to nonglobal template handling
       
       Updates #2701
       
       Diffstat:
         M hugolib/embedded_shortcodes_test.go |      43 ++++++++++++++-----------------
         M hugolib/handler_base.go             |       3 +--
         M hugolib/handler_file.go             |       3 +--
         M hugolib/handler_meta.go             |       2 +-
         M hugolib/handler_page.go             |      27 ++++++++++++++-------------
         M hugolib/hugo_sites.go               |      43 ++++++++++++++++++++++++-------
         M hugolib/page.go                     |       7 +++----
         M hugolib/shortcode.go                |      30 +++++++++++++++---------------
         M hugolib/shortcode_test.go           |      42 +++++++++++++++++--------------
         M hugolib/site.go                     |      40 +++++++++++++++++--------------
         M hugolib/site_test.go                |       9 +++++++--
         M tpl/template.go                     |      88 ++++++++++++++++---------------
         M tpl/template_ast_transformers_test… |       5 -----
         M tpl/template_funcs.go               |      57 ++++++++++++++++++-------------
         M tpl/template_funcs_test.go          |      27 +++++++++++++++------------
         M tpl/template_test.go                |      34 ++++++++++++++++---------------
         M vendor/vendor.json                  |       6 +++---
       
       17 files changed, 256 insertions(+), 210 deletions(-)
       ---
   DIR diff --git a/hugolib/embedded_shortcodes_test.go b/hugolib/embedded_shortcodes_test.go
       @@ -19,16 +19,17 @@ import (
                "html/template"
                "net/url"
                "os"
       -        "path/filepath"
                "regexp"
                "strings"
                "testing"
        
                "io/ioutil"
                "log"
       +        "path/filepath"
        
       -        "github.com/spf13/hugo/helpers"
                "github.com/spf13/hugo/tpl"
       +
       +        "github.com/spf13/hugo/helpers"
                jww "github.com/spf13/jwalterweatherman"
                "github.com/spf13/viper"
                "github.com/stretchr/testify/require"
       @@ -106,9 +107,8 @@ void do();
                                "(?s)^\n<div class=\"highlight\" style=\"background: #f0f0f0\"><pre style=\"line-height: 125%\">.*?void</span>.*?do</span>.*?().*?</pre></div>\n$",
                        },
                } {
       -                templ := tpl.New(logger)
                        p, _ := pageFromString(simplePage, "simple.md")
       -                output, err := HandleShortcodes(this.in, p, templ)
       +                output, err := HandleShortcodes(this.in, p)
        
                        if err != nil {
                                t.Fatalf("[%d] Handle shortcode error", i)
       @@ -150,9 +150,8 @@ func TestShortcodeFigure(t *testing.T) {
                                "(?s)^\n<figure >.*?<img src=\"/img/hugo-logo.png\" />.*?<figcaption>.*?<p>.*?<a href=\"/img/hugo-logo.png\">.*?Hugo logo.*?</a>.*?</p>.*?</figcaption>.*?</figure>\n$",
                        },
                } {
       -                templ := tpl.New(logger)
                        p, _ := pageFromString(simplePage, "simple.md")
       -                output, err := HandleShortcodes(this.in, p, templ)
       +                output, err := HandleShortcodes(this.in, p)
        
                        matched, err := regexp.MatchString(this.expected, output)
        
       @@ -175,9 +174,8 @@ func TestShortcodeSpeakerdeck(t *testing.T) {
                                "(?s)^<script async class='speakerdeck-embed' data-id='4e8126e72d853c0060001f97'.*?>.*?</script>$",
                        },
                } {
       -                templ := tpl.New(logger)
                        p, _ := pageFromString(simplePage, "simple.md")
       -                output, err := HandleShortcodes(this.in, p, templ)
       +                output, err := HandleShortcodes(this.in, p)
        
                        matched, err := regexp.MatchString(this.expected, output)
        
       @@ -210,9 +208,8 @@ func TestShortcodeYoutube(t *testing.T) {
                                "(?s)^\n<div class=\"video\">.*?<iframe src=\"//www.youtube.com/embed/w7Ft2ymGmfc\\?autoplay=1\".*?allowfullscreen frameborder=\"0\">.*?</iframe>.*?</div>$",
                        },
                } {
       -                templ := tpl.New(logger)
                        p, _ := pageFromString(simplePage, "simple.md")
       -                output, err := HandleShortcodes(this.in, p, templ)
       +                output, err := HandleShortcodes(this.in, p)
        
                        matched, err := regexp.MatchString(this.expected, output)
        
       @@ -245,9 +242,8 @@ func TestShortcodeVimeo(t *testing.T) {
                                "(?s)^<div class=\"video\">.*?<iframe src=\"//player.vimeo.com/video/146022717\" webkitallowfullscreen mozallowfullscreen allowfullscreen>.*?</iframe>.*?</div>$",
                        },
                } {
       -                templ := tpl.New(logger)
                        p, _ := pageFromString(simplePage, "simple.md")
       -                output, err := HandleShortcodes(this.in, p, templ)
       +                output, err := HandleShortcodes(this.in, p)
        
                        matched, err := regexp.MatchString(this.expected, output)
        
       @@ -274,9 +270,8 @@ func TestShortcodeGist(t *testing.T) {
                                "(?s)^<script src=\"//gist.github.com/spf13/7896402.js\\?file=img.html\"></script>$",
                        },
                } {
       -                templ := tpl.New(logger)
                        p, _ := pageFromString(simplePage, "simple.md")
       -                output, err := HandleShortcodes(this.in, p, templ)
       +                output, err := HandleShortcodes(this.in, p)
        
                        matched, err := regexp.MatchString(this.expected, output)
        
       @@ -313,13 +308,14 @@ func TestShortcodeTweet(t *testing.T) {
                                },
                        }
        
       -                templ := tpl.New(logger)
       -                templ.Lookup("").Funcs(tweetFuncMap)
       +                p, _ := pageFromString(simplePage, "simple.md", func(templ tpl.Template) error {
       +                        templ.Funcs(tweetFuncMap)
       +                        return nil
       +                })
        
       -                p, _ := pageFromString(simplePage, "simple.md")
                        cacheFileID := viper.GetString("cacheDir") + url.QueryEscape("https://api.twitter.com/1/statuses/oembed.json?id=666616452582129664")
                        defer os.Remove(cacheFileID)
       -                output, err := HandleShortcodes(this.in, p, templ)
       +                output, err := HandleShortcodes(this.in, p)
        
                        matched, err := regexp.MatchString(this.expected, output)
        
       @@ -353,7 +349,7 @@ func TestShortcodeInstagram(t *testing.T) {
                        },
                } {
                        // overload getJSON to return mock API response from Instagram
       -                tweetFuncMap := template.FuncMap{
       +                instagramFuncMap := template.FuncMap{
                                "getJSON": func(urlParts ...string) interface{} {
                                        var v interface{}
                                        err := json.Unmarshal([]byte(this.resp), &v)
       @@ -365,13 +361,14 @@ func TestShortcodeInstagram(t *testing.T) {
                                },
                        }
        
       -                templ := tpl.New(logger)
       -                templ.Lookup("").Funcs(tweetFuncMap)
       +                p, _ := pageFromString(simplePage, "simple.md", func(templ tpl.Template) error {
       +                        templ.Funcs(instagramFuncMap)
       +                        return nil
       +                })
        
       -                p, _ := pageFromString(simplePage, "simple.md")
                        cacheFileID := viper.GetString("cacheDir") + url.QueryEscape("https://api.instagram.com/oembed/?url=https://instagram.com/p/BMokmydjG-M/&hidecaption="+this.hidecaption)
                        defer os.Remove(cacheFileID)
       -                output, err := HandleShortcodes(this.in, p, templ)
       +                output, err := HandleShortcodes(this.in, p)
        
                        if err != nil {
                                t.Fatalf("[%d] Failed to render shortcodes", i)
   DIR diff --git a/hugolib/handler_base.go b/hugolib/handler_base.go
       @@ -15,12 +15,11 @@ package hugolib
        
        import (
                "github.com/spf13/hugo/source"
       -        "github.com/spf13/hugo/tpl"
        )
        
        type Handler interface {
                FileConvert(*source.File, *Site) HandledResult
       -        PageConvert(*Page, tpl.Template) HandledResult
       +        PageConvert(*Page) HandledResult
                Read(*source.File, *Site) HandledResult
                Extensions() []string
        }
   DIR diff --git a/hugolib/handler_file.go b/hugolib/handler_file.go
       @@ -18,7 +18,6 @@ import (
        
                "github.com/dchest/cssmin"
                "github.com/spf13/hugo/source"
       -        "github.com/spf13/hugo/tpl"
        )
        
        func init() {
       @@ -32,7 +31,7 @@ func (h basicFileHandler) Read(f *source.File, s *Site) HandledResult {
                return HandledResult{file: f}
        }
        
       -func (h basicFileHandler) PageConvert(*Page, tpl.Template) HandledResult {
       +func (h basicFileHandler) PageConvert(*Page) HandledResult {
                return HandledResult{}
        }
        
   DIR diff --git a/hugolib/handler_meta.go b/hugolib/handler_meta.go
       @@ -74,7 +74,7 @@ func (mh *MetaHandle) Convert(i interface{}, s *Site, results HandleResults) {
                                return
                        }
        
       -                results <- h.PageConvert(p, s.owner.tmpl)
       +                results <- h.PageConvert(p)
                }
        }
        
   DIR diff --git a/hugolib/handler_page.go b/hugolib/handler_page.go
       @@ -19,7 +19,6 @@ import (
        
                "github.com/spf13/hugo/helpers"
                "github.com/spf13/hugo/source"
       -        "github.com/spf13/hugo/tpl"
                "github.com/spf13/viper"
        )
        
       @@ -56,8 +55,8 @@ type markdownHandler struct {
        }
        
        func (h markdownHandler) Extensions() []string { return []string{"mdown", "markdown", "md"} }
       -func (h markdownHandler) PageConvert(p *Page, t tpl.Template) HandledResult {
       -        return commonConvert(p, t)
       +func (h markdownHandler) PageConvert(p *Page) HandledResult {
       +        return commonConvert(p)
        }
        
        type htmlHandler struct {
       @@ -65,7 +64,9 @@ type htmlHandler struct {
        }
        
        func (h htmlHandler) Extensions() []string { return []string{"html", "htm"} }
       -func (h htmlHandler) PageConvert(p *Page, t tpl.Template) HandledResult {
       +
       +// TODO(bep) globals use p.s.t
       +func (h htmlHandler) PageConvert(p *Page) HandledResult {
                if p.rendered {
                        panic(fmt.Sprintf("Page %q already rendered, does not need conversion", p.BaseFileName()))
                }
       @@ -73,7 +74,7 @@ func (h htmlHandler) PageConvert(p *Page, t tpl.Template) HandledResult {
                // Work on a copy of the raw content from now on.
                p.createWorkContentCopy()
        
       -        p.ProcessShortcodes(t)
       +        p.ProcessShortcodes()
        
                return HandledResult{err: nil}
        }
       @@ -83,8 +84,8 @@ type asciidocHandler struct {
        }
        
        func (h asciidocHandler) Extensions() []string { return []string{"asciidoc", "adoc", "ad"} }
       -func (h asciidocHandler) PageConvert(p *Page, t tpl.Template) HandledResult {
       -        return commonConvert(p, t)
       +func (h asciidocHandler) PageConvert(p *Page) HandledResult {
       +        return commonConvert(p)
        }
        
        type rstHandler struct {
       @@ -92,8 +93,8 @@ type rstHandler struct {
        }
        
        func (h rstHandler) Extensions() []string { return []string{"rest", "rst"} }
       -func (h rstHandler) PageConvert(p *Page, t tpl.Template) HandledResult {
       -        return commonConvert(p, t)
       +func (h rstHandler) PageConvert(p *Page) HandledResult {
       +        return commonConvert(p)
        }
        
        type mmarkHandler struct {
       @@ -101,11 +102,11 @@ type mmarkHandler struct {
        }
        
        func (h mmarkHandler) Extensions() []string { return []string{"mmark"} }
       -func (h mmarkHandler) PageConvert(p *Page, t tpl.Template) HandledResult {
       -        return commonConvert(p, t)
       +func (h mmarkHandler) PageConvert(p *Page) HandledResult {
       +        return commonConvert(p)
        }
        
       -func commonConvert(p *Page, t tpl.Template) HandledResult {
       +func commonConvert(p *Page) HandledResult {
                if p.rendered {
                        panic(fmt.Sprintf("Page %q already rendered, does not need conversion", p.BaseFileName()))
                }
       @@ -113,7 +114,7 @@ func commonConvert(p *Page, t tpl.Template) HandledResult {
                // Work on a copy of the raw content from now on.
                p.createWorkContentCopy()
        
       -        p.ProcessShortcodes(t)
       +        p.ProcessShortcodes()
        
                // TODO(bep) these page handlers need to be re-evaluated, as it is hard to
                // process a page in isolation. See the new preRender func.
   DIR diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go
       @@ -34,7 +34,6 @@ import (
        type HugoSites struct {
                Sites []*Site
        
       -        tmpl    tpl.Template
                runMode runmode
        
                multilingual *Multilingual
       @@ -50,7 +49,14 @@ type deps struct {
                // The logger to use.
                log *jww.Notepad
        
       -        // TODO(bep) next in line: Viper, hugofs, template
       +        tmpl *tpl.GoHTMLTemplate
       +
       +        // TODO(bep) next in line: Viper, hugofs
       +}
       +
       +func (d *deps) refreshTemplates(withTemplate ...func(templ tpl.Template) error) {
       +        d.tmpl = tpl.New(d.log, withTemplate...)
       +        d.tmpl.PrintErrors() // TODO(bep) globals error handling
        }
        
        func newDeps(cfg DepsCfg) *deps {
       @@ -59,11 +65,12 @@ func newDeps(cfg DepsCfg) *deps {
                if logger == nil {
                        // TODO(bep) globals default log level
                        //logger = jww.NewNotepad(jww.LevelError, jww.LevelWarn, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
       -                logger = jww.NewNotepad(jww.LevelFatal, jww.LevelFatal, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
       +                logger = jww.NewNotepad(jww.LevelError, jww.LevelError, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
                }
        
                return &deps{
       -                log: logger,
       +                log:  logger,
       +                tmpl: tpl.New(logger, cfg.WithTemplate...),
                }
        }
        
       @@ -76,8 +83,16 @@ func newHugoSites(cfg DepsCfg, sites ...*Site) (*HugoSites, error) {
                        return nil, err
                }
        
       +        var d *deps
       +
       +        if sites[0].deps != nil {
       +                d = sites[0].deps
       +        } else {
       +                d = newDeps(cfg)
       +        }
       +
                h := &HugoSites{
       -                deps:         newDeps(cfg),
       +                deps:         d,
                        multilingual: langConfig,
                        Sites:        sites}
        
       @@ -91,18 +106,24 @@ func newHugoSites(cfg DepsCfg, sites ...*Site) (*HugoSites, error) {
        // NewHugoSitesFromConfiguration creates HugoSites from the global Viper config.
        // TODO(bep) globals rename this when all the globals are gone.
        func NewHugoSitesFromConfiguration(cfg DepsCfg) (*HugoSites, error) {
       -        sites, err := createSitesFromConfig()
       +        sites, err := createSitesFromConfig(cfg)
                if err != nil {
                        return nil, err
                }
                return newHugoSites(cfg, sites...)
        }
        
       -func createSitesFromConfig() ([]*Site, error) {
       +func createSitesFromConfig(cfg DepsCfg) ([]*Site, error) {
       +        deps := newDeps(cfg)
       +        return createSitesFromDeps(deps)
       +}
       +
       +func createSitesFromDeps(deps *deps) ([]*Site, error) {
                var sites []*Site
                multilingual := viper.GetStringMap("languages")
       +
                if len(multilingual) == 0 {
       -                sites = append(sites, newSite(helpers.NewDefaultLanguage()))
       +                sites = append(sites, newSite(helpers.NewDefaultLanguage(), deps))
                }
        
                if len(multilingual) > 0 {
       @@ -115,7 +136,7 @@ func createSitesFromConfig() ([]*Site, error) {
                        }
        
                        for _, lang := range languages {
       -                        sites = append(sites, newSite(lang))
       +                        sites = append(sites, newSite(lang, deps))
                        }
        
                }
       @@ -134,7 +155,7 @@ func (h *HugoSites) reset() {
        
        func (h *HugoSites) createSitesFromConfig() error {
        
       -        sites, err := createSitesFromConfig()
       +        sites, err := createSitesFromDeps(h.deps)
        
                if err != nil {
                        return err
       @@ -192,6 +213,8 @@ type DepsCfg struct {
        
                // The Logger to use.
                Logger *jww.Notepad
       +
       +        WithTemplate []func(templ tpl.Template) error
        }
        
        func (h *HugoSites) renderCrossSitesArtifacts() error {
   DIR diff --git a/hugolib/page.go b/hugolib/page.go
       @@ -40,7 +40,6 @@ import (
                bp "github.com/spf13/hugo/bufferpool"
                "github.com/spf13/hugo/hugofs"
                "github.com/spf13/hugo/source"
       -        "github.com/spf13/hugo/tpl"
                "github.com/spf13/viper"
        )
        
       @@ -1284,7 +1283,7 @@ func (p *Page) Render(layout ...string) template.HTML {
                        l = p.layouts()
                }
        
       -        return tpl.ExecuteTemplateToHTML(p, l...)
       +        return p.s.tmpl.ExecuteTemplateToHTML(p, l...)
        }
        
        func (p *Page) determineMarkupType() string {
       @@ -1399,8 +1398,8 @@ func (p *Page) SaveSource() error {
                return p.SaveSourceAs(p.FullFilePath())
        }
        
       -func (p *Page) ProcessShortcodes(t tpl.Template) {
       -        tmpContent, tmpContentShortCodes, _ := extractAndRenderShortcodes(string(p.workContent), p, t)
       +func (p *Page) ProcessShortcodes() {
       +        tmpContent, tmpContentShortCodes, _ := extractAndRenderShortcodes(string(p.workContent), p)
                p.workContent = []byte(tmpContent)
                p.contentShortCodes = tmpContentShortCodes
        }
   DIR diff --git a/hugolib/shortcode.go b/hugolib/shortcode.go
       @@ -151,8 +151,8 @@ func (sc shortcode) String() string {
        
        // HandleShortcodes does all in  one go: extract, render and replace
        // only used for testing
       -func HandleShortcodes(stringToParse string, page *Page, t tpl.Template) (string, error) {
       -        tmpContent, tmpShortcodes, err := extractAndRenderShortcodes(stringToParse, page, t)
       +func HandleShortcodes(stringToParse string, page *Page) (string, error) {
       +        tmpContent, tmpShortcodes, err := extractAndRenderShortcodes(stringToParse, page)
        
                if err != nil {
                        return "", err
       @@ -210,8 +210,8 @@ const innerNewlineRegexp = "\n"
        const innerCleanupRegexp = `\A<p>(.*)</p>\n\z`
        const innerCleanupExpand = "$1"
        
       -func renderShortcode(sc shortcode, parent *ShortcodeWithPage, p *Page, t tpl.Template) string {
       -        tmpl := getShortcodeTemplate(sc.name, t)
       +func renderShortcode(sc shortcode, parent *ShortcodeWithPage, p *Page) string {
       +        tmpl := getShortcodeTemplate(sc.name, p.s.tmpl)
        
                if tmpl == nil {
                        p.s.log.ERROR.Printf("Unable to locate template for shortcode '%s' in page %s", sc.name, p.BaseFileName())
       @@ -230,7 +230,7 @@ func renderShortcode(sc shortcode, parent *ShortcodeWithPage, p *Page, t tpl.Tem
                                case string:
                                        inner += innerData.(string)
                                case shortcode:
       -                                inner += renderShortcode(innerData.(shortcode), data, p, t)
       +                                inner += renderShortcode(innerData.(shortcode), data, p)
                                default:
                                        p.s.log.ERROR.Printf("Illegal state on shortcode rendering of '%s' in page %s. Illegal type in inner data: %s ",
                                                sc.name, p.BaseFileName(), reflect.TypeOf(innerData))
       @@ -280,9 +280,9 @@ func renderShortcode(sc shortcode, parent *ShortcodeWithPage, p *Page, t tpl.Tem
                return renderShortcodeWithPage(tmpl, data)
        }
        
       -func extractAndRenderShortcodes(stringToParse string, p *Page, t tpl.Template) (string, map[string]func() (string, error), error) {
       +func extractAndRenderShortcodes(stringToParse string, p *Page) (string, map[string]func() (string, error), error) {
        
       -        content, shortcodes, err := extractShortcodes(stringToParse, p, t)
       +        content, shortcodes, err := extractShortcodes(stringToParse, p)
        
                if err != nil {
                        //  try to render what we have whilst logging the error
       @@ -293,7 +293,7 @@ func extractAndRenderShortcodes(stringToParse string, p *Page, t tpl.Template) (
                // TODO(bep) refactor this
                p.shortcodes = shortcodes
        
       -        renderedShortcodes := renderShortcodes(shortcodes, p, t)
       +        renderedShortcodes := renderShortcodes(shortcodes, p)
        
                return content, renderedShortcodes, err
        
       @@ -315,7 +315,7 @@ func executeShortcodeFuncMap(funcs map[string]func() (string, error)) (map[strin
                return result, nil
        }
        
       -func renderShortcodes(shortcodes map[string]shortcode, p *Page, t tpl.Template) map[string]func() (string, error) {
       +func renderShortcodes(shortcodes map[string]shortcode, p *Page) map[string]func() (string, error) {
                renderedShortcodes := make(map[string]func() (string, error))
        
                for key, sc := range shortcodes {
       @@ -324,7 +324,7 @@ func renderShortcodes(shortcodes map[string]shortcode, p *Page, t tpl.Template) 
                                renderedShortcodes[key] = emptyShortcodeFn
                        } else {
                                shorctode := sc
       -                        renderedShortcodes[key] = func() (string, error) { return renderShortcode(shorctode, nil, p, t), nil }
       +                        renderedShortcodes[key] = func() (string, error) { return renderShortcode(shorctode, nil, p), nil }
                        }
                }
        
       @@ -336,7 +336,7 @@ var errShortCodeIllegalState = errors.New("Illegal shortcode state")
        // pageTokens state:
        // - before: positioned just before the shortcode start
        // - after: shortcode(s) consumed (plural when they are nested)
       -func extractShortcode(pt *pageTokens, p *Page, t tpl.Template) (shortcode, error) {
       +func extractShortcode(pt *pageTokens, p *Page) (shortcode, error) {
                sc := shortcode{}
                var isInner = false
        
       @@ -357,7 +357,7 @@ Loop:
                                if cnt > 0 {
                                        // nested shortcode; append it to inner content
                                        pt.backup3(currItem, next)
       -                                nested, err := extractShortcode(pt, p, t)
       +                                nested, err := extractShortcode(pt, p)
                                        if err == nil {
                                                sc.inner = append(sc.inner, nested)
                                        } else {
       @@ -398,7 +398,7 @@ Loop:
                                sc.inner = append(sc.inner, currItem.val)
                        case tScName:
                                sc.name = currItem.val
       -                        tmpl := getShortcodeTemplate(sc.name, t)
       +                        tmpl := getShortcodeTemplate(sc.name, p.s.tmpl)
        
                                if tmpl == nil {
                                        return sc, fmt.Errorf("Unable to locate template for shortcode '%s' in page %s", sc.name, p.BaseFileName())
       @@ -454,7 +454,7 @@ Loop:
                return sc, nil
        }
        
       -func extractShortcodes(stringToParse string, p *Page, t tpl.Template) (string, map[string]shortcode, error) {
       +func extractShortcodes(stringToParse string, p *Page) (string, map[string]shortcode, error) {
        
                shortCodes := make(map[string]shortcode)
        
       @@ -492,7 +492,7 @@ Loop:
                        case tLeftDelimScWithMarkup, tLeftDelimScNoMarkup:
                                // let extractShortcode handle left delim (will do so recursively)
                                pt.backup()
       -                        if currShortcode, err = extractShortcode(pt, p, t); err != nil {
       +                        if currShortcode, err = extractShortcode(pt, p); err != nil {
                                        return result.String(), shortCodes, err
                                }
        
   DIR diff --git a/hugolib/shortcode_test.go b/hugolib/shortcode_test.go
       @@ -32,8 +32,13 @@ import (
        )
        
        // TODO(bep) remove
       -func pageFromString(in, filename string) (*Page, error) {
       -        return pageTestSite.NewPageFrom(strings.NewReader(in), filename)
       +func pageFromString(in, filename string, withTemplate ...func(templ tpl.Template) error) (*Page, error) {
       +        s := pageTestSite
       +        if len(withTemplate) > 0 {
       +                // Have to create a new site
       +                s = NewSiteDefaultLang(withTemplate...)
       +        }
       +        return s.NewPageFrom(strings.NewReader(in), filename)
        }
        
        func CheckShortCodeMatch(t *testing.T, input, expected string, withTemplate func(templ tpl.Template) error) {
       @@ -83,10 +88,10 @@ title: "Title"
        }
        
        func TestShortcodeGoFuzzReports(t *testing.T) {
       -        tem := tpl.New(logger)
        
       -        tem.AddInternalShortcode("sc.html", `foo`)
       -        p, _ := pageFromString(simplePage, "simple.md")
       +        p, _ := pageFromString(simplePage, "simple.md", func(templ tpl.Template) error {
       +                return templ.AddInternalShortcode("sc.html", `foo`)
       +        })
        
                for i, this := range []struct {
                        data      string
       @@ -94,7 +99,7 @@ func TestShortcodeGoFuzzReports(t *testing.T) {
                }{
                        {"{{</*/", true},
                } {
       -                output, err := HandleShortcodes(this.data, p, tem)
       +                output, err := HandleShortcodes(this.data, p)
        
                        if this.expectErr && err == nil {
                                t.Errorf("[%d] should have errored", i)
       @@ -304,15 +309,13 @@ func TestHighlight(t *testing.T) {
                viper.Set("pygmentsStyle", "bw")
                viper.Set("pygmentsUseClasses", false)
        
       -        templ := tpl.New(logger)
       -
                code := `
        {{< highlight java >}}
        void do();
        {{< /highlight >}}`
        
                p, _ := pageFromString(simplePage, "simple.md")
       -        output, err := HandleShortcodes(code, p, templ)
       +        output, err := HandleShortcodes(code, p)
        
                if err != nil {
                        t.Fatal("Handle shortcode error", err)
       @@ -379,16 +382,17 @@ func TestExtractShortcodes(t *testing.T) {
                                fmt.Sprintf("Hello %sworld%s. And that's it.", testScPlaceholderRegexp, testScPlaceholderRegexp), ""},
                } {
        
       -                p, _ := pageFromString(simplePage, "simple.md")
       -                tem := tpl.New(logger)
       -                tem.AddInternalShortcode("tag.html", `tag`)
       -                tem.AddInternalShortcode("sc1.html", `sc1`)
       -                tem.AddInternalShortcode("sc2.html", `sc2`)
       -                tem.AddInternalShortcode("inner.html", `{{with .Inner }}{{ . }}{{ end }}`)
       -                tem.AddInternalShortcode("inner2.html", `{{.Inner}}`)
       -                tem.AddInternalShortcode("inner3.html", `{{.Inner}}`)
       -
       -                content, shortCodes, err := extractShortcodes(this.input, p, tem)
       +                p, _ := pageFromString(simplePage, "simple.md", func(templ tpl.Template) error {
       +                        templ.AddInternalShortcode("tag.html", `tag`)
       +                        templ.AddInternalShortcode("sc1.html", `sc1`)
       +                        templ.AddInternalShortcode("sc2.html", `sc2`)
       +                        templ.AddInternalShortcode("inner.html", `{{with .Inner }}{{ . }}{{ end }}`)
       +                        templ.AddInternalShortcode("inner2.html", `{{.Inner}}`)
       +                        templ.AddInternalShortcode("inner3.html", `{{.Inner}}`)
       +                        return nil
       +                })
       +
       +                content, shortCodes, err := extractShortcodes(this.input, p)
        
                        if b, ok := this.expect.(bool); ok && !b {
                                if err == nil {
   DIR diff --git a/hugolib/site.go b/hugolib/site.go
       @@ -115,19 +115,23 @@ func (s *Site) reset() *Site {
        }
        
        // newSite creates a new site in the given language.
       -func newSite(lang *helpers.Language) *Site {
       +func newSite(lang *helpers.Language, deps *deps, withTemplate ...func(templ tpl.Template) error) *Site {
                c := newPageCollections()
       -        // TODO(bep) globals (also see other Site creation places)
       -        deps := newDeps(DepsCfg{})
                // TODO(bep) globals
                viper.Set("currentContentLanguage", lang)
       +
       +        if deps == nil {
       +                depsCfg := DepsCfg{WithTemplate: withTemplate}
       +                deps = newDeps(depsCfg)
       +        }
       +
                return &Site{deps: deps, Language: lang, PageCollections: c, Info: newSiteInfo(siteBuilderCfg{pageCollections: c, language: lang})}
        
        }
        
        // NewSiteDefaultLang creates a new site in the default language.
       -func NewSiteDefaultLang() *Site {
       -        return newSite(helpers.NewDefaultLanguage())
       +func NewSiteDefaultLang(withTemplate ...func(templ tpl.Template) error) *Site {
       +        return newSite(helpers.NewDefaultLanguage(), nil, withTemplate...)
        }
        
        // Convenience func used in tests.
       @@ -656,24 +660,23 @@ func (s *Site) reProcess(events []fsnotify.Event) (whatChanged, error) {
        
        }
        
       -func (s *Site) loadTemplates() {
       -        s.owner.tmpl = tpl.InitializeT(s.log)
       -        s.owner.tmpl.LoadTemplates(s.absLayoutDir())
       -        if s.hasTheme() {
       -                s.owner.tmpl.LoadTemplatesWithPrefix(s.absThemeDir()+"/layouts", "theme")
       -        }
       -}
       -
        func (s *Site) prepTemplates(withTemplate func(templ tpl.Template) error) error {
       -        s.loadTemplates()
        
       -        if withTemplate != nil {
       -                if err := withTemplate(s.owner.tmpl); err != nil {
       -                        return err
       +        wt := func(tmpl tpl.Template) error {
       +                // TODO(bep) global error handling
       +                tmpl.LoadTemplates(s.absLayoutDir())
       +                if s.hasTheme() {
       +                        tmpl.LoadTemplatesWithPrefix(s.absThemeDir()+"/layouts", "theme")
       +                }
       +                if withTemplate != nil {
       +                        if err := withTemplate(tmpl); err != nil {
       +                                return err
       +                        }
                        }
       +                return nil
                }
        
       -        s.owner.tmpl.MarkReady()
       +        s.refreshTemplates(wt)
        
                return nil
        }
       @@ -778,6 +781,7 @@ func (s *Site) process(config BuildCfg) (err error) {
                if err = s.initialize(); err != nil {
                        return
                }
       +
                s.prepTemplates(config.withTemplate)
                s.owner.tmpl.PrintErrors()
                s.timerStep("initialize & template prep")
   DIR diff --git a/hugolib/site_test.go b/hugolib/site_test.go
       @@ -109,8 +109,13 @@ func TestRenderWithInvalidTemplate(t *testing.T) {
                        t.Fatalf("Got build error: %s", err)
                }
        
       -        if s.log.LogCountForLevelsGreaterThanorEqualTo(jww.LevelError) != 1 {
       -                t.Fatalf("Expecting the template to log an ERROR")
       +        errCount := s.log.LogCountForLevelsGreaterThanorEqualTo(jww.LevelError)
       +
       +        // TODO(bep) globals clean up the template error handling
       +        // The template errors are stored in a slice etc. so we get 4 log entries
       +        // When we should get only 1
       +        if errCount == 0 {
       +                t.Fatalf("Expecting the template to log 1 ERROR, got %d", errCount)
                }
        }
        
   DIR diff --git a/tpl/template.go b/tpl/template.go
       @@ -30,10 +30,8 @@ import (
                "github.com/yosssi/ace"
        )
        
       -var localTemplates *template.Template
       -
       -// TODO(bep) globals get rid of the reset of the jww.ERR etc.
       -var tmpl *GoHTMLTemplate
       +// TODO(bep) globals get rid of the rest of the jww.ERR etc.
       +//var tmpl *GoHTMLTemplate
        
        // TODO(bep) an interface with hundreds of methods ... remove it.
        // And unexport most of these methods.
       @@ -45,13 +43,13 @@ type Template interface {
                GetClone() *template.Template
                LoadTemplates(absPath string)
                LoadTemplatesWithPrefix(absPath, prefix string)
       -        MarkReady()
                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
                PrintErrors()
       +        Funcs(funcMap template.FuncMap)
        }
        
        type templateErr struct {
       @@ -60,7 +58,8 @@ type templateErr struct {
        }
        
        type GoHTMLTemplate struct {
       -        template.Template
       +        *template.Template
       +
                clone *template.Template
        
                // a separate storage for the overlays created from cloned master templates.
       @@ -69,41 +68,54 @@ type GoHTMLTemplate struct {
        
                errors []*templateErr
        
       +        funcster *templateFuncster
       +
                // TODO(bep) globals template
                log *jww.Notepad
        }
        
       -// InitializeT resets the internal template state to its initial state
       -func InitializeT(logger *jww.Notepad) *GoHTMLTemplate {
       -        tmpl = New(logger)
       -        return tmpl
       -}
       -
        // New returns a new Hugo Template System
        // with all the additional features, templates & functions
       -func New(logger *jww.Notepad) *GoHTMLTemplate {
       -        var templates = &GoHTMLTemplate{
       -                Template: *template.New(""),
       +func New(logger *jww.Notepad, withTemplate ...func(templ Template) error) *GoHTMLTemplate {
       +        tmpl := &GoHTMLTemplate{
       +                Template: template.New(""),
                        overlays: make(map[string]*template.Template),
                        errors:   make([]*templateErr, 0),
                        log:      logger,
                }
        
       -        localTemplates = &templates.Template
       +        tmpl.funcster = newTemplateFuncster(tmpl)
        
                // The URL funcs in the funcMap is somewhat language dependent,
                // so we need to wait until the language and site config is loaded.
       -        initFuncMap()
       +        // TODO(bep) globals
       +        tmpl.funcster.initFuncMap()
        
       -        for k, v := range funcMap {
       +        // TODO(bep) globals
       +        for k, v := range tmpl.funcster.funcMap {
                        amber.FuncMap[k] = v
                }
       -        templates.Funcs(funcMap)
       -        templates.LoadEmbedded()
       -        return templates
       +
       +        tmpl.LoadEmbedded()
       +
       +        for _, wt := range withTemplate {
       +                err := wt(tmpl)
       +                if err != nil {
       +                        tmpl.errors = append(tmpl.errors, &templateErr{"init", err})
       +                }
       +
       +        }
       +
       +        tmpl.markReady()
       +
       +        return tmpl
       +}
       +
       +func (t *GoHTMLTemplate) Funcs(funcMap template.FuncMap) {
       +        t.Template.Funcs(funcMap)
        }
        
       -func partial(name string, contextList ...interface{}) template.HTML {
       +func (t *GoHTMLTemplate) partial(name string, contextList ...interface{}) template.HTML {
                if strings.HasPrefix("partials/", name) {
                        name = name[8:]
                }
       @@ -114,16 +126,16 @@ func partial(name string, contextList ...interface{}) template.HTML {
                } else {
                        context = contextList[0]
                }
       -        return ExecuteTemplateToHTML(context, "partials/"+name, "theme/partials/"+name)
       +        return t.ExecuteTemplateToHTML(context, "partials/"+name, "theme/partials/"+name)
        }
        
       -func executeTemplate(context interface{}, w io.Writer, layouts ...string) {
       +func (t *GoHTMLTemplate) executeTemplate(context interface{}, w io.Writer, layouts ...string) {
                var worked bool
                for _, layout := range layouts {
       -                templ := Lookup(layout)
       +                templ := t.Lookup(layout)
                        if templ == nil {
                                layout += ".html"
       -                        templ = Lookup(layout)
       +                        templ = t.Lookup(layout)
                        }
        
                        if templ != nil {
       @@ -136,28 +148,20 @@ func executeTemplate(context interface{}, w io.Writer, layouts ...string) {
                        }
                }
                if !worked {
       -                tmpl.log.ERROR.Println("Unable to render", layouts)
       -                tmpl.log.ERROR.Println("Expecting to find a template in either the theme/layouts or /layouts in one of the following relative locations", layouts)
       +                t.log.ERROR.Println("Unable to render", layouts)
       +                t.log.ERROR.Println("Expecting to find a template in either the theme/layouts or /layouts in one of the following relative locations", layouts)
                }
        }
        
       -func ExecuteTemplateToHTML(context interface{}, layouts ...string) template.HTML {
       +func (t *GoHTMLTemplate) ExecuteTemplateToHTML(context interface{}, layouts ...string) template.HTML {
                b := bp.GetBuffer()
                defer bp.PutBuffer(b)
       -        executeTemplate(context, b, layouts...)
       +        t.executeTemplate(context, b, layouts...)
                return template.HTML(b.String())
        }
        
       -func Lookup(name string) *template.Template {
       -        return tmpl.Lookup(name)
       -}
       -
        func (t *GoHTMLTemplate) Lookup(name string) *template.Template {
        
       -        if templ := localTemplates.Lookup(name); templ != nil {
       -                return templ
       -        }
       -
                if t.overlays != nil {
                        if templ, ok := t.overlays[name]; ok {
                                return templ
       @@ -183,9 +187,9 @@ func (t *GoHTMLTemplate) LoadEmbedded() {
                t.EmbedTemplates()
        }
        
       -// MarkReady marks the template as "ready for execution". No changes allowed
       +// markReady marks the template as "ready for execution". No changes allowed
        // after this is set.
       -func (t *GoHTMLTemplate) MarkReady() {
       +func (t *GoHTMLTemplate) markReady() {
                if t.clone == nil {
                        t.clone = template.Must(t.Template.Clone())
                }
       @@ -522,7 +526,7 @@ func (t *GoHTMLTemplate) LoadTemplates(absPath string) {
        }
        
        func (t *GoHTMLTemplate) PrintErrors() {
       -        for _, e := range t.errors {
       -                t.log.ERROR.Println(e.err)
       +        for i, e := range t.errors {
       +                t.log.ERROR.Println(i, ":", e.err)
                }
        }
   DIR diff --git a/tpl/template_ast_transformers_test.go b/tpl/template_ast_transformers_test.go
       @@ -18,7 +18,6 @@ import (
        
                "html/template"
        
       -        jww "github.com/spf13/jwalterweatherman"
                "github.com/stretchr/testify/require"
        )
        
       @@ -265,7 +264,3 @@ P2: {{ .Params.LOWER }}
                require.Contains(t, result, "P1: P1L")
                require.Contains(t, result, "P2: P1L")
        }
       -
       -func init() {
       -        jww.SetStdoutThreshold(jww.LevelCritical)
       -}
   DIR diff --git a/tpl/template_funcs.go b/tpl/template_funcs.go
       @@ -54,9 +54,19 @@ import (
                _ "image/png"
        )
        
       -var (
       -        funcMap template.FuncMap
       -)
       +// Some of the template funcs are'nt entirely stateless.
       +type templateFuncster struct {
       +        t              *GoHTMLTemplate
       +        funcMap        template.FuncMap
       +        cachedPartials partialCache
       +}
       +
       +func newTemplateFuncster(t *GoHTMLTemplate) *templateFuncster {
       +        return &templateFuncster{
       +                t:              t,
       +                cachedPartials: partialCache{p: make(map[string]template.HTML)},
       +        }
       +}
        
        // eq returns the boolean truth of arg1 == arg2.
        func eq(x, y interface{}) bool {
       @@ -1003,7 +1013,7 @@ func where(seq, key interface{}, args ...interface{}) (interface{}, error) {
        }
        
        // apply takes a map, array, or slice and returns a new slice with the function fname applied over it.
       -func apply(seq interface{}, fname string, args ...interface{}) (interface{}, error) {
       +func (tf *templateFuncster) apply(seq interface{}, fname string, args ...interface{}) (interface{}, error) {
                if seq == nil {
                        return make([]interface{}, 0), nil
                }
       @@ -1018,7 +1028,7 @@ func apply(seq interface{}, fname string, args ...interface{}) (interface{}, err
                        return nil, errors.New("can't iterate over a nil value")
                }
        
       -        fn, found := funcMap[fname]
       +        fn, found := tf.funcMap[fname]
                if !found {
                        return nil, errors.New("can't find function " + fname)
                }
       @@ -1518,41 +1528,39 @@ type partialCache struct {
        // Get retrieves partial output from the cache based upon the partial name.
        // If the partial is not found in the cache, the partial is rendered and added
        // to the cache.
       -func (c *partialCache) Get(key, name string, context interface{}) (p template.HTML) {
       +func (tf *templateFuncster) Get(key, name string, context interface{}) (p template.HTML) {
                var ok bool
        
       -        c.RLock()
       -        p, ok = c.p[key]
       -        c.RUnlock()
       +        tf.cachedPartials.RLock()
       +        p, ok = tf.cachedPartials.p[key]
       +        tf.cachedPartials.RUnlock()
        
                if ok {
                        return p
                }
        
       -        c.Lock()
       -        if p, ok = c.p[key]; !ok {
       -                p = partial(name, context)
       -                c.p[key] = p
       +        tf.cachedPartials.Lock()
       +        if p, ok = tf.cachedPartials.p[key]; !ok {
       +                p = tf.t.partial(name, context)
       +                tf.cachedPartials.p[key] = p
                }
       -        c.Unlock()
       +        tf.cachedPartials.Unlock()
        
                return p
        }
        
       -var cachedPartials = partialCache{p: make(map[string]template.HTML)}
       -
        // partialCached executes and caches partial templates.  An optional variant
        // string parameter (a string slice actually, but be only use a variadic
        // argument to make it optional) can be passed so that a given partial can have
        // multiple uses.  The cache is created with name+variant as the key.
       -func partialCached(name string, context interface{}, variant ...string) template.HTML {
       +func (tf *templateFuncster) partialCached(name string, context interface{}, variant ...string) template.HTML {
                key := name
                if len(variant) > 0 {
                        for i := 0; i < len(variant); i++ {
                                key += variant[i]
                        }
                }
       -        return cachedPartials.Get(key, name, context)
       +        return tf.Get(key, name, context)
        }
        
        // regexpCache represents a cache of regexp objects protected by a mutex.
       @@ -2090,8 +2098,8 @@ func getenv(key interface{}) (string, error) {
                return os.Getenv(skey), nil
        }
        
       -func initFuncMap() {
       -        funcMap = template.FuncMap{
       +func (tf *templateFuncster) initFuncMap() {
       +        funcMap := template.FuncMap{
                        "absURL": absURL,
                        "absLangURL": func(i interface{}) (template.HTML, error) {
                                s, err := cast.ToStringE(i)
       @@ -2102,7 +2110,7 @@ func initFuncMap() {
                        },
                        "add":           func(a, b interface{}) (interface{}, error) { return helpers.DoArithmetic(a, b, '+') },
                        "after":         after,
       -                "apply":         apply,
       +                "apply":         tf.apply,
                        "base64Decode":  base64Decode,
                        "base64Encode":  base64Encode,
                        "chomp":         chomp,
       @@ -2147,8 +2155,8 @@ func initFuncMap() {
                        "mul":           func(a, b interface{}) (interface{}, error) { return helpers.DoArithmetic(a, b, '*') },
                        "ne":            ne,
                        "now":           func() time.Time { return time.Now() },
       -                "partial":       partial,
       -                "partialCached": partialCached,
       +                "partial":       tf.t.partial,
       +                "partialCached": tf.partialCached,
                        "plainify":      plainify,
                        "pluralize":     pluralize,
                        "querify":       querify,
       @@ -2195,4 +2203,7 @@ func initFuncMap() {
                        "i18n":         i18nTranslate,
                        "T":            i18nTranslate,
                }
       +
       +        tf.funcMap = funcMap
       +        tf.t.Funcs(funcMap)
        }
   DIR diff --git a/tpl/template_funcs_test.go b/tpl/template_funcs_test.go
       @@ -1960,40 +1960,43 @@ func TestMarkdownify(t *testing.T) {
        }
        
        func TestApply(t *testing.T) {
       +
       +        f := newTestFuncster()
       +
                strings := []interface{}{"a\n", "b\n"}
                noStringers := []interface{}{tstNoStringer{}, tstNoStringer{}}
        
       -        chomped, _ := apply(strings, "chomp", ".")
       +        chomped, _ := f.apply(strings, "chomp", ".")
                assert.Equal(t, []interface{}{template.HTML("a"), template.HTML("b")}, chomped)
        
       -        chomped, _ = apply(strings, "chomp", "c\n")
       +        chomped, _ = f.apply(strings, "chomp", "c\n")
                assert.Equal(t, []interface{}{template.HTML("c"), template.HTML("c")}, chomped)
        
       -        chomped, _ = apply(nil, "chomp", ".")
       +        chomped, _ = f.apply(nil, "chomp", ".")
                assert.Equal(t, []interface{}{}, chomped)
        
       -        _, err := apply(strings, "apply", ".")
       +        _, err := f.apply(strings, "apply", ".")
                if err == nil {
                        t.Errorf("apply with apply should fail")
                }
        
                var nilErr *error
       -        _, err = apply(nilErr, "chomp", ".")
       +        _, err = f.apply(nilErr, "chomp", ".")
                if err == nil {
                        t.Errorf("apply with nil in seq should fail")
                }
        
       -        _, err = apply(strings, "dobedobedo", ".")
       +        _, err = f.apply(strings, "dobedobedo", ".")
                if err == nil {
                        t.Errorf("apply with unknown func should fail")
                }
        
       -        _, err = apply(noStringers, "chomp", ".")
       +        _, err = f.apply(noStringers, "chomp", ".")
                if err == nil {
                        t.Errorf("apply when func fails should fail")
                }
        
       -        _, err = apply(tstNoStringer{}, "chomp", ".")
       +        _, err = f.apply(tstNoStringer{}, "chomp", ".")
                if err == nil {
                        t.Errorf("apply with non-sequence should fail")
                }
       @@ -2780,7 +2783,6 @@ func TestPartialCached(t *testing.T) {
                data.Params = map[string]interface{}{"langCode": "en"}
        
                tstInitTemplates()
       -        InitializeT(logger)
                for i, tc := range testCases {
                        var tmp string
                        if tc.variant != "" {
       @@ -2831,7 +2833,6 @@ func TestPartialCached(t *testing.T) {
        }
        
        func BenchmarkPartial(b *testing.B) {
       -        InitializeT(logger)
                tmpl, err := New(logger).New("testroot").Parse(`{{ partial "bench1" . }}`)
                if err != nil {
                        b.Fatalf("unable to create new html template: %s", err)
       @@ -2851,7 +2852,6 @@ func BenchmarkPartial(b *testing.B) {
        }
        
        func BenchmarkPartialCached(b *testing.B) {
       -        InitializeT(logger)
                tmpl, err := New(logger).New("testroot").Parse(`{{ partialCached "bench1" . }}`)
                if err != nil {
                        b.Fatalf("unable to create new html template: %s", err)
       @@ -2871,7 +2871,6 @@ func BenchmarkPartialCached(b *testing.B) {
        }
        
        func BenchmarkPartialCachedVariants(b *testing.B) {
       -        InitializeT(logger)
                tmpl, err := New(logger).New("testroot").Parse(`{{ partialCached "bench1" . "header" }}`)
                if err != nil {
                        b.Fatalf("unable to create new html template: %s", err)
       @@ -2889,3 +2888,7 @@ func BenchmarkPartialCachedVariants(b *testing.B) {
                        buf.Reset()
                }
        }
       +
       +func newTestFuncster() *templateFuncster {
       +        return New(logger).funcster
       +}
   DIR diff --git a/tpl/template_test.go b/tpl/template_test.go
       @@ -55,8 +55,6 @@ html lang=en
        
                        for _, root := range []string{"", os.TempDir()} {
        
       -                        templ := New(logger)
       -
                                basePath := this.basePath
                                innerPath := this.innerPath
        
       @@ -70,17 +68,20 @@ html lang=en
        
                                d := "DATA"
        
       -                        err := templ.AddAceTemplate("mytemplate.ace", basePath, innerPath,
       -                                []byte(this.baseContent), []byte(this.innerContent))
       +                        templ := New(logger, func(templ Template) error {
       +                                return templ.AddAceTemplate("mytemplate.ace", basePath, innerPath,
       +                                        []byte(this.baseContent), []byte(this.innerContent))
        
       -                        if err != nil && this.expectErr == 0 {
       -                                t.Errorf("Test %d with root '%s' errored: %s", i, root, err)
       -                        } else if err == nil && this.expectErr == 1 {
       +                        })
       +
       +                        if len(templ.errors) > 0 && this.expectErr == 0 {
       +                                t.Errorf("Test %d with root '%s' errored: %v", i, root, templ.errors)
       +                        } else if len(templ.errors) == 0 && this.expectErr == 1 {
                                        t.Errorf("#1 Test %d with root '%s' should have errored", i, root)
                                }
        
                                var buff bytes.Buffer
       -                        err = templ.ExecuteTemplate(&buff, "mytemplate.html", d)
       +                        err := templ.ExecuteTemplate(&buff, "mytemplate.html", d)
        
                                if err != nil && this.expectErr == 0 {
                                        t.Errorf("Test %d with root '%s' errored: %s", i, root, err)
       @@ -245,7 +246,6 @@ func TestTplGoFuzzReports(t *testing.T) {
                        // Issue #1095
                        {"{{apply .C \"urlize\" " +
                                "\".\"}}", 2}} {
       -                templ := New(logger)
        
                        d := &Data{
                                A: 42,
       @@ -258,15 +258,17 @@ func TestTplGoFuzzReports(t *testing.T) {
                                H: "a,b,c,d,e,f",
                        }
        
       -                err := templ.AddTemplate("fuzz", this.data)
       +                templ := New(logger, func(templ Template) error {
       +                        return templ.AddTemplate("fuzz", this.data)
        
       -                if err != nil && this.expectErr == 0 {
       -                        t.Fatalf("Test %d errored: %s", i, err)
       -                } else if err == nil && this.expectErr == 1 {
       -                        t.Fatalf("#1 Test %d should have errored", i)
       -                }
       +                })
        
       -                err = templ.ExecuteTemplate(ioutil.Discard, "fuzz", d)
       +                if len(templ.errors) > 0 && this.expectErr == 0 {
       +                        t.Errorf("Test %d errored: %v", i, templ.errors)
       +                } else if len(templ.errors) == 0 && this.expectErr == 1 {
       +                        t.Errorf("#1 Test %d should have errored", i)
       +                }
       +                err := templ.ExecuteTemplate(ioutil.Discard, "fuzz", d)
        
                        if err != nil && this.expectErr == 0 {
                                t.Fatalf("Test %d errored: %s", i, err)
   DIR diff --git a/vendor/vendor.json b/vendor/vendor.json
       @@ -281,10 +281,10 @@
                                "revisionTime": "2016-11-30T04:45:28Z"
                        },
                        {
       -                        "checksumSHA1": "HWDERqbEvvfLwzP7Dvh2fvu+sng=",
       +                        "checksumSHA1": "9pkkhgKp3mwSreiML3plQlQYdLQ=",
                                "path": "github.com/spf13/jwalterweatherman",
       -                        "revision": "bccdd23ae5e51bd2b081814db093646c7af3d34d",
       -                        "revisionTime": "2017-01-05T10:55:09Z"
       +                        "revision": "fa7ca7e836cf3a8bb4ebf799f472c12d7e903d66",
       +                        "revisionTime": "2017-01-09T13:33:55Z"
                        },
                        {
                                "checksumSHA1": "zLJY+lsX1e5OO6gRxQd5RfKgdQY=",