shithub: hugo

Download patch

ref: f45cb3172862140883cfa08bd401c17e1ada5b39
parent: 49ef6472039ede7d485242eba511207a8274495a
author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
date: Thu Jan 30 15:02:26 EST 2020

Fix base template handling with preceding comments

Fixes #6816

--- a/hugolib/template_test.go
+++ b/hugolib/template_test.go
@@ -398,6 +398,27 @@
 
 }
 
+// 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()
--- a/tpl/tplimpl/template.go
+++ b/tpl/tplimpl/template.go
@@ -22,6 +22,8 @@
 	"strings"
 	"sync"
 	"time"
+	"unicode"
+	"unicode/utf8"
 
 	"github.com/gohugoio/hugo/common/types"
 
@@ -72,13 +74,40 @@
 	_ 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 @@
 		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
--- a/tpl/tplimpl/template_test.go
+++ b/tpl/tplimpl/template_test.go
@@ -25,9 +25,16 @@
 	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)
 }