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  }