2017-07-16 23:43:04 +02:00
|
|
|
package render
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"io"
|
|
|
|
"unicode"
|
|
|
|
)
|
|
|
|
|
2017-07-17 00:02:07 +02:00
|
|
|
// A trimWriter provides whitespace control around a wrapped io.Writer.
|
|
|
|
// The caller should call TrimLeft(bool) and TrimRight(bool) respectively
|
|
|
|
// before and after processing a tag or expression, and Flush() at completion.
|
2017-07-16 23:43:04 +02:00
|
|
|
type trimWriter struct {
|
|
|
|
w io.Writer
|
2017-07-17 00:02:07 +02:00
|
|
|
buf bytes.Buffer
|
2017-07-16 23:43:04 +02:00
|
|
|
trimRight bool
|
|
|
|
}
|
|
|
|
|
2017-07-17 00:02:07 +02:00
|
|
|
// This violates the letter of the protocol by returning the count of the
|
|
|
|
// bytes, rather than the actual number of bytes written. We can't know the
|
|
|
|
// number of bytes written until later, and it won't in general be the same
|
|
|
|
// as the argument length (that's the whole point of trimming), but speaking
|
|
|
|
// truthfully here would cause some callers to return io.ErrShortWrite, ruining
|
|
|
|
// this as an io.Writer.
|
2017-07-16 23:43:04 +02:00
|
|
|
func (tw *trimWriter) Write(b []byte) (int, error) {
|
2017-07-17 00:02:07 +02:00
|
|
|
n := len(b)
|
2017-07-16 23:43:04 +02:00
|
|
|
if tw.trimRight {
|
|
|
|
b = bytes.TrimLeftFunc(b, unicode.IsSpace)
|
2022-01-06 14:26:10 +01:00
|
|
|
if n != 0 {
|
|
|
|
tw.trimRight = false
|
|
|
|
}
|
2017-07-17 00:02:07 +02:00
|
|
|
} else if tw.buf.Len() > 0 {
|
|
|
|
if err := tw.Flush(); err != nil {
|
2017-07-16 23:43:04 +02:00
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nonWS := bytes.TrimRightFunc(b, unicode.IsSpace)
|
|
|
|
if len(nonWS) < len(b) {
|
2017-07-17 00:02:07 +02:00
|
|
|
if _, err := tw.buf.Write(b[len(nonWS):]); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
2017-07-16 23:43:04 +02:00
|
|
|
}
|
2017-07-17 00:02:07 +02:00
|
|
|
_, err := tw.w.Write(nonWS)
|
|
|
|
return n, err
|
2017-07-16 23:43:04 +02:00
|
|
|
}
|
|
|
|
func (tw *trimWriter) Flush() (err error) {
|
2017-07-17 00:02:07 +02:00
|
|
|
if tw.buf.Len() > 0 {
|
|
|
|
_, err = tw.buf.WriteTo(tw.w)
|
|
|
|
tw.buf.Reset()
|
2017-07-16 23:43:04 +02:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tw *trimWriter) TrimLeft(f bool) {
|
2017-07-17 00:02:07 +02:00
|
|
|
if !f && tw.buf.Len() > 0 {
|
2017-07-16 23:43:04 +02:00
|
|
|
if err := tw.Flush(); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
2017-07-17 00:02:07 +02:00
|
|
|
tw.buf.Reset()
|
2017-07-16 23:43:04 +02:00
|
|
|
tw.trimRight = false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tw *trimWriter) TrimRight(f bool) {
|
|
|
|
tw.trimRight = f
|
|
|
|
}
|