From 87dbec54bb0357a5de587e55d30ee0716b3def79 Mon Sep 17 00:00:00 2001 From: Gustavo Niemeyer Date: Mon, 30 May 2011 11:53:09 -0300 Subject: [PATCH] template: fix and clean interaction between quotes and formatters Fixes issue #1897. R=r, gustavo, r CC=golang-dev https://golang.org/cl/4561049 --- src/pkg/template/template.go | 47 ++++++++++++++++++++++--------- src/pkg/template/template_test.go | 12 ++++---- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/pkg/template/template.go b/src/pkg/template/template.go index 0706c93fe2c..10111900445 100644 --- a/src/pkg/template/template.go +++ b/src/pkg/template/template.go @@ -491,20 +491,9 @@ func (t *Template) formatter(name string) func(io.Writer, string, ...interface{} // -- Parsing -// Allocate a new variable-evaluation element. +// newVariable allocates a new variable-evaluation element. func (t *Template) newVariable(words []string) *variableElement { - // After the final space-separated argument, formatters may be specified separated - // by pipe symbols, for example: {a b c|d|e} - - // Until we learn otherwise, formatters contains a single name: "", the default formatter. - formatters := []string{""} - lastWord := words[len(words)-1] - bar := strings.IndexRune(lastWord, '|') - if bar >= 0 { - words[len(words)-1] = lastWord[0:bar] - formatters = strings.Split(lastWord[bar+1:], "|", -1) - } - + formatters := extractFormatters(words) args := make([]interface{}, len(words)) // Build argument list, processing any literals @@ -550,6 +539,38 @@ func (t *Template) newVariable(words []string) *variableElement { return &variableElement{t.linenum, args, formatters} } +// extractFormatters extracts a list of formatters from words. +// After the final space-separated argument in a variable, formatters may be +// specified separated by pipe symbols. For example: {a b c|d|e} +// The words parameter still has the formatters joined by '|' in the last word. +// extractFormatters splits formatters, replaces the last word with the content +// found before the first '|' within it, and returns the formatters obtained. +// If no formatters are found in words, the default formatter is returned. +func extractFormatters(words []string) (formatters []string) { + // "" is the default formatter. + formatters = []string{""} + if len(words) == 0 { + return + } + var bar int + lastWord := words[len(words)-1] + if isQuote(lastWord[0]) { + end := endQuote([]byte(lastWord), 0) + if end < 0 || end+1 == len(lastWord) || lastWord[end+1] != '|' { + return + } + bar = end + 1 + } else { + bar = strings.IndexRune(lastWord, '|') + if bar < 0 { + return + } + } + words[len(words)-1] = lastWord[0:bar] + formatters = strings.Split(lastWord[bar+1:], "|", -1) + return +} + // Grab the next item. If it's simple, just append it to the template. // Otherwise return its details. func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) { diff --git a/src/pkg/template/template_test.go b/src/pkg/template/template_test.go index 147a1ca2178..99b23c28836 100644 --- a/src/pkg/template/template_test.go +++ b/src/pkg/template/template_test.go @@ -144,21 +144,21 @@ var tests = []*Test{ }, &Test{ - in: `{"Strings" ":"} {""} {"\t\u0123 \x23\\"} {"\"}{\\"}`, + in: `{"Strings" ":"} {""} {"|"} {"\t\u0123 \x23\\"} {"\"}{\\"}`, - out: "Strings: \t\u0123 \x23\\ \"}{\\", + out: "Strings: | \t\u0123 \x23\\ \"}{\\", }, &Test{ - in: "{`Raw strings` `:`} {``} {`\\t\\u0123 \\x23\\`} {`}{\\`}", + in: "{`Raw strings` `:`} {``} {`|`} {`\\t\\u0123 \\x23\\`} {`}{\\`}", - out: "Raw strings: \\t\\u0123 \\x23\\ }{\\", + out: "Raw strings: | \\t\\u0123 \\x23\\ }{\\", }, &Test{ - in: "Characters: {'a'} {'\\u0123'} {' '} {'}'} {'{'}", + in: "Characters: {'a'} {'\\u0123'} {' '} {'{'} {'|'} {'}'}", - out: "Characters: 97 291 32 125 123", + out: "Characters: 97 291 32 123 124 125", }, &Test{