1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
package padding
import (
"bytes"
"io"
"strings"
"github.com/mattn/go-runewidth"
"github.com/muesli/reflow/ansi"
)
type PaddingFunc func(w io.Writer)
type Writer struct {
Padding uint
PadFunc PaddingFunc
ansiWriter *ansi.Writer
buf bytes.Buffer
cache bytes.Buffer
lineLen int
ansi bool
}
func NewWriter(width uint, paddingFunc PaddingFunc) *Writer {
w := &Writer{
Padding: width,
PadFunc: paddingFunc,
}
w.ansiWriter = &ansi.Writer{
Forward: &w.buf,
}
return w
}
func NewWriterPipe(forward io.Writer, width uint, paddingFunc PaddingFunc) *Writer {
return &Writer{
Padding: width,
PadFunc: paddingFunc,
ansiWriter: &ansi.Writer{
Forward: forward,
},
}
}
// Bytes is shorthand for declaring a new default padding-writer instance,
// used to immediately pad a byte slice.
func Bytes(b []byte, width uint) []byte {
f := NewWriter(width, nil)
_, _ = f.Write(b)
_ = f.Flush()
return f.Bytes()
}
// String is shorthand for declaring a new default padding-writer instance,
// used to immediately pad a string.
func String(s string, width uint) string {
return string(Bytes([]byte(s), width))
}
// Write is used to write content to the padding buffer.
func (w *Writer) Write(b []byte) (int, error) {
for _, c := range string(b) {
if c == '\x1B' {
// ANSI escape sequence
w.ansi = true
} else if w.ansi {
if (c >= 0x41 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a) {
// ANSI sequence terminated
w.ansi = false
}
} else {
w.lineLen += runewidth.StringWidth(string(c))
if c == '\n' {
// end of current line
err := w.pad()
if err != nil {
return 0, err
}
w.ansiWriter.ResetAnsi()
w.lineLen = 0
}
}
_, err := w.ansiWriter.Write([]byte(string(c)))
if err != nil {
return 0, err
}
}
return len(b), nil
}
func (w *Writer) pad() error {
if w.Padding > 0 && uint(w.lineLen) < w.Padding {
if w.PadFunc != nil {
for i := 0; i < int(w.Padding)-w.lineLen; i++ {
w.PadFunc(w.ansiWriter)
}
} else {
_, err := w.ansiWriter.Write([]byte(strings.Repeat(" ", int(w.Padding)-w.lineLen)))
if err != nil {
return err
}
}
}
return nil
}
// Close will finish the padding operation.
func (w *Writer) Close() (err error) {
return w.Flush()
}
// Bytes returns the padded result as a byte slice.
func (w *Writer) Bytes() []byte {
return w.cache.Bytes()
}
// String returns the padded result as a string.
func (w *Writer) String() string {
return w.cache.String()
}
// Flush will finish the padding operation. Always call it before trying to
// retrieve the final result.
func (w *Writer) Flush() (err error) {
if w.lineLen != 0 {
if err = w.pad(); err != nil {
return
}
}
w.cache.Reset()
_, err = w.buf.WriteTo(&w.cache)
w.lineLen = 0
w.ansi = false
return
}
|