11
"github.com/rogpeppe/go-internal/fmtsort"
14
type formatter struct {
20
// Formatter makes a wrapper, f, that will format x as go source with line
21
// breaks and tabs. Object f responds to the "%v" formatting verb when both the
22
// "#" and " " (space) flags are set, for example:
24
// fmt.Sprintf("%# v", Formatter(x))
26
// If one of these two flags is not set, or any other verb is used, f will
27
// format x according to the usual rules of package fmt.
28
// In particular, if x satisfies fmt.Formatter, then x.Format will be called.
29
func Formatter(x interface{}) (f fmt.Formatter) {
30
return formatter{v: reflect.ValueOf(x), quote: true}
33
func (fo formatter) String() string {
34
return fmt.Sprint(fo.v.Interface()) // unwrap it
37
func (fo formatter) passThrough(f fmt.State, c rune) {
39
for i := 0; i < 128; i++ {
44
if w, ok := f.Width(); ok {
45
s += fmt.Sprintf("%d", w)
47
if p, ok := f.Precision(); ok {
48
s += fmt.Sprintf(".%d", p)
51
fmt.Fprintf(f, s, fo.v.Interface())
54
func (fo formatter) Format(f fmt.State, c rune) {
55
if fo.force || c == 'v' && f.Flag('#') && f.Flag(' ') {
56
w := tabwriter.NewWriter(f, 4, 4, 1, ' ', 0)
57
p := &printer{tw: w, Writer: w, visited: make(map[visit]int)}
58
p.printValue(fo.v, true, fo.quote)
72
func (p *printer) indent() *printer {
74
q.tw = tabwriter.NewWriter(p.Writer, 4, 4, 1, ' ', 0)
75
q.Writer = text.NewIndentWriter(q.tw, []byte{'\t'})
79
func (p *printer) printInline(v reflect.Value, x interface{}, showType bool) {
81
io.WriteString(p, v.Type().String())
82
fmt.Fprintf(p, "(%#v)", x)
84
fmt.Fprintf(p, "%#v", x)
88
// printValue must keep track of already-printed pointer values to avoid
95
func (p *printer) catchPanic(v reflect.Value, method string) {
96
if r := recover(); r != nil {
97
if v.Kind() == reflect.Ptr && v.IsNil() {
99
io.WriteString(p, v.Type().String())
100
io.WriteString(p, ")(nil)")
104
io.WriteString(p, v.Type().String())
105
io.WriteString(p, ")(PANIC=calling method ")
106
io.WriteString(p, strconv.Quote(method))
107
io.WriteString(p, ": ")
113
func (p *printer) printValue(v reflect.Value, showType, quote bool) {
115
io.WriteString(p, "!%v(DEPTH EXCEEDED)")
119
if v.IsValid() && v.CanInterface() {
121
if goStringer, ok := i.(fmt.GoStringer); ok {
122
defer p.catchPanic(v, "GoString")
123
io.WriteString(p, goStringer.GoString())
130
p.printInline(v, v.Bool(), showType)
131
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
132
p.printInline(v, v.Int(), showType)
133
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
134
p.printInline(v, v.Uint(), showType)
135
case reflect.Float32, reflect.Float64:
136
p.printInline(v, v.Float(), showType)
137
case reflect.Complex64, reflect.Complex128:
138
fmt.Fprintf(p, "%#v", v.Complex())
140
p.fmtString(v.String(), quote)
144
io.WriteString(p, t.String())
148
expand := !canInline(v.Type())
154
sm := fmtsort.Sort(v)
155
for i := 0; i < v.Len(); i++ {
158
pp.printValue(k, false, true)
163
showTypeInStruct := t.Elem().Kind() == reflect.Interface
164
pp.printValue(mv, showTypeInStruct, true)
166
io.WriteString(pp, ",\n")
167
} else if i < v.Len()-1 {
168
io.WriteString(pp, ", ")
179
addr := v.UnsafeAddr()
180
vis := visit{addr, t}
181
if vd, ok := p.visited[vis]; ok && vd < p.depth {
182
p.fmtString(t.String()+"{(CYCLIC REFERENCE)}", false)
183
break // don't print v again
185
p.visited[vis] = p.depth
189
io.WriteString(p, t.String())
193
expand := !canInline(v.Type())
199
for i := 0; i < v.NumField(); i++ {
200
showTypeInStruct := true
201
if f := t.Field(i); f.Name != "" {
202
io.WriteString(pp, f.Name)
207
showTypeInStruct = labelType(f.Type)
209
pp.printValue(getField(v, i), showTypeInStruct, true)
211
io.WriteString(pp, ",\n")
212
} else if i < v.NumField()-1 {
213
io.WriteString(pp, ", ")
221
case reflect.Interface:
222
switch e := v.Elem(); {
223
case e.Kind() == reflect.Invalid:
224
io.WriteString(p, "nil")
228
pp.printValue(e, showType, true)
230
io.WriteString(p, v.Type().String())
231
io.WriteString(p, "(nil)")
233
case reflect.Array, reflect.Slice:
236
io.WriteString(p, t.String())
238
if v.Kind() == reflect.Slice && v.IsNil() && showType {
239
io.WriteString(p, "(nil)")
242
if v.Kind() == reflect.Slice && v.IsNil() {
243
io.WriteString(p, "nil")
247
expand := !canInline(v.Type())
253
for i := 0; i < v.Len(); i++ {
254
showTypeInSlice := t.Elem().Kind() == reflect.Interface
255
pp.printValue(v.Index(i), showTypeInSlice, true)
257
io.WriteString(pp, ",\n")
258
} else if i < v.Len()-1 {
259
io.WriteString(pp, ", ")
270
io.WriteString(p, v.Type().String())
271
io.WriteString(p, ")(nil)")
276
pp.printValue(e, true, true)
282
io.WriteString(p, v.Type().String())
283
fmt.Fprintf(p, ")(%#v)", x)
285
fmt.Fprintf(p, "%#v", x)
288
io.WriteString(p, v.Type().String())
289
io.WriteString(p, " {...}")
290
case reflect.UnsafePointer:
291
p.printInline(v, v.Pointer(), showType)
292
case reflect.Invalid:
293
io.WriteString(p, "nil")
297
func canInline(t reflect.Type) bool {
300
return !canExpand(t.Elem())
302
for i := 0; i < t.NumField(); i++ {
303
if canExpand(t.Field(i).Type) {
308
case reflect.Interface:
310
case reflect.Array, reflect.Slice:
311
return !canExpand(t.Elem())
314
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
320
func canExpand(t reflect.Type) bool {
322
case reflect.Map, reflect.Struct,
323
reflect.Interface, reflect.Array, reflect.Slice,
330
func labelType(t reflect.Type) bool {
332
case reflect.Interface, reflect.Struct:
338
func (p *printer) fmtString(s string, quote bool) {
345
func writeByte(w io.Writer, b byte) {
349
func getField(v reflect.Value, i int) reflect.Value {
351
if val.Kind() == reflect.Interface && !val.IsNil() {