github.com/kr/pretty@v0.3.1/formatter.go (about) 1 package pretty 2 3 import ( 4 "fmt" 5 "io" 6 "reflect" 7 "strconv" 8 "text/tabwriter" 9 10 "github.com/kr/text" 11 "github.com/rogpeppe/go-internal/fmtsort" 12 ) 13 14 type formatter struct { 15 v reflect.Value 16 force bool 17 quote bool 18 } 19 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: 23 // 24 // fmt.Sprintf("%# v", Formatter(x)) 25 // 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} 31 } 32 33 func (fo formatter) String() string { 34 return fmt.Sprint(fo.v.Interface()) // unwrap it 35 } 36 37 func (fo formatter) passThrough(f fmt.State, c rune) { 38 s := "%" 39 for i := 0; i < 128; i++ { 40 if f.Flag(i) { 41 s += string(rune(i)) 42 } 43 } 44 if w, ok := f.Width(); ok { 45 s += fmt.Sprintf("%d", w) 46 } 47 if p, ok := f.Precision(); ok { 48 s += fmt.Sprintf(".%d", p) 49 } 50 s += string(c) 51 fmt.Fprintf(f, s, fo.v.Interface()) 52 } 53 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) 59 w.Flush() 60 return 61 } 62 fo.passThrough(f, c) 63 } 64 65 type printer struct { 66 io.Writer 67 tw *tabwriter.Writer 68 visited map[visit]int 69 depth int 70 } 71 72 func (p *printer) indent() *printer { 73 q := *p 74 q.tw = tabwriter.NewWriter(p.Writer, 4, 4, 1, ' ', 0) 75 q.Writer = text.NewIndentWriter(q.tw, []byte{'\t'}) 76 return &q 77 } 78 79 func (p *printer) printInline(v reflect.Value, x interface{}, showType bool) { 80 if showType { 81 io.WriteString(p, v.Type().String()) 82 fmt.Fprintf(p, "(%#v)", x) 83 } else { 84 fmt.Fprintf(p, "%#v", x) 85 } 86 } 87 88 // printValue must keep track of already-printed pointer values to avoid 89 // infinite recursion. 90 type visit struct { 91 v uintptr 92 typ reflect.Type 93 } 94 95 func (p *printer) catchPanic(v reflect.Value, method string) { 96 if r := recover(); r != nil { 97 if v.Kind() == reflect.Ptr && v.IsNil() { 98 writeByte(p, '(') 99 io.WriteString(p, v.Type().String()) 100 io.WriteString(p, ")(nil)") 101 return 102 } 103 writeByte(p, '(') 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, ": ") 108 fmt.Fprint(p, r) 109 writeByte(p, ')') 110 } 111 } 112 113 func (p *printer) printValue(v reflect.Value, showType, quote bool) { 114 if p.depth > 10 { 115 io.WriteString(p, "!%v(DEPTH EXCEEDED)") 116 return 117 } 118 119 if v.IsValid() && v.CanInterface() { 120 i := v.Interface() 121 if goStringer, ok := i.(fmt.GoStringer); ok { 122 defer p.catchPanic(v, "GoString") 123 io.WriteString(p, goStringer.GoString()) 124 return 125 } 126 } 127 128 switch v.Kind() { 129 case reflect.Bool: 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()) 139 case reflect.String: 140 p.fmtString(v.String(), quote) 141 case reflect.Map: 142 t := v.Type() 143 if showType { 144 io.WriteString(p, t.String()) 145 } 146 writeByte(p, '{') 147 if nonzero(v) { 148 expand := !canInline(v.Type()) 149 pp := p 150 if expand { 151 writeByte(p, '\n') 152 pp = p.indent() 153 } 154 sm := fmtsort.Sort(v) 155 for i := 0; i < v.Len(); i++ { 156 k := sm.Key[i] 157 mv := sm.Value[i] 158 pp.printValue(k, false, true) 159 writeByte(pp, ':') 160 if expand { 161 writeByte(pp, '\t') 162 } 163 showTypeInStruct := t.Elem().Kind() == reflect.Interface 164 pp.printValue(mv, showTypeInStruct, true) 165 if expand { 166 io.WriteString(pp, ",\n") 167 } else if i < v.Len()-1 { 168 io.WriteString(pp, ", ") 169 } 170 } 171 if expand { 172 pp.tw.Flush() 173 } 174 } 175 writeByte(p, '}') 176 case reflect.Struct: 177 t := v.Type() 178 if v.CanAddr() { 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 184 } 185 p.visited[vis] = p.depth 186 } 187 188 if showType { 189 io.WriteString(p, t.String()) 190 } 191 writeByte(p, '{') 192 if nonzero(v) { 193 expand := !canInline(v.Type()) 194 pp := p 195 if expand { 196 writeByte(p, '\n') 197 pp = p.indent() 198 } 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) 203 writeByte(pp, ':') 204 if expand { 205 writeByte(pp, '\t') 206 } 207 showTypeInStruct = labelType(f.Type) 208 } 209 pp.printValue(getField(v, i), showTypeInStruct, true) 210 if expand { 211 io.WriteString(pp, ",\n") 212 } else if i < v.NumField()-1 { 213 io.WriteString(pp, ", ") 214 } 215 } 216 if expand { 217 pp.tw.Flush() 218 } 219 } 220 writeByte(p, '}') 221 case reflect.Interface: 222 switch e := v.Elem(); { 223 case e.Kind() == reflect.Invalid: 224 io.WriteString(p, "nil") 225 case e.IsValid(): 226 pp := *p 227 pp.depth++ 228 pp.printValue(e, showType, true) 229 default: 230 io.WriteString(p, v.Type().String()) 231 io.WriteString(p, "(nil)") 232 } 233 case reflect.Array, reflect.Slice: 234 t := v.Type() 235 if showType { 236 io.WriteString(p, t.String()) 237 } 238 if v.Kind() == reflect.Slice && v.IsNil() && showType { 239 io.WriteString(p, "(nil)") 240 break 241 } 242 if v.Kind() == reflect.Slice && v.IsNil() { 243 io.WriteString(p, "nil") 244 break 245 } 246 writeByte(p, '{') 247 expand := !canInline(v.Type()) 248 pp := p 249 if expand { 250 writeByte(p, '\n') 251 pp = p.indent() 252 } 253 for i := 0; i < v.Len(); i++ { 254 showTypeInSlice := t.Elem().Kind() == reflect.Interface 255 pp.printValue(v.Index(i), showTypeInSlice, true) 256 if expand { 257 io.WriteString(pp, ",\n") 258 } else if i < v.Len()-1 { 259 io.WriteString(pp, ", ") 260 } 261 } 262 if expand { 263 pp.tw.Flush() 264 } 265 writeByte(p, '}') 266 case reflect.Ptr: 267 e := v.Elem() 268 if !e.IsValid() { 269 writeByte(p, '(') 270 io.WriteString(p, v.Type().String()) 271 io.WriteString(p, ")(nil)") 272 } else { 273 pp := *p 274 pp.depth++ 275 writeByte(pp, '&') 276 pp.printValue(e, true, true) 277 } 278 case reflect.Chan: 279 x := v.Pointer() 280 if showType { 281 writeByte(p, '(') 282 io.WriteString(p, v.Type().String()) 283 fmt.Fprintf(p, ")(%#v)", x) 284 } else { 285 fmt.Fprintf(p, "%#v", x) 286 } 287 case reflect.Func: 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") 294 } 295 } 296 297 func canInline(t reflect.Type) bool { 298 switch t.Kind() { 299 case reflect.Map: 300 return !canExpand(t.Elem()) 301 case reflect.Struct: 302 for i := 0; i < t.NumField(); i++ { 303 if canExpand(t.Field(i).Type) { 304 return false 305 } 306 } 307 return true 308 case reflect.Interface: 309 return false 310 case reflect.Array, reflect.Slice: 311 return !canExpand(t.Elem()) 312 case reflect.Ptr: 313 return false 314 case reflect.Chan, reflect.Func, reflect.UnsafePointer: 315 return false 316 } 317 return true 318 } 319 320 func canExpand(t reflect.Type) bool { 321 switch t.Kind() { 322 case reflect.Map, reflect.Struct, 323 reflect.Interface, reflect.Array, reflect.Slice, 324 reflect.Ptr: 325 return true 326 } 327 return false 328 } 329 330 func labelType(t reflect.Type) bool { 331 switch t.Kind() { 332 case reflect.Interface, reflect.Struct: 333 return true 334 } 335 return false 336 } 337 338 func (p *printer) fmtString(s string, quote bool) { 339 if quote { 340 s = strconv.Quote(s) 341 } 342 io.WriteString(p, s) 343 } 344 345 func writeByte(w io.Writer, b byte) { 346 w.Write([]byte{b}) 347 } 348 349 func getField(v reflect.Value, i int) reflect.Value { 350 val := v.Field(i) 351 if val.Kind() == reflect.Interface && !val.IsNil() { 352 val = val.Elem() 353 } 354 return val 355 }