-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathformatter.go
137 lines (122 loc) · 2.65 KB
/
formatter.go
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
package pogo
import (
"bytes"
"io"
"strings"
"github.com/pkg/errors"
)
// Formatter to write text with an options
type Formatter struct {
// Border is an prefix to each line
Border string
// Prefix is an extra prefix to first line between border and text
Prefix string
// Width of line to wrap (no wrap if less or equal zero)
Width int
buffer *bytes.Buffer
output io.Writer
}
// NewFormatter to write in w
func NewFormatter(w io.Writer) *Formatter {
return &Formatter{
buffer: &bytes.Buffer{},
output: w,
}
}
// Format text
func (f *Formatter) Format(text string) error {
return recoverHandledError(func() {
f.mustFormat(text)
})
}
// BreakLine add \n
func (f *Formatter) BreakLine() error {
_, err := io.WriteString(f.output, "\n")
return errors.WithStack(err)
}
func (f *Formatter) mustFormat(text string) {
lines := f.splitLines(text)
if f.Prefix != "" {
f.mustWrite(f.output, f.Border)
f.mustWrite(f.output, f.Prefix)
if f.isOneQuotedLine(lines) {
f.mustWrite(f.output, "\"")
f.mustWrite(f.output, lines[0])
f.mustWrite(f.output, "\"\n")
return
}
f.mustWrite(f.output, "\"\"\n")
}
for _, line := range lines {
f.writeLine(line)
}
}
func (f *Formatter) isOneQuotedLine(lines []string) bool {
if len(lines) != 1 {
return false
}
if f.Width < 1 {
return true
}
return len(f.Border)+len(f.Prefix)+2+len(lines[0]) <= f.Width
}
func (f *Formatter) splitLines(text string) []string {
if f.Prefix == "" {
return strings.Split(text, "\n")
}
return strings.SplitAfter(f.escape(text), "\\n")
}
func (f *Formatter) escape(text string) string {
return strings.NewReplacer(
"\"", "\\\"",
"\\", "\\\\",
"\n", "\\n",
"\r", "\\r",
"\t", "\\t",
).Replace(text)
}
func (f *Formatter) len() int {
n := f.buffer.Len() + len(f.Border)
if f.Prefix != "" {
n += 2
}
return n
}
func (f *Formatter) writeLine(line string) {
if f.Width > 0 {
for _, word := range strings.SplitAfter(line, " ") {
if f.len()+len(word) > f.Width {
f.flush()
}
f.mustWrite(f.buffer, word)
}
} else {
f.mustWrite(f.buffer, line)
}
f.flush()
}
func (f *Formatter) flush() {
if f.buffer.Len() == 0 && f.Width > 0 {
return
}
if f.buffer.Len() == 0 && f.Prefix == "" {
f.mustWrite(f.output, strings.TrimRight(f.Border, " "))
f.mustWrite(f.output, "\n")
return
}
f.mustWrite(f.output, f.Border)
if f.Prefix != "" {
f.mustWrite(f.output, `"`)
}
f.mustWrite(f.output, f.buffer.String())
if f.Prefix != "" {
f.mustWrite(f.output, `"`)
}
f.mustWrite(f.output, "\n")
f.buffer.Reset()
}
func (Formatter) mustWrite(w io.Writer, s string) {
if _, err := io.WriteString(w, s); err != nil {
panic(errors.WithStack(err))
}
}