1
2
3
4
5 package xerrors
6
7 import (
8 "bytes"
9 "fmt"
10 "io"
11 "reflect"
12 "strconv"
13 )
14
15
16
17 func FormatError(f Formatter, s fmt.State, verb rune) {
18
19
20
21
22
23
24
25
26 var (
27 sep = " "
28 p = &state{State: s}
29 direct = true
30 )
31
32 var err error = f
33
34 switch verb {
35
36
37
38 case 'v':
39 if s.Flag('#') {
40 if stringer, ok := err.(fmt.GoStringer); ok {
41 io.WriteString(&p.buf, stringer.GoString())
42 goto exit
43 }
44
45 } else if s.Flag('+') {
46 p.printDetail = true
47 sep = "\n - "
48 }
49 case 's':
50 case 'q', 'x', 'X':
51
52
53
54 direct = false
55
56 default:
57 p.buf.WriteString("%!")
58 p.buf.WriteRune(verb)
59 p.buf.WriteByte('(')
60 switch {
61 case err != nil:
62 p.buf.WriteString(reflect.TypeOf(f).String())
63 default:
64 p.buf.WriteString("<nil>")
65 }
66 p.buf.WriteByte(')')
67 io.Copy(s, &p.buf)
68 return
69 }
70
71 loop:
72 for {
73 switch v := err.(type) {
74 case Formatter:
75 err = v.FormatError((*printer)(p))
76 case fmt.Formatter:
77 v.Format(p, 'v')
78 break loop
79 default:
80 io.WriteString(&p.buf, v.Error())
81 break loop
82 }
83 if err == nil {
84 break
85 }
86 if p.needColon || !p.printDetail {
87 p.buf.WriteByte(':')
88 p.needColon = false
89 }
90 p.buf.WriteString(sep)
91 p.inDetail = false
92 p.needNewline = false
93 }
94
95 exit:
96 width, okW := s.Width()
97 prec, okP := s.Precision()
98
99 if !direct || (okW && width > 0) || okP {
100
101 format := []byte{'%'}
102 if s.Flag('-') {
103 format = append(format, '-')
104 }
105 if s.Flag('+') {
106 format = append(format, '+')
107 }
108 if s.Flag(' ') {
109 format = append(format, ' ')
110 }
111 if okW {
112 format = strconv.AppendInt(format, int64(width), 10)
113 }
114 if okP {
115 format = append(format, '.')
116 format = strconv.AppendInt(format, int64(prec), 10)
117 }
118 format = append(format, string(verb)...)
119 fmt.Fprintf(s, string(format), p.buf.String())
120 } else {
121 io.Copy(s, &p.buf)
122 }
123 }
124
125 var detailSep = []byte("\n ")
126
127
128 type state struct {
129 fmt.State
130 buf bytes.Buffer
131
132 printDetail bool
133 inDetail bool
134 needColon bool
135 needNewline bool
136 }
137
138 func (s *state) Write(b []byte) (n int, err error) {
139 if s.printDetail {
140 if len(b) == 0 {
141 return 0, nil
142 }
143 if s.inDetail && s.needColon {
144 s.needNewline = true
145 if b[0] == '\n' {
146 b = b[1:]
147 }
148 }
149 k := 0
150 for i, c := range b {
151 if s.needNewline {
152 if s.inDetail && s.needColon {
153 s.buf.WriteByte(':')
154 s.needColon = false
155 }
156 s.buf.Write(detailSep)
157 s.needNewline = false
158 }
159 if c == '\n' {
160 s.buf.Write(b[k:i])
161 k = i + 1
162 s.needNewline = true
163 }
164 }
165 s.buf.Write(b[k:])
166 if !s.inDetail {
167 s.needColon = true
168 }
169 } else if !s.inDetail {
170 s.buf.Write(b)
171 }
172 return len(b), nil
173 }
174
175
176 type printer state
177
178 func (s *printer) Print(args ...interface{}) {
179 if !s.inDetail || s.printDetail {
180 fmt.Fprint((*state)(s), args...)
181 }
182 }
183
184 func (s *printer) Printf(format string, args ...interface{}) {
185 if !s.inDetail || s.printDetail {
186 fmt.Fprintf((*state)(s), format, args...)
187 }
188 }
189
190 func (s *printer) Detail() bool {
191 s.inDetail = true
192 return s.printDetail
193 }
194
View as plain text