1
0
mirror of https://github.com/golang/go synced 2024-11-22 06:44:40 -07:00

template: finally fix space handling around actions.

Rewrite the code to express the intention more clearly.

Fixes #1042.

R=rsc
CC=golang-dev
https://golang.org/cl/2011046
This commit is contained in:
Rob Pike 2010-08-28 07:52:55 +10:00
parent da25964e9e
commit b5664ee320
2 changed files with 39 additions and 26 deletions

View File

@ -216,10 +216,9 @@ func equal(s []byte, n int, t []byte) bool {
// item is empty, we are at EOF. The item will be either a // item is empty, we are at EOF. The item will be either a
// delimited string or a non-empty string between delimited // delimited string or a non-empty string between delimited
// strings. Tokens stop at (but include, if plain text) a newline. // strings. Tokens stop at (but include, if plain text) a newline.
// Action tokens on a line by themselves drop the white space on // Action tokens on a line by themselves drop any space on
// either side, up to and including the newline. // either side, up to and including the newline.
func (t *Template) nextItem() []byte { func (t *Template) nextItem() []byte {
special := false // is this a {.foo} directive, which means trim white space?
startOfLine := t.p == 0 || t.buf[t.p-1] == '\n' startOfLine := t.p == 0 || t.buf[t.p-1] == '\n'
start := t.p start := t.p
var i int var i int
@ -233,7 +232,7 @@ func (t *Template) nextItem() []byte {
break break
} }
} }
leadingWhite := i > start leadingSpace := i > start
// What's left is nothing, newline, delimited string, or plain text // What's left is nothing, newline, delimited string, or plain text
Switch: Switch:
switch { switch {
@ -242,28 +241,50 @@ Switch:
case t.buf[i] == '\n': case t.buf[i] == '\n':
newline() newline()
case equal(t.buf, i, t.ldelim): case equal(t.buf, i, t.ldelim):
// Delete surrounding white space if this {.foo} is the first thing on the line. left := i // Start of left delimiter.
i += len(t.ldelim) // position after delimiter right := -1 // Will be (immediately after) right delimiter.
special = i+1 < len(t.buf) && (t.buf[i] == '.' || t.buf[i] == '#') haveText := false // Delimiters contain text.
if special && startOfLine { i += len(t.ldelim)
start = i - len(t.ldelim) // Find the end of the action.
} else if leadingWhite {
// not trimming space: return leading white space if there is some.
i -= len(t.ldelim)
t.p = i
return t.buf[start:i]
}
for ; i < len(t.buf); i++ { for ; i < len(t.buf); i++ {
if t.buf[i] == '\n' { if t.buf[i] == '\n' {
break break
} }
if equal(t.buf, i, t.rdelim) { if equal(t.buf, i, t.rdelim) {
i += len(t.rdelim) i += len(t.rdelim)
break Switch right = i
break
} }
haveText = true
} }
if right < 0 {
t.parseError("unmatched opening delimiter") t.parseError("unmatched opening delimiter")
return nil return nil
}
// Is this a special action (starts with '.' or '#') and the only thing on the line?
if startOfLine && haveText {
firstChar := t.buf[left+len(t.ldelim)]
if firstChar == '.' || firstChar == '#' {
// It's special and the first thing on the line. Is it the last?
for j := right; j < len(t.buf) && white(t.buf[j]); j++ {
if t.buf[j] == '\n' {
// Yes it is. Drop the surrounding space and return the {.foo}
t.linenum++
t.p = j + 1
return t.buf[left:right]
}
}
}
}
// No it's not. If there's leading space, return that.
if leadingSpace {
// not trimming space: return leading white space if there is some.
t.p = left
return t.buf[start:left]
}
// Return the word, leave the trailing space.
start = left
break
default: default:
for ; i < len(t.buf); i++ { for ; i < len(t.buf); i++ {
if t.buf[i] == '\n' { if t.buf[i] == '\n' {
@ -276,15 +297,6 @@ Switch:
} }
} }
item := t.buf[start:i] item := t.buf[start:i]
if special && startOfLine {
// consume trailing white space
for ; i < len(t.buf) && white(t.buf[i]); i++ {
if t.buf[i] == '\n' {
newline()
break // stop before newline
}
}
}
t.p = i t.p = i
return item return item
} }

View File

@ -99,6 +99,7 @@ var tests = []*Test{
&Test{" {.tab} \n", "\t", ""}, &Test{" {.tab} \n", "\t", ""},
&Test{" {#comment} \n", "", ""}, &Test{" {#comment} \n", "", ""},
&Test{"\tSome Text\t\n", "\tSome Text\t\n", ""}, &Test{"\tSome Text\t\n", "\tSome Text\t\n", ""},
&Test{" {.meta-right} {.meta-right} {.meta-right} \n", " } } } \n", ""},
// Variables at top level // Variables at top level
&Test{ &Test{