-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Closed
Labels
Description
A recent issue with the HTMLFormatter mishandling []byte values has prompted a discussion about restructuring the way template formatters work. See the thread here: http://groups.google.com/group/golang-dev/t/9e19c6b2f578c5ad And relevant notes from rsc: -- The most interesting formatters, at least in the template code I've written or seen, are the ones that take a particular rich data type and do something type-specific. For example, godoc has formatters that format a syntax tree as HTML or as text. The directory listings have a tiny little formatter called dir/ that takes a *os.Dir and emits a "/" if it is a directory, and "" otherwise, which puts the / on adler32/ on the http://golang.org/src/pkg/hash/ page. There are probably more that I'm forgetting, but it's important not to make those harder. One possibility would be to change the signature of the formatters to allow func Formatter(w io.Writer, value T, format string) for any type T, and have Execute treat T = string or T = []byte as meaning "if it's not that type already, convert to a string representation and then pass that type". So you'd have func HTMLFormatter(w io.Writer, value []byte, format string) and Execute would then do the conversions, but func DirSlash(w io.Writer, value *os.Dir, format string) func HTMLAst(w io.Writer, value ast.Expr, format string) would still work too (and Execute could give a good error when the value isn't the expected type). That opens the door to the possibility of using formatters that accept []byte in pseudo-pipelines, like {foo|ast|html} as long as the ast formatter can handle foo and then the html formatter can handle []byte. Execute would run "ast" writing to a bytes.Buffer and then run "html" passing buf.Bytes() writing to wherever it usually writes to. The reflect package didn't have Call when we wrote template, so this wasn't an option we could have even considered. Json-template does pipelines now but there it's easier to just keep returning new values and taking old values, because there are no static types in the program.