Commit 04220014 authored by Rob Pike's avatar Rob Pike

text/template: allow newlines in raw quotes

This was disallowed for error-checking reasons but people ask for
it, it's easy, and it's clear what it all means.

Fixes #7323.

Change-Id: I26542f5ac6519e45b335ad789713a4d9e356279b
Reviewed-on: https://go-review.googlesource.com/9537Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent cf3ac26a
......@@ -18,7 +18,7 @@ structure as execution proceeds.
The input text for a template is UTF-8-encoded text in any format.
"Actions"--data evaluations or control structures--are delimited by
"{{" and "}}"; all text outside actions is copied to the output unchanged.
Actions may not span newlines, although comments can.
Except for raw strings, actions may not span newlines, although comments can.
Once parsed, a template may be executed safely in parallel.
......@@ -106,7 +106,7 @@ An argument is a simple value, denoted by one of the following.
- A boolean, string, character, integer, floating-point, imaginary
or complex constant in Go syntax. These behave like Go's untyped
constants, although raw strings may not span newlines.
constants.
- The keyword nil, representing an untyped Go nil.
- The character '.' (period):
.
......
......@@ -1095,3 +1095,16 @@ func TestMissingMapKey(t *testing.T) {
t.Errorf("expected error; got none")
}
}
// Test that the error message for multiline unterminated string
// refers to the line number of the opening quote.
func TestUnterminatedStringError(t *testing.T) {
_, err := New("X").Parse("hello\n\n{{`unterminated\n\n\n\n}}\n some more\n\n")
if err == nil {
t.Fatal("expected error")
}
str := err.Error()
if !strings.Contains(str, "X:3: unexpected unterminated raw quoted strin") {
t.Fatalf("unexpected error: %s", str)
}
}
......@@ -525,7 +525,7 @@ func lexRawQuote(l *lexer) stateFn {
Loop:
for {
switch l.next() {
case eof, '\n':
case eof:
return l.errorf("unterminated raw quoted string")
case '`':
break Loop
......
......@@ -58,18 +58,20 @@ type lexTest struct {
}
var (
tEOF = item{itemEOF, 0, ""}
tFor = item{itemIdentifier, 0, "for"}
tLeft = item{itemLeftDelim, 0, "{{"}
tLpar = item{itemLeftParen, 0, "("}
tPipe = item{itemPipe, 0, "|"}
tQuote = item{itemString, 0, `"abc \n\t\" "`}
tRange = item{itemRange, 0, "range"}
tRight = item{itemRightDelim, 0, "}}"}
tRpar = item{itemRightParen, 0, ")"}
tSpace = item{itemSpace, 0, " "}
raw = "`" + `abc\n\t\" ` + "`"
tRawQuote = item{itemRawString, 0, raw}
tEOF = item{itemEOF, 0, ""}
tFor = item{itemIdentifier, 0, "for"}
tLeft = item{itemLeftDelim, 0, "{{"}
tLpar = item{itemLeftParen, 0, "("}
tPipe = item{itemPipe, 0, "|"}
tQuote = item{itemString, 0, `"abc \n\t\" "`}
tRange = item{itemRange, 0, "range"}
tRight = item{itemRightDelim, 0, "}}"}
tRpar = item{itemRightParen, 0, ")"}
tSpace = item{itemSpace, 0, " "}
raw = "`" + `abc\n\t\" ` + "`"
rawNL = "`now is{{\n}}the time`" // Contains newline inside raw quote.
tRawQuote = item{itemRawString, 0, raw}
tRawQuoteNL = item{itemRawString, 0, rawNL}
)
var lexTests = []lexTest{
......@@ -104,6 +106,7 @@ var lexTests = []lexTest{
{"for", `{{for}}`, []item{tLeft, tFor, tRight, tEOF}},
{"quote", `{{"abc \n\t\" "}}`, []item{tLeft, tQuote, tRight, tEOF}},
{"raw quote", "{{" + raw + "}}", []item{tLeft, tRawQuote, tRight, tEOF}},
{"raw quote with newline", "{{" + rawNL + "}}", []item{tLeft, tRawQuoteNL, tRight, tEOF}},
{"numbers", "{{1 02 0x14 -7.2i 1e3 +1.2e-4 4.2i 1+2i}}", []item{
tLeft,
{itemNumber, 0, "1"},
......@@ -294,7 +297,7 @@ var lexTests = []lexTest{
tLeft,
{itemError, 0, "unterminated quoted string"},
}},
{"unclosed raw quote", "{{`xx\n`}}", []item{
{"unclosed raw quote", "{{`xx}}", []item{
tLeft,
{itemError, 0, "unterminated raw quoted string"},
}},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment