Skip to content

Commit

Permalink
text/template: allow using -}} with many spaces
Browse files Browse the repository at this point in the history
lexSpace consumed all spaces, even if the last one was part of a right
delimiter like " -}}". Thus, "3  -}}" wouldn't lex as "3" and a right
delimiter, but as "3", "-", and "}}".

To fix that, make lexSpace stop if it encounters a right delimiter.

Fixes #30948.

Change-Id: I80a5546e5809e54f6823e2bf3a57a7e8808329be
Reviewed-on: https://go-review.googlesource.com/c/go/+/168457
Reviewed-by: Daniel Martí <[email protected]>
  • Loading branch information
mvdan authored and robpike committed Mar 24, 2019
1 parent b434bbf commit e770b5b
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 26 deletions.
69 changes: 43 additions & 26 deletions src/text/template/parse/lex.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,18 @@ type stateFn func(*lexer) stateFn

// lexer holds the state of the scanner.
type lexer struct {
name string // the name of the input; used only for error reports
input string // the string being scanned
leftDelim string // start of action
rightDelim string // end of action
pos Pos // current position in the input
start Pos // start position of this item
width Pos // width of last rune read from input
items chan item // channel of scanned items
parenDepth int // nesting depth of ( ) exprs
line int // 1+number of newlines seen
startLine int // start line of this item
name string // the name of the input; used only for error reports
input string // the string being scanned
leftDelim string // start of action
rightDelim string // end of action
trimRightDelim string // end of action with trim marker
pos Pos // current position in the input
start Pos // start position of this item
width Pos // width of last rune read from input
items chan item // channel of scanned items
parenDepth int // nesting depth of ( ) exprs
line int // 1+number of newlines seen
startLine int // start line of this item
}

// next returns the next rune in the input.
Expand Down Expand Up @@ -210,13 +211,14 @@ func lex(name, input, left, right string) *lexer {
right = rightDelim
}
l := &lexer{
name: name,
input: input,
leftDelim: left,
rightDelim: right,
items: make(chan item),
line: 1,
startLine: 1,
name: name,
input: input,
leftDelim: left,
rightDelim: right,
trimRightDelim: rightTrimMarker + right,
items: make(chan item),
line: 1,
startLine: 1,
}
go l.run()
return l
Expand Down Expand Up @@ -275,14 +277,12 @@ func rightTrimLength(s string) Pos {

// atRightDelim reports whether the lexer is at a right delimiter, possibly preceded by a trim marker.
func (l *lexer) atRightDelim() (delim, trimSpaces bool) {
if strings.HasPrefix(l.input[l.pos:], l.rightDelim) {
return true, false
}
// The right delim might have the marker before.
if strings.HasPrefix(l.input[l.pos:], rightTrimMarker) &&
strings.HasPrefix(l.input[l.pos+trimMarkerLen:], l.rightDelim) {
if strings.HasPrefix(l.input[l.pos:], l.trimRightDelim) { // With trim marker.
return true, true
}
if strings.HasPrefix(l.input[l.pos:], l.rightDelim) { // Without trim marker.
return true, false
}
return false, false
}

Expand Down Expand Up @@ -366,6 +366,7 @@ func lexInsideAction(l *lexer) stateFn {
case r == eof || isEndOfLine(r):
return l.errorf("unclosed action")
case isSpace(r):
l.backup() // Put space back in case we have " -}}".
return lexSpace
case r == '=':
l.emit(itemAssign)
Expand Down Expand Up @@ -418,10 +419,26 @@ func lexInsideAction(l *lexer) stateFn {
}

// lexSpace scans a run of space characters.
// One space has already been seen.
// We have not consumed the first space, which is known to be present.
// Take care if there is a trim-marked right delimiter, which starts with a space.
func lexSpace(l *lexer) stateFn {
for isSpace(l.peek()) {
var r rune
var numSpaces int
for {
r = l.peek()
if !isSpace(r) {
break
}
l.next()
numSpaces++
}
// Be careful about a trim-marked closing delimiter, which has a minus
// after a space. We know there is a space, so check for the '-' that might follow.
if strings.HasPrefix(l.input[l.pos-1:], l.trimRightDelim) {
l.backup() // Before the space.
if numSpaces == 1 {
return lexRightDelim // On the delim, so go right to that.
}
}
l.emit(itemSpace)
return lexInsideAction
Expand Down
1 change: 1 addition & 0 deletions src/text/template/parse/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ var parseTests = []parseTest{
{"trim left", "x \r\n\t{{- 3}}", noError, `"x"{{3}}`},
{"trim right", "{{3 -}}\n\n\ty", noError, `{{3}}"y"`},
{"trim left and right", "x \r\n\t{{- 3 -}}\n\n\ty", noError, `"x"{{3}}"y"`},
{"trim with extra spaces", "x\n{{- 3 -}}\ny", noError, `"x"{{3}}"y"`},
{"comment trim left", "x \r\n\t{{- /* hi */}}", noError, `"x"`},
{"comment trim right", "{{/* hi */ -}}\n\n\ty", noError, `"y"`},
{"comment trim left and right", "x \r\n\t{{- /* */ -}}\n\n\ty", noError, `"x""y"`},
Expand Down

0 comments on commit e770b5b

Please sign in to comment.