From f45cb3172862140883cfa08bd401c17e1ada5b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Thu, 30 Jan 2020 20:02:26 +0100 Subject: [PATCH] Fix base template handling with preceding comments Fixes #6816 --- hugolib/template_test.go | 21 ++++++++++++++++++ tpl/tplimpl/template.go | 41 ++++++++++++++++++++++++++++++------ tpl/tplimpl/template_test.go | 13 +++++++++--- 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/hugolib/template_test.go b/hugolib/template_test.go index 44566f5a750..ccf5d103e48 100644 --- a/hugolib/template_test.go +++ b/hugolib/template_test.go @@ -398,6 +398,27 @@ title: The Page } +// https://github.com/gohugoio/hugo/issues/6816 +func TestTemplateBaseWithComment(t *testing.T) { + t.Parallel() + b := newTestSitesBuilder(t).WithSimpleConfigFile() + b.WithTemplatesAdded( + "baseof.html", `Base: {{ block "main" . }}{{ end }}`, + "index.html", ` + {{/* A comment */}} + {{ define "main" }} + Bonjour + {{ end }} + + + `) + + b.Build(BuildCfg{}) + b.AssertFileContent("public/index.html", `Base: +Bonjour`) + +} + func TestTemplateLookupSite(t *testing.T) { t.Run("basic", func(t *testing.T) { t.Parallel() diff --git a/tpl/tplimpl/template.go b/tpl/tplimpl/template.go index a87cdde344d..457a5cb9285 100644 --- a/tpl/tplimpl/template.go +++ b/tpl/tplimpl/template.go @@ -22,6 +22,8 @@ import ( "strings" "sync" "time" + "unicode" + "unicode/utf8" "github.com/gohugoio/hugo/common/types" @@ -72,13 +74,40 @@ var ( _ tpl.Info = (*templateState)(nil) ) -// A template needing a base template is a template with only define sections, -// but we check only for the start. -// If a base template does not exist, we will handle that when it's used. -var baseTemplateDefineRe = regexp.MustCompile(`^\s*{{-?\s*define`) +var baseTemplateDefineRe = regexp.MustCompile(`^{{-?\s*define`) +// needsBaseTemplate returns true if the first non-comment template block is a +// define block. +// If a base template does not exist, we will handle that when it's used. func needsBaseTemplate(templ string) bool { - return baseTemplateDefineRe.MatchString(templ) + idx := -1 + inComment := false + for i := 0; i < len(templ); { + if !inComment && strings.HasPrefix(templ[i:], "{{/*") { + inComment = true + i += 4 + } else if inComment && strings.HasPrefix(templ[i:], "*/}}") { + inComment = false + i += 4 + } else { + r, size := utf8.DecodeRuneInString(templ[i:]) + if !inComment { + if strings.HasPrefix(templ[i:], "{{") { + idx = i + break + } else if !unicode.IsSpace(r) { + break + } + } + i += size + } + } + + if idx == -1 { + return false + } + + return baseTemplateDefineRe.MatchString(templ[idx:]) } func newIdentity(name string) identity.Manager { @@ -549,7 +578,7 @@ func (t *templateHandler) addTemplateFile(name, path string) error { return nil } - needsBaseof := !t.noBaseNeeded(name) && baseTemplateDefineRe.MatchString(tinfo.template) + needsBaseof := !t.noBaseNeeded(name) && needsBaseTemplate(tinfo.template) if needsBaseof { t.needsBaseof[name] = tinfo return nil diff --git a/tpl/tplimpl/template_test.go b/tpl/tplimpl/template_test.go index 05be5bbb765..5e372d986a8 100644 --- a/tpl/tplimpl/template_test.go +++ b/tpl/tplimpl/template_test.go @@ -25,9 +25,16 @@ func TestNeedsBaseTemplate(t *testing.T) { c.Assert(needsBaseTemplate(`{{define "main" }}`), qt.Equals, true) c.Assert(needsBaseTemplate(`{{- define "main" }}`), qt.Equals, true) c.Assert(needsBaseTemplate(`{{-define "main" }}`), qt.Equals, true) + c.Assert(needsBaseTemplate(` + + {{-define "main" }} + + `), qt.Equals, true) c.Assert(needsBaseTemplate(` {{ define "main" }}`), qt.Equals, true) - c.Assert(needsBaseTemplate(` -{{ define "main" }}`), qt.Equals, true) + c.Assert(needsBaseTemplate(` + {{ define "main" }}`), qt.Equals, true) c.Assert(needsBaseTemplate(` A {{ define "main" }}`), qt.Equals, false) - + c.Assert(needsBaseTemplate(` {{ printf "foo" }}`), qt.Equals, false) + c.Assert(needsBaseTemplate(`{{/* comment */}} {{ define "main" }}`), qt.Equals, true) + c.Assert(needsBaseTemplate(` {{/* comment */}} A {{ define "main" }}`), qt.Equals, false) }