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  }