fixed dependencies
This commit is contained in:
526
vendor/github.com/k0kubun/pp/v3/printer.go
generated
vendored
Normal file
526
vendor/github.com/k0kubun/pp/v3/printer.go
generated
vendored
Normal file
@@ -0,0 +1,526 @@
|
||||
// printer.go: The actual pretty print implementation. Everything in this file should be private.
|
||||
package pp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message"
|
||||
)
|
||||
|
||||
const (
|
||||
indentWidth = 2
|
||||
)
|
||||
|
||||
func (pp *PrettyPrinter) format(object interface{}) string {
|
||||
return newPrinter(object, &pp.currentScheme, pp.maxDepth, pp.coloringEnabled, pp.decimalUint, pp.exportedOnly, pp.thousandsSeparator).String()
|
||||
}
|
||||
|
||||
func newPrinter(object interface{}, currentScheme *ColorScheme, maxDepth int, coloringEnabled bool, decimalUint bool, exportedOnly bool, thousandsSeparator bool) *printer {
|
||||
buffer := bytes.NewBufferString("")
|
||||
tw := new(tabwriter.Writer)
|
||||
tw.Init(buffer, indentWidth, 0, 1, ' ', 0)
|
||||
|
||||
printer := &printer{
|
||||
Buffer: buffer,
|
||||
tw: tw,
|
||||
depth: 0,
|
||||
maxDepth: maxDepth,
|
||||
value: reflect.ValueOf(object),
|
||||
visited: map[uintptr]bool{},
|
||||
currentScheme: currentScheme,
|
||||
coloringEnabled: coloringEnabled,
|
||||
decimalUint: decimalUint,
|
||||
exportedOnly: exportedOnly,
|
||||
thousandsSeparator: thousandsSeparator,
|
||||
}
|
||||
|
||||
if thousandsSeparator {
|
||||
printer.localizedPrinter = message.NewPrinter(language.English)
|
||||
}
|
||||
|
||||
return printer
|
||||
}
|
||||
|
||||
type printer struct {
|
||||
*bytes.Buffer
|
||||
tw *tabwriter.Writer
|
||||
depth int
|
||||
maxDepth int
|
||||
value reflect.Value
|
||||
visited map[uintptr]bool
|
||||
currentScheme *ColorScheme
|
||||
coloringEnabled bool
|
||||
decimalUint bool
|
||||
exportedOnly bool
|
||||
thousandsSeparator bool
|
||||
localizedPrinter *message.Printer
|
||||
}
|
||||
|
||||
func (p *printer) String() string {
|
||||
switch p.value.Kind() {
|
||||
case reflect.Bool:
|
||||
p.colorPrint(p.raw(), p.currentScheme.Bool)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Uintptr, reflect.Complex64, reflect.Complex128:
|
||||
p.colorPrint(p.raw(), p.currentScheme.Integer)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
p.colorPrint(p.raw(), p.currentScheme.Float)
|
||||
case reflect.String:
|
||||
p.printString()
|
||||
case reflect.Map:
|
||||
p.printMap()
|
||||
case reflect.Struct:
|
||||
p.printStruct()
|
||||
case reflect.Array, reflect.Slice:
|
||||
p.printSlice()
|
||||
case reflect.Chan:
|
||||
p.printf("(%s)(%s)", p.typeString(), p.pointerAddr())
|
||||
case reflect.Interface:
|
||||
p.printInterface()
|
||||
case reflect.Ptr:
|
||||
p.printPtr()
|
||||
case reflect.Func:
|
||||
p.printf("%s {...}", p.typeString())
|
||||
case reflect.UnsafePointer:
|
||||
p.printf("%s(%s)", p.typeString(), p.pointerAddr())
|
||||
case reflect.Invalid:
|
||||
p.print(p.nil())
|
||||
default:
|
||||
p.print(p.raw())
|
||||
}
|
||||
|
||||
p.tw.Flush()
|
||||
return p.Buffer.String()
|
||||
}
|
||||
|
||||
func (p *printer) print(text string) {
|
||||
fmt.Fprint(p.tw, text)
|
||||
}
|
||||
|
||||
func (p *printer) printf(format string, args ...interface{}) {
|
||||
text := fmt.Sprintf(format, args...)
|
||||
p.print(text)
|
||||
}
|
||||
|
||||
func (p *printer) println(text string) {
|
||||
p.print(text + "\n")
|
||||
}
|
||||
|
||||
func (p *printer) indentPrint(text string) {
|
||||
p.print(p.indent() + text)
|
||||
}
|
||||
|
||||
func (p *printer) indentPrintf(format string, args ...interface{}) {
|
||||
text := fmt.Sprintf(format, args...)
|
||||
p.indentPrint(text)
|
||||
}
|
||||
|
||||
func (p *printer) colorPrint(text string, color uint16) {
|
||||
p.print(p.colorize(text, color))
|
||||
}
|
||||
|
||||
func (p *printer) printString() {
|
||||
quoted := strconv.Quote(p.value.String())
|
||||
quoted = quoted[1 : len(quoted)-1]
|
||||
|
||||
p.colorPrint(`"`, p.currentScheme.StringQuotation)
|
||||
for len(quoted) > 0 {
|
||||
pos := strings.IndexByte(quoted, '\\')
|
||||
if pos == -1 {
|
||||
p.colorPrint(quoted, p.currentScheme.String)
|
||||
break
|
||||
}
|
||||
if pos != 0 {
|
||||
p.colorPrint(quoted[0:pos], p.currentScheme.String)
|
||||
}
|
||||
|
||||
n := 1
|
||||
switch quoted[pos+1] {
|
||||
case 'x': // "\x00"
|
||||
n = 3
|
||||
case 'u': // "\u0000"
|
||||
n = 5
|
||||
case 'U': // "\U00000000"
|
||||
n = 9
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': // "\000"
|
||||
n = 3
|
||||
}
|
||||
p.colorPrint(quoted[pos:pos+n+1], p.currentScheme.EscapedChar)
|
||||
quoted = quoted[pos+n+1:]
|
||||
}
|
||||
p.colorPrint(`"`, p.currentScheme.StringQuotation)
|
||||
}
|
||||
|
||||
func (p *printer) printMap() {
|
||||
if p.value.Len() == 0 {
|
||||
p.printf("%s{}", p.typeString())
|
||||
return
|
||||
}
|
||||
|
||||
if p.visited[p.value.Pointer()] {
|
||||
p.printf("%s{...}", p.typeString())
|
||||
return
|
||||
}
|
||||
p.visited[p.value.Pointer()] = true
|
||||
|
||||
if PrintMapTypes {
|
||||
p.printf("%s{\n", p.typeString())
|
||||
} else {
|
||||
p.println("{")
|
||||
}
|
||||
p.indented(func() {
|
||||
value := sortMap(p.value)
|
||||
for i := 0; i < value.Len(); i++ {
|
||||
p.indentPrintf("%s:\t%s,\n", p.format(value.keys[i]), p.format(value.values[i]))
|
||||
}
|
||||
})
|
||||
p.indentPrint("}")
|
||||
}
|
||||
|
||||
func (p *printer) printStruct() {
|
||||
if p.value.CanInterface() {
|
||||
if p.value.Type().String() == "time.Time" && p.value.Type().PkgPath() == "time" {
|
||||
p.printTime()
|
||||
return
|
||||
} else if p.value.Type().String() == "big.Int" {
|
||||
bigInt := p.value.Interface().(big.Int)
|
||||
p.print(p.colorize(bigInt.String(), p.currentScheme.Integer))
|
||||
return
|
||||
} else if p.value.Type().String() == "big.Float" {
|
||||
bigFloat := p.value.Interface().(big.Float)
|
||||
p.print(p.colorize(bigFloat.String(), p.currentScheme.Float))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var fields []int
|
||||
for i := 0; i < p.value.NumField(); i++ {
|
||||
field := p.value.Type().Field(i)
|
||||
value := p.value.Field(i)
|
||||
// ignore unexported if needed
|
||||
if p.exportedOnly && field.PkgPath != "" {
|
||||
continue
|
||||
}
|
||||
// ignore fields if zero value, or explicitly set
|
||||
if tag := field.Tag.Get("pp"); tag != "" {
|
||||
parts := strings.Split(tag, ",")
|
||||
if len(parts) == 2 && parts[1] == "omitempty" && valueIsZero(value) {
|
||||
continue
|
||||
}
|
||||
if parts[0] == "-" {
|
||||
continue
|
||||
}
|
||||
}
|
||||
fields = append(fields, i)
|
||||
}
|
||||
|
||||
if len(fields) == 0 {
|
||||
p.print(p.typeString() + "{}")
|
||||
return
|
||||
}
|
||||
|
||||
p.println(p.typeString() + "{")
|
||||
p.indented(func() {
|
||||
for _, i := range fields {
|
||||
field := p.value.Type().Field(i)
|
||||
value := p.value.Field(i)
|
||||
|
||||
fieldName := field.Name
|
||||
if tag := field.Tag.Get("pp"); tag != "" {
|
||||
tagName := strings.Split(tag, ",")
|
||||
if tagName[0] != "" {
|
||||
fieldName = tagName[0]
|
||||
}
|
||||
}
|
||||
|
||||
colorizedFieldName := p.colorize(fieldName, p.currentScheme.FieldName)
|
||||
p.indentPrintf("%s:\t%s,\n", colorizedFieldName, p.format(value))
|
||||
}
|
||||
})
|
||||
p.indentPrint("}")
|
||||
}
|
||||
|
||||
func (p *printer) printTime() {
|
||||
tm := p.value.Interface().(time.Time)
|
||||
p.printf(
|
||||
"%s-%s-%s %s:%s:%s %s",
|
||||
p.colorize(strconv.Itoa(tm.Year()), p.currentScheme.Time),
|
||||
p.colorize(fmt.Sprintf("%02d", tm.Month()), p.currentScheme.Time),
|
||||
p.colorize(fmt.Sprintf("%02d", tm.Day()), p.currentScheme.Time),
|
||||
p.colorize(fmt.Sprintf("%02d", tm.Hour()), p.currentScheme.Time),
|
||||
p.colorize(fmt.Sprintf("%02d", tm.Minute()), p.currentScheme.Time),
|
||||
p.colorize(fmt.Sprintf("%02d", tm.Second()), p.currentScheme.Time),
|
||||
p.colorize(tm.Location().String(), p.currentScheme.Time),
|
||||
)
|
||||
}
|
||||
|
||||
func (p *printer) printSlice() {
|
||||
if p.value.Kind() == reflect.Slice && p.value.IsNil() {
|
||||
p.printf("%s(%s)", p.typeString(), p.nil())
|
||||
return
|
||||
}
|
||||
if p.value.Len() == 0 {
|
||||
p.printf("%s{}", p.typeString())
|
||||
return
|
||||
}
|
||||
|
||||
if p.value.Kind() == reflect.Slice {
|
||||
if p.visited[p.value.Pointer()] {
|
||||
// Stop travarsing cyclic reference
|
||||
p.printf("%s{...}", p.typeString())
|
||||
return
|
||||
}
|
||||
p.visited[p.value.Pointer()] = true
|
||||
}
|
||||
|
||||
// Fold a large buffer
|
||||
if p.value.Len() > BufferFoldThreshold {
|
||||
p.printf("%s{...}", p.typeString())
|
||||
return
|
||||
}
|
||||
|
||||
p.println(p.typeString() + "{")
|
||||
p.indented(func() {
|
||||
groupsize := 0
|
||||
switch p.value.Type().Elem().Kind() {
|
||||
case reflect.Uint8:
|
||||
groupsize = 16
|
||||
case reflect.Uint16:
|
||||
groupsize = 8
|
||||
case reflect.Uint32:
|
||||
groupsize = 8
|
||||
case reflect.Uint64:
|
||||
groupsize = 4
|
||||
}
|
||||
|
||||
if groupsize > 0 {
|
||||
for i := 0; i < p.value.Len(); i++ {
|
||||
// indent for new group
|
||||
if i%groupsize == 0 {
|
||||
p.print(p.indent())
|
||||
}
|
||||
// slice element
|
||||
p.printf("%s,", p.format(p.value.Index(i)))
|
||||
// space or newline
|
||||
if (i+1)%groupsize == 0 || i+1 == p.value.Len() {
|
||||
p.print("\n")
|
||||
} else {
|
||||
p.print(" ")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < p.value.Len(); i++ {
|
||||
p.indentPrintf("%s,\n", p.format(p.value.Index(i)))
|
||||
}
|
||||
}
|
||||
})
|
||||
p.indentPrint("}")
|
||||
}
|
||||
|
||||
func (p *printer) printInterface() {
|
||||
e := p.value.Elem()
|
||||
if e.Kind() == reflect.Invalid {
|
||||
p.print(p.nil())
|
||||
} else if e.IsValid() {
|
||||
p.print(p.format(e))
|
||||
} else {
|
||||
p.printf("%s(%s)", p.typeString(), p.nil())
|
||||
}
|
||||
}
|
||||
|
||||
func (p *printer) printPtr() {
|
||||
if p.visited[p.value.Pointer()] {
|
||||
p.printf("&%s{...}", p.elemTypeString())
|
||||
return
|
||||
}
|
||||
if p.value.Pointer() != 0 {
|
||||
p.visited[p.value.Pointer()] = true
|
||||
}
|
||||
|
||||
if p.value.Elem().IsValid() {
|
||||
p.printf("&%s", p.format(p.value.Elem()))
|
||||
} else {
|
||||
p.printf("(%s)(%s)", p.typeString(), p.nil())
|
||||
}
|
||||
}
|
||||
|
||||
func (p *printer) pointerAddr() string {
|
||||
return p.colorize(fmt.Sprintf("%#v", p.value.Pointer()), p.currentScheme.PointerAdress)
|
||||
}
|
||||
|
||||
func (p *printer) typeString() string {
|
||||
return p.colorizeType(p.value.Type().String())
|
||||
}
|
||||
|
||||
func (p *printer) elemTypeString() string {
|
||||
return p.colorizeType(p.value.Elem().Type().String())
|
||||
}
|
||||
|
||||
func (p *printer) colorizeType(t string) string {
|
||||
prefix := ""
|
||||
|
||||
if p.matchRegexp(t, `^\[\].+$`) {
|
||||
prefix = "[]"
|
||||
t = t[2:]
|
||||
}
|
||||
|
||||
if p.matchRegexp(t, `^\[\d+\].+$`) {
|
||||
num := regexp.MustCompile(`\d+`).FindString(t)
|
||||
prefix = fmt.Sprintf("[%s]", p.colorize(num, p.currentScheme.ObjectLength))
|
||||
t = t[2+len(num):]
|
||||
}
|
||||
|
||||
if p.matchRegexp(t, `^[^\.]+\.[^\.]+$`) {
|
||||
ts := strings.Split(t, ".")
|
||||
t = fmt.Sprintf("%s.%s", ts[0], p.colorize(ts[1], p.currentScheme.StructName))
|
||||
} else {
|
||||
t = p.colorize(t, p.currentScheme.StructName)
|
||||
}
|
||||
return prefix + t
|
||||
}
|
||||
|
||||
func (p *printer) matchRegexp(text, exp string) bool {
|
||||
return regexp.MustCompile(exp).MatchString(text)
|
||||
}
|
||||
|
||||
func (p *printer) indented(proc func()) {
|
||||
p.depth++
|
||||
if p.maxDepth == -1 || p.depth <= p.maxDepth {
|
||||
proc()
|
||||
}
|
||||
p.depth--
|
||||
}
|
||||
|
||||
func (p *printer) fmtOrLocalizedSprintf(format string, a ...interface{}) string {
|
||||
if p.localizedPrinter == nil {
|
||||
return fmt.Sprintf(format, a...)
|
||||
}
|
||||
|
||||
return p.localizedPrinter.Sprintf(format, a...)
|
||||
}
|
||||
|
||||
func (p *printer) raw() string {
|
||||
// Some value causes panic when Interface() is called.
|
||||
switch p.value.Kind() {
|
||||
case reflect.Bool:
|
||||
return fmt.Sprintf("%#v", p.value.Bool())
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return p.fmtOrLocalizedSprintf("%v", p.value.Int())
|
||||
case reflect.Uint, reflect.Uintptr:
|
||||
if p.decimalUint {
|
||||
return p.fmtOrLocalizedSprintf("%d", p.value.Uint())
|
||||
} else {
|
||||
return fmt.Sprintf("%#v", p.value.Uint())
|
||||
}
|
||||
case reflect.Uint8:
|
||||
if p.decimalUint {
|
||||
return fmt.Sprintf("%d", p.value.Uint())
|
||||
} else {
|
||||
return fmt.Sprintf("0x%02x", p.value.Uint())
|
||||
}
|
||||
case reflect.Uint16:
|
||||
if p.decimalUint {
|
||||
return p.fmtOrLocalizedSprintf("%d", p.value.Uint())
|
||||
} else {
|
||||
return fmt.Sprintf("0x%04x", p.value.Uint())
|
||||
}
|
||||
case reflect.Uint32:
|
||||
if p.decimalUint {
|
||||
return p.fmtOrLocalizedSprintf("%d", p.value.Uint())
|
||||
} else {
|
||||
return fmt.Sprintf("0x%08x", p.value.Uint())
|
||||
}
|
||||
case reflect.Uint64:
|
||||
if p.decimalUint {
|
||||
return p.fmtOrLocalizedSprintf("%d", p.value.Uint())
|
||||
} else {
|
||||
return fmt.Sprintf("0x%016x", p.value.Uint())
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return p.fmtOrLocalizedSprintf("%f", p.value.Float())
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
return fmt.Sprintf("%#v", p.value.Complex())
|
||||
default:
|
||||
return fmt.Sprintf("%#v", p.value.Interface())
|
||||
}
|
||||
}
|
||||
|
||||
func (p *printer) nil() string {
|
||||
return p.colorize("nil", p.currentScheme.Nil)
|
||||
}
|
||||
|
||||
func (p *printer) colorize(text string, color uint16) string {
|
||||
if ColoringEnabled && p.coloringEnabled {
|
||||
return colorizeText(text, color)
|
||||
} else {
|
||||
return text
|
||||
}
|
||||
}
|
||||
|
||||
func (p *printer) format(object interface{}) string {
|
||||
pp := newPrinter(object, p.currentScheme, p.maxDepth, p.coloringEnabled, p.decimalUint, p.exportedOnly, p.thousandsSeparator)
|
||||
pp.depth = p.depth
|
||||
pp.visited = p.visited
|
||||
if value, ok := object.(reflect.Value); ok {
|
||||
pp.value = value
|
||||
}
|
||||
return pp.String()
|
||||
}
|
||||
|
||||
func (p *printer) indent() string {
|
||||
return strings.Repeat("\t", p.depth)
|
||||
}
|
||||
|
||||
// valueIsZero reports whether v is the zero value for its type.
|
||||
// It returns false if the argument is invalid.
|
||||
// This is a copy paste of reflect#IsZero from go1.15. It is not present before go1.13 (source: https://golang.org/doc/go1.13#library)
|
||||
// source: https://golang.org/src/reflect/value.go?s=34297:34325#L1090
|
||||
// This will need to be updated for new types or the decision should be made to drop support for Go version pre go1.13
|
||||
func valueIsZero(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Bool:
|
||||
return !v.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return math.Float64bits(v.Float()) == 0
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
c := v.Complex()
|
||||
return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
|
||||
case reflect.Array:
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
if !valueIsZero(v.Index(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
|
||||
return v.IsNil()
|
||||
case reflect.String:
|
||||
return v.Len() == 0
|
||||
case reflect.Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
if !valueIsZero(v.Field(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
default:
|
||||
// this is the only difference between stdlib reflect#IsZero and this function. We're not going to
|
||||
// panic on the default cause, even
|
||||
return false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user