github.com/chunqian/pretty@v0.0.0-20200305075802-e57086a8d0c4/formatter.go (about) 1 package pretty 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "path/filepath" 8 "reflect" 9 "strconv" 10 "text/tabwriter" 11 12 "github.com/kr/text" 13 "github.com/pelletier/go-toml" 14 ) 15 16 var depth int64 17 18 func init() { 19 depth = 3 20 21 dir, _ := os.Executable() 22 path := filepath.Dir(dir) 23 config, err := toml.LoadFile(path + "/q.toml") 24 if err == nil { 25 logD := config.Get("LOG_DEPTH") 26 if logD == nil { 27 fmt.Printf("pretty Log Depth is %d\n", depth) 28 return 29 } 30 depth = logD.(int64) 31 fmt.Printf("pretty Log Depth is %d\n", depth) 32 return 33 } 34 35 path, _ = os.Getwd() 36 config, err = toml.LoadFile(path + "/q.toml") 37 if err == nil { 38 logD := config.Get("LOG_DEPTH") 39 if logD == nil { 40 fmt.Printf("pretty Log Depth is %d\n", depth) 41 return 42 } 43 depth = logD.(int64) 44 fmt.Printf("pretty Log Depth is %d\n", depth) 45 return 46 } 47 } 48 49 type formatter struct { 50 v reflect.Value 51 force bool 52 quote bool 53 } 54 55 // Formatter makes a wrapper, f, that will format x as go source with line 56 // breaks and tabs. Object f responds to the "%v" formatting verb when both the 57 // "#" and " " (space) flags are set, for example: 58 // 59 // fmt.Sprintf("%# v", Formatter(x)) 60 // 61 // If one of these two flags is not set, or any other verb is used, f will 62 // format x according to the usual rules of package fmt. 63 // In particular, if x satisfies fmt.Formatter, then x.Format will be called. 64 func Formatter(x interface{}) (f fmt.Formatter) { 65 return formatter{v: reflect.ValueOf(x), quote: true} 66 } 67 68 func (fo formatter) String() string { 69 return fmt.Sprint(fo.v.Interface()) // unwrap it 70 } 71 72 func (fo formatter) passThrough(f fmt.State, c rune) { 73 s := "%" 74 for i := 0; i < 128; i++ { 75 if f.Flag(i) { 76 s += string(i) 77 } 78 } 79 if w, ok := f.Width(); ok { 80 s += fmt.Sprintf("%d", w) 81 } 82 if p, ok := f.Precision(); ok { 83 s += fmt.Sprintf(".%d", p) 84 } 85 s += string(c) 86 fmt.Fprintf(f, s, fo.v.Interface()) 87 } 88 89 func (fo formatter) Format(f fmt.State, c rune) { 90 if fo.force || c == 'v' && f.Flag('#') && f.Flag(' ') { 91 w := tabwriter.NewWriter(f, 4, 4, 1, ' ', 0) 92 p := &printer{tw: w, Writer: w, visited: make(map[visit]int)} 93 p.printValue(fo.v, true, fo.quote) 94 w.Flush() 95 return 96 } 97 fo.passThrough(f, c) 98 } 99 100 type printer struct { 101 io.Writer 102 tw *tabwriter.Writer 103 visited map[visit]int 104 depth int 105 } 106 107 func (p *printer) indent() *printer { 108 q := *p 109 q.tw = tabwriter.NewWriter(p.Writer, 4, 4, 1, ' ', 0) 110 q.Writer = text.NewIndentWriter(q.tw, []byte{'\t'}) 111 return &q 112 } 113 114 func (p *printer) printInline(v reflect.Value, x interface{}, showType bool) { 115 if showType { 116 io.WriteString(p, v.Type().String()) 117 switch x.(type) { 118 case int64, uint64: 119 fmt.Fprintf(p, "(%#d)", x) 120 case float64: 121 fmt.Fprintf(p, "(%#.4f)", x) 122 default: 123 fmt.Fprintf(p, "(%#v)", x) 124 } 125 // fmt.Fprintf(p, "(%#v)", x) 126 } else { 127 switch x.(type) { 128 case int64, uint64: 129 fmt.Fprintf(p, "%#d", x) 130 case float64: 131 fmt.Fprintf(p, "%#.4f", x) 132 default: 133 fmt.Fprintf(p, "%#v", x) 134 } 135 // fmt.Fprintf(p, "%#v", x) 136 } 137 } 138 139 // printValue must keep track of already-printed pointer values to avoid 140 // infinite recursion. 141 type visit struct { 142 v uintptr 143 typ reflect.Type 144 } 145 146 func (p *printer) printValue(v reflect.Value, showType, quote bool) { 147 if p.depth > 10 { 148 io.WriteString(p, "!%v(DEPTH EXCEEDED)") 149 return 150 } 151 152 switch v.Kind() { 153 case reflect.Bool: 154 p.printInline(v, v.Bool(), showType) 155 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 156 p.printInline(v, v.Int(), showType) 157 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 158 p.printInline(v, v.Uint(), showType) 159 case reflect.Float32, reflect.Float64: 160 p.printInline(v, v.Float(), showType) 161 case reflect.Complex64, reflect.Complex128: 162 fmt.Fprintf(p, "%#v", v.Complex()) 163 case reflect.String: 164 p.fmtString(v.String(), quote) 165 case reflect.Map: 166 t := v.Type() 167 if showType { 168 io.WriteString(p, t.String()) 169 } 170 writeByte(p, '{') 171 if nonzero(v) { 172 expand := !canInline(v.Type()) 173 pp := p 174 if expand { 175 writeByte(p, '\n') 176 pp = p.indent() 177 } 178 keys := v.MapKeys() 179 for i := 0; i < v.Len(); i++ { 180 k := keys[i] 181 mv := v.MapIndex(k) 182 pp.printValue(k, false, true) 183 writeByte(pp, ':') 184 if expand { 185 writeByte(pp, '\t') 186 } 187 showTypeInStruct := t.Elem().Kind() == reflect.Interface 188 pp.printValue(mv, showTypeInStruct, true) 189 if expand { 190 io.WriteString(pp, ",\n") 191 } else if i < v.Len()-1 { 192 io.WriteString(pp, ", ") 193 } 194 } 195 if expand { 196 pp.tw.Flush() 197 } 198 } 199 writeByte(p, '}') 200 case reflect.Struct: 201 t := v.Type() 202 if v.CanAddr() { 203 addr := v.UnsafeAddr() 204 vis := visit{addr, t} 205 if vd, ok := p.visited[vis]; ok && vd < p.depth { 206 p.fmtString(t.String()+"{(CYCLIC REFERENCE)}", false) 207 break // don't print v again 208 } 209 p.visited[vis] = p.depth 210 211 if p.depth > int(depth) { 212 writeByte(p, '(') 213 writeByte(p, '*') 214 io.WriteString(p, v.Type().String()) 215 fmt.Fprintf(p, ")(%#v)", addr) 216 break 217 } 218 } 219 220 if showType { 221 io.WriteString(p, t.String()) 222 } 223 writeByte(p, '{') 224 if nonzero(v) { 225 expand := !canInline(v.Type()) 226 pp := p 227 if expand { 228 writeByte(p, '\n') 229 pp = p.indent() 230 } 231 for i := 0; i < v.NumField(); i++ { 232 showTypeInStruct := true 233 if f := t.Field(i); f.Name != "" { 234 io.WriteString(pp, f.Name) 235 writeByte(pp, ':') 236 if expand { 237 writeByte(pp, '\t') 238 } 239 showTypeInStruct = labelType(f.Type) 240 } 241 pp.printValue(getField(v, i), showTypeInStruct, true) 242 if expand { 243 io.WriteString(pp, ",\n") 244 } else if i < v.NumField()-1 { 245 io.WriteString(pp, ", ") 246 } 247 } 248 if expand { 249 pp.tw.Flush() 250 } 251 } 252 writeByte(p, '}') 253 case reflect.Interface: 254 switch e := v.Elem(); { 255 case e.Kind() == reflect.Invalid: 256 io.WriteString(p, "nil") 257 case e.IsValid(): 258 pp := *p 259 pp.depth++ 260 pp.printValue(e, showType, true) 261 default: 262 io.WriteString(p, v.Type().String()) 263 io.WriteString(p, "(nil)") 264 } 265 case reflect.Array, reflect.Slice: 266 t := v.Type() 267 if showType { 268 io.WriteString(p, t.String()) 269 } 270 if v.Kind() == reflect.Slice && v.IsNil() && showType { 271 io.WriteString(p, "(nil)") 272 break 273 } 274 if v.Kind() == reflect.Slice && v.IsNil() { 275 io.WriteString(p, "nil") 276 break 277 } 278 writeByte(p, '{') 279 expand := !canInline(v.Type()) 280 pp := p 281 if expand { 282 writeByte(p, '\n') 283 pp = p.indent() 284 } 285 for i := 0; i < v.Len(); i++ { 286 showTypeInSlice := t.Elem().Kind() == reflect.Interface 287 pp.printValue(v.Index(i), showTypeInSlice, true) 288 if expand { 289 io.WriteString(pp, ",\n") 290 } else if i < v.Len()-1 { 291 io.WriteString(pp, ", ") 292 } 293 } 294 if expand { 295 pp.tw.Flush() 296 } 297 writeByte(p, '}') 298 case reflect.Ptr: 299 e := v.Elem() 300 if !e.IsValid() { 301 writeByte(p, '(') 302 io.WriteString(p, v.Type().String()) 303 io.WriteString(p, ")(nil)") 304 } else { 305 pp := *p 306 pp.depth++ 307 308 switch e.Kind() { 309 case reflect.Struct: 310 pp.printValue(e, true, true) 311 default: 312 writeByte(pp, '&') 313 pp.printValue(e, true, true) 314 } 315 // writeByte(pp, '&') 316 // pp.printValue(e, true, true) 317 } 318 case reflect.Chan: 319 x := v.Pointer() 320 if showType { 321 writeByte(p, '(') 322 io.WriteString(p, v.Type().String()) 323 fmt.Fprintf(p, ")(%#v)", x) 324 } else { 325 fmt.Fprintf(p, "%#v", x) 326 } 327 case reflect.Func: 328 io.WriteString(p, v.Type().String()) 329 io.WriteString(p, " {...}") 330 case reflect.UnsafePointer: 331 p.printInline(v, v.Pointer(), showType) 332 case reflect.Invalid: 333 io.WriteString(p, "nil") 334 } 335 } 336 337 func canInline(t reflect.Type) bool { 338 switch t.Kind() { 339 case reflect.Map: 340 return !canExpand(t.Elem()) 341 case reflect.Struct: 342 for i := 0; i < t.NumField(); i++ { 343 if canExpand(t.Field(i).Type) { 344 return false 345 } 346 } 347 return true 348 case reflect.Interface: 349 return false 350 case reflect.Array, reflect.Slice: 351 return !canExpand(t.Elem()) 352 case reflect.Ptr: 353 return false 354 case reflect.Chan, reflect.Func, reflect.UnsafePointer: 355 return false 356 } 357 return true 358 } 359 360 func canExpand(t reflect.Type) bool { 361 switch t.Kind() { 362 case reflect.Map, reflect.Struct, 363 reflect.Interface, reflect.Array, reflect.Slice, 364 reflect.Ptr: 365 return true 366 } 367 return false 368 } 369 370 func labelType(t reflect.Type) bool { 371 switch t.Kind() { 372 case reflect.Interface, reflect.Struct: 373 return true 374 } 375 return false 376 } 377 378 func (p *printer) fmtString(s string, quote bool) { 379 if quote { 380 s = strconv.Quote(s) 381 } 382 io.WriteString(p, s) 383 } 384 385 func writeByte(w io.Writer, b byte) { 386 w.Write([]byte{b}) 387 } 388 389 func getField(v reflect.Value, i int) reflect.Value { 390 val := v.Field(i) 391 if val.Kind() == reflect.Interface && !val.IsNil() { 392 val = val.Elem() 393 } 394 return val 395 }