1
0
mirror of https://github.com/golang/go synced 2024-11-22 03:24:41 -07:00

template: change the signature of formatters for future development.

Make them more like Printf, with a ... final argument.  This breaks
code with existing formatters but not the templates that use them.

R=rsc, gri
CC=golang-dev
https://golang.org/cl/3378041
This commit is contained in:
Rob Pike 2010-12-01 13:33:49 -08:00
parent 009aebdba8
commit d1524217df
5 changed files with 54 additions and 44 deletions

View File

@ -563,7 +563,7 @@ func writeText(w io.Writer, text []byte, html bool) {
// Write anything to w; optionally html-escaped. // Write anything to w; optionally html-escaped.
func writeAny(w io.Writer, x interface{}, html bool) { func writeAny(w io.Writer, html bool, x interface{}) {
switch v := x.(type) { switch v := x.(type) {
case []byte: case []byte:
writeText(w, v, html) writeText(w, v, html)
@ -584,23 +584,23 @@ func writeAny(w io.Writer, x interface{}, html bool) {
// Template formatter for "html" format. // Template formatter for "html" format.
func htmlFmt(w io.Writer, x interface{}, format string) { func htmlFmt(w io.Writer, format string, x ...interface{}) {
writeAny(w, x, true) writeAny(w, true, x[0])
} }
// Template formatter for "html-esc" format. // Template formatter for "html-esc" format.
func htmlEscFmt(w io.Writer, x interface{}, format string) { func htmlEscFmt(w io.Writer, format string, x ...interface{}) {
var buf bytes.Buffer var buf bytes.Buffer
writeAny(&buf, x, false) writeAny(&buf, false, x[0])
template.HTMLEscape(w, buf.Bytes()) template.HTMLEscape(w, buf.Bytes())
} }
// Template formatter for "html-comment" format. // Template formatter for "html-comment" format.
func htmlCommentFmt(w io.Writer, x interface{}, format string) { func htmlCommentFmt(w io.Writer, format string, x ...interface{}) {
var buf bytes.Buffer var buf bytes.Buffer
writeAny(&buf, x, false) writeAny(&buf, false, x[0])
// TODO(gri) Provide list of words (e.g. function parameters) // TODO(gri) Provide list of words (e.g. function parameters)
// to be emphasized by ToHTML. // to be emphasized by ToHTML.
doc.ToHTML(w, buf.Bytes(), nil) // does html-escaping doc.ToHTML(w, buf.Bytes(), nil) // does html-escaping
@ -608,13 +608,13 @@ func htmlCommentFmt(w io.Writer, x interface{}, format string) {
// Template formatter for "" (default) format. // Template formatter for "" (default) format.
func textFmt(w io.Writer, x interface{}, format string) { func textFmt(w io.Writer, format string, x ...interface{}) {
writeAny(w, x, false) writeAny(w, false, x[0])
} }
// Template formatter for the various "url-xxx" formats. // Template formatter for the various "url-xxx" formats.
func urlFmt(w io.Writer, x interface{}, format string) { func urlFmt(w io.Writer, format string, x ...interface{}) {
var path string var path string
var line int var line int
@ -622,7 +622,7 @@ func urlFmt(w io.Writer, x interface{}, format string) {
type positioner interface { type positioner interface {
Pos() token.Position Pos() token.Position
} }
switch t := x.(type) { switch t := x[0].(type) {
case string: case string:
path = t path = t
case positioner: case positioner:
@ -676,14 +676,14 @@ var infoKinds = [nKinds]string{
// Template formatter for "infoKind" format. // Template formatter for "infoKind" format.
func infoKindFmt(w io.Writer, x interface{}, format string) { func infoKindFmt(w io.Writer, format string, x ...interface{}) {
fmt.Fprintf(w, infoKinds[x.(SpotKind)]) // infoKind entries are html-escaped fmt.Fprintf(w, infoKinds[x[0].(SpotKind)]) // infoKind entries are html-escaped
} }
// Template formatter for "infoLine" format. // Template formatter for "infoLine" format.
func infoLineFmt(w io.Writer, x interface{}, format string) { func infoLineFmt(w io.Writer, format string, x ...interface{}) {
info := x.(SpotInfo) info := x[0].(SpotInfo)
line := info.Lori() line := info.Lori()
if info.IsIndex() { if info.IsIndex() {
index, _ := searchIndex.get() index, _ := searchIndex.get()
@ -702,8 +702,8 @@ func infoLineFmt(w io.Writer, x interface{}, format string) {
// Template formatter for "infoSnippet" format. // Template formatter for "infoSnippet" format.
func infoSnippetFmt(w io.Writer, x interface{}, format string) { func infoSnippetFmt(w io.Writer, format string, x ...interface{}) {
info := x.(SpotInfo) info := x[0].(SpotInfo)
text := `<span class="alert">no snippet text available</span>` text := `<span class="alert">no snippet text available</span>`
if info.IsIndex() { if info.IsIndex() {
index, _ := searchIndex.get() index, _ := searchIndex.get()
@ -716,30 +716,30 @@ func infoSnippetFmt(w io.Writer, x interface{}, format string) {
// Template formatter for "padding" format. // Template formatter for "padding" format.
func paddingFmt(w io.Writer, x interface{}, format string) { func paddingFmt(w io.Writer, format string, x ...interface{}) {
for i := x.(int); i > 0; i-- { for i := x[0].(int); i > 0; i-- {
fmt.Fprint(w, `<td width="25"></td>`) fmt.Fprint(w, `<td width="25"></td>`)
} }
} }
// Template formatter for "time" format. // Template formatter for "time" format.
func timeFmt(w io.Writer, x interface{}, format string) { func timeFmt(w io.Writer, format string, x ...interface{}) {
template.HTMLEscape(w, []byte(time.SecondsToLocalTime(x.(int64)/1e9).String())) template.HTMLEscape(w, []byte(time.SecondsToLocalTime(x[0].(int64)/1e9).String()))
} }
// Template formatter for "dir/" format. // Template formatter for "dir/" format.
func dirslashFmt(w io.Writer, x interface{}, format string) { func dirslashFmt(w io.Writer, format string, x ...interface{}) {
if x.(*os.FileInfo).IsDirectory() { if x[0].(*os.FileInfo).IsDirectory() {
w.Write([]byte{'/'}) w.Write([]byte{'/'})
} }
} }
// Template formatter for "localname" format. // Template formatter for "localname" format.
func localnameFmt(w io.Writer, x interface{}, format string) { func localnameFmt(w io.Writer, format string, x ...interface{}) {
_, localname := pathutil.Split(x.(string)) _, localname := pathutil.Split(x[0].(string))
template.HTMLEscape(w, []byte(localname)) template.HTMLEscape(w, []byte(localname))
} }

View File

@ -367,7 +367,7 @@ func main() {
if i > 0 { if i > 0 {
fmt.Println() fmt.Println()
} }
writeAny(os.Stdout, d, *html) writeAny(os.Stdout, *html, d)
fmt.Println() fmt.Println()
} }
return return

View File

@ -16,12 +16,14 @@ import (
// It is stored under the name "str" and is the default formatter. // It is stored under the name "str" and is the default formatter.
// You can override the default formatter by storing your default // You can override the default formatter by storing your default
// under the name "" in your custom formatter map. // under the name "" in your custom formatter map.
func StringFormatter(w io.Writer, value interface{}, format string) { func StringFormatter(w io.Writer, format string, value ...interface{}) {
if b, ok := value.([]byte); ok { if len(value) == 1 {
w.Write(b) if b, ok := value[0].([]byte); ok {
return w.Write(b)
return
}
} }
fmt.Fprint(w, value) fmt.Fprint(w, value...)
} }
var ( var (
@ -60,11 +62,15 @@ func HTMLEscape(w io.Writer, s []byte) {
} }
// HTMLFormatter formats arbitrary values for HTML // HTMLFormatter formats arbitrary values for HTML
func HTMLFormatter(w io.Writer, value interface{}, format string) { func HTMLFormatter(w io.Writer, format string, value ...interface{}) {
b, ok := value.([]byte) ok := false
var b []byte
if len(value) == 1 {
b, ok = value[0].([]byte)
}
if !ok { if !ok {
var buf bytes.Buffer var buf bytes.Buffer
fmt.Fprint(&buf, value) fmt.Fprint(&buf, value...)
b = buf.Bytes() b = buf.Bytes()
} }
HTMLEscape(w, b) HTMLEscape(w, b)

View File

@ -55,9 +55,10 @@
map passed to the template set up routines or in the default map passed to the template set up routines or in the default
set ("html","str","") and is used to process the data for set ("html","str","") and is used to process the data for
output. The formatter function has signature output. The formatter function has signature
func(wr io.Writer, data interface{}, formatter string) func(wr io.Writer, formatter string, data ...interface{})
where wr is the destination for output, data is the field where wr is the destination for output, data holds the field
value, and formatter is its name at the invocation site. values at the instantiation, and formatter is its name at
the invocation site.
*/ */
package template package template
@ -101,7 +102,7 @@ const (
// FormatterMap is the type describing the mapping from formatter // FormatterMap is the type describing the mapping from formatter
// names to the functions that implement them. // names to the functions that implement them.
type FormatterMap map[string]func(io.Writer, interface{}, string) type FormatterMap map[string]func(io.Writer, string, ...interface{})
// Built-in formatters. // Built-in formatters.
var builtins = FormatterMap{ var builtins = FormatterMap{
@ -690,13 +691,13 @@ func (t *Template) writeVariable(v *variableElement, st *state) {
// is it in user-supplied map? // is it in user-supplied map?
if t.fmap != nil { if t.fmap != nil {
if fn, ok := t.fmap[formatter]; ok { if fn, ok := t.fmap[formatter]; ok {
fn(st.wr, val, formatter) fn(st.wr, formatter, val)
return return
} }
} }
// is it in builtin map? // is it in builtin map?
if fn, ok := builtins[formatter]; ok { if fn, ok := builtins[formatter]; ok {
fn(st.wr, val, formatter) fn(st.wr, formatter, val)
return return
} }
t.execError(st, v.linenum, "missing formatter %s for variable %s", formatter, v.name) t.execError(st, v.linenum, "missing formatter %s for variable %s", formatter, v.name)

View File

@ -76,9 +76,12 @@ func plus1(v interface{}) string {
return fmt.Sprint(i + 1) return fmt.Sprint(i + 1)
} }
func writer(f func(interface{}) string) func(io.Writer, interface{}, string) { func writer(f func(interface{}) string) func(io.Writer, string, ...interface{}) {
return func(w io.Writer, v interface{}, format string) { return func(w io.Writer, format string, v ...interface{}) {
io.WriteString(w, f(v)) if len(v) != 1 {
panic("test writer expected one arg")
}
io.WriteString(w, f(v[0]))
} }
} }
@ -601,7 +604,7 @@ func TestHTMLFormatterWithByte(t *testing.T) {
s := "Test string." s := "Test string."
b := []byte(s) b := []byte(s)
var buf bytes.Buffer var buf bytes.Buffer
HTMLFormatter(&buf, b, "") HTMLFormatter(&buf, "", b)
bs := buf.String() bs := buf.String()
if bs != s { if bs != s {
t.Errorf("munged []byte, expected: %s got: %s", s, bs) t.Errorf("munged []byte, expected: %s got: %s", s, bs)