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