diff --git a/scripts/fork_go_templates/main.go b/scripts/fork_go_templates/main.go index 4ffba018f..9296b7bdd 100644 --- a/scripts/fork_go_templates/main.go +++ b/scripts/fork_go_templates/main.go @@ -17,7 +17,7 @@ import ( ) func main() { - // The current is built with Go tag go1.18 4aa1efed4853ea067d665a952eee77c52faac774 + // The current is built with 41a82aa9c3 text/template/parse: allow space after continue or break fmt.Println("Forking ...") defer fmt.Println("Done ...") diff --git a/tpl/internal/go_templates/htmltemplate/escape.go b/tpl/internal/go_templates/htmltemplate/escape.go index 5382c4288..488894416 100644 --- a/tpl/internal/go_templates/htmltemplate/escape.go +++ b/tpl/internal/go_templates/htmltemplate/escape.go @@ -45,7 +45,7 @@ func escapeTemplate(tmpl *Template, node parse.Node, name string) error { } // evalArgs formats the list of arguments into a string. It is equivalent to -// fmt.Sprint(args...), except that it deferences all pointers. +// fmt.Sprint(args...), except that it dereferences all pointers. func evalArgs(args ...any) string { // Optimization for simple common case of a single string argument. if len(args) == 1 { @@ -691,7 +691,7 @@ func (e *escaper) escapeTemplateBody(c context, t *template.Template) (context, return c.eq(c1) } // We need to assume an output context so that recursive template calls - // take the fast path out of escapeTree instead of infinitely recursing. + // take the fast path out of escapeTree instead of infinitely recurring. // Naively assuming that the input context is the same as the output // works >90% of the time. e.output[t.Name()] = c diff --git a/tpl/internal/go_templates/texttemplate/parse/parse.go b/tpl/internal/go_templates/texttemplate/parse/parse.go index b0cbe9dfc..ce548b088 100644 --- a/tpl/internal/go_templates/texttemplate/parse/parse.go +++ b/tpl/internal/go_templates/texttemplate/parse/parse.go @@ -415,8 +415,8 @@ func (t *Tree) action() (n Node) { // {{break}} // Break keyword is past. func (t *Tree) breakControl(pos Pos, line int) Node { - if token := t.next(); token.typ != itemRightDelim { - t.unexpected(token, "in {{break}}") + if token := t.nextNonSpace(); token.typ != itemRightDelim { + t.unexpected(token, "{{break}}") } if t.rangeDepth == 0 { t.errorf("{{break}} outside {{range}}") @@ -428,8 +428,8 @@ func (t *Tree) breakControl(pos Pos, line int) Node { // {{continue}} // Continue keyword is past. func (t *Tree) continueControl(pos Pos, line int) Node { - if token := t.next(); token.typ != itemRightDelim { - t.unexpected(token, "in {{continue}}") + if token := t.nextNonSpace(); token.typ != itemRightDelim { + t.unexpected(token, "{{continue}}") } if t.rangeDepth == 0 { t.errorf("{{continue}} outside {{range}}") diff --git a/tpl/internal/go_templates/texttemplate/parse/parse_test.go b/tpl/internal/go_templates/texttemplate/parse/parse_test.go index b0e75afa9..52bd6aca2 100644 --- a/tpl/internal/go_templates/texttemplate/parse/parse_test.go +++ b/tpl/internal/go_templates/texttemplate/parse/parse_test.go @@ -263,6 +263,10 @@ var parseTests = []parseTest{ {"newline in pipeline", "{{\n\"x\"\n|\nprintf\n}}", noError, `{{"x" | printf}}`}, {"newline in comment", "{{/*\nhello\n*/}}", noError, ""}, {"newline in comment", "{{-\n/*\nhello\n*/\n-}}", noError, ""}, + {"spaces around continue", "{{range .SI}}{{.}}{{ continue }}{{end}}", noError, + `{{range .SI}}{{.}}{{continue}}{{end}}`}, + {"spaces around break", "{{range .SI}}{{.}}{{ break }}{{end}}", noError, + `{{range .SI}}{{.}}{{break}}{{end}}`}, // Errors. {"unclosed action", "hello{{range", hasError, ""}, diff --git a/tpl/tplimpl/integration_test.go b/tpl/tplimpl/integration_test.go index 18cebc7d1..49722c5c1 100644 --- a/tpl/tplimpl/integration_test.go +++ b/tpl/tplimpl/integration_test.go @@ -75,9 +75,10 @@ title: "P1" -- layouts/partials/counter.html -- {{ if .Scratch.Get "counter" }}{{ .Scratch.Add "counter" 1 }}{{ else }}{{ .Scratch.Set "counter" 1 }}{{ end }}{{ return true }} -- layouts/_default/single.html -- -{{/* Note no spaces in {{continue}} or {{break}}, see https://github.com/golang/go/issues/51670 */}} continue:{{ range seq 5 }}{{ if eq . 2 }}{{continue}}{{ end }}{{ . }}{{ end }}:END: break:{{ range seq 5 }}{{ if eq . 2 }}{{break}}{{ end }}{{ . }}{{ end }}:END: +continue2:{{ range seq 5 }}{{ if eq . 2 }}{{ continue }}{{ end }}{{ . }}{{ end }}:END: +break2:{{ range seq 5 }}{{ if eq . 2 }}{{ break }}{{ end }}{{ . }}{{ end }}:END: counter1: {{ partial "counter.html" . }}/{{ .Scratch.Get "counter" }} and1: {{ if (and false (partial "counter.html" .)) }}true{{ else }}false{{ end }} @@ -103,6 +104,8 @@ counter2: {{ .Scratch.Get "counter" }} b.AssertFileContent("public/p1/index.html", ` continue:1345:END: break:1:END: +continue2:1345:END: +break2:1:END: counter1: true/1 and1: false or1: true