bee/vendor/github.com/derekparker/delve/service/api/prettyprint.go

322 lines
7.3 KiB
Go

package api
import (
"bytes"
"fmt"
"io"
"reflect"
)
const (
// strings longer than this will cause slices, arrays and structs to be printed on multiple lines when newlines is enabled
maxShortStringLen = 7
// string used for one indentation level (when printing on multiple lines)
indentString = "\t"
)
// SinglelineString returns a representation of v on a single line.
func (v *Variable) SinglelineString() string {
var buf bytes.Buffer
v.writeTo(&buf, true, false, true, "")
return buf.String()
}
// MultilineString returns a representation of v on multiple lines.
func (v *Variable) MultilineString(indent string) string {
var buf bytes.Buffer
v.writeTo(&buf, true, true, true, indent)
return buf.String()
}
func (v *Variable) writeTo(buf io.Writer, top, newlines, includeType bool, indent string) {
if v.Unreadable != "" {
fmt.Fprintf(buf, "(unreadable %s)", v.Unreadable)
return
}
if !top && v.Addr == 0 {
if includeType && v.Type != "void" {
fmt.Fprintf(buf, "%s nil", v.Type)
} else {
fmt.Fprintf(buf, "nil")
}
return
}
switch v.Kind {
case reflect.Slice:
v.writeSliceTo(buf, newlines, includeType, indent)
case reflect.Array:
v.writeArrayTo(buf, newlines, includeType, indent)
case reflect.Ptr:
if v.Type == "" {
fmt.Fprintf(buf, "nil")
} else if v.Children[0].OnlyAddr && v.Children[0].Addr != 0 {
fmt.Fprintf(buf, "(%s)(0x%x)", v.Type, v.Children[0].Addr)
} else {
fmt.Fprintf(buf, "*")
v.Children[0].writeTo(buf, false, newlines, includeType, indent)
}
case reflect.UnsafePointer:
fmt.Fprintf(buf, "unsafe.Pointer(0x%x)", v.Children[0].Addr)
case reflect.String:
v.writeStringTo(buf)
case reflect.Chan:
if newlines {
v.writeStructTo(buf, newlines, includeType, indent)
} else {
if len(v.Children) == 0 {
fmt.Fprintf(buf, "%s nil", v.Type)
} else {
fmt.Fprintf(buf, "%s %s/%s", v.Type, v.Children[0].Value, v.Children[1].Value)
}
}
case reflect.Struct:
v.writeStructTo(buf, newlines, includeType, indent)
case reflect.Interface:
if includeType {
if v.Children[0].Kind == reflect.Invalid {
fmt.Fprintf(buf, "%s ", v.Type)
if v.Children[0].Addr == 0 {
fmt.Fprintf(buf, "nil")
return
}
} else {
fmt.Fprintf(buf, "%s(%s) ", v.Type, v.Children[0].Type)
}
}
data := v.Children[0]
if data.Kind == reflect.Ptr {
if data.Children[0].Addr == 0 {
fmt.Fprintf(buf, "nil")
} else if data.Children[0].OnlyAddr {
fmt.Fprintf(buf, "0x%x", v.Children[0].Addr)
} else {
v.Children[0].writeTo(buf, false, newlines, !includeType, indent)
}
} else {
v.Children[0].writeTo(buf, false, newlines, !includeType, indent)
}
case reflect.Map:
v.writeMapTo(buf, newlines, includeType, indent)
case reflect.Func:
if v.Value == "" {
fmt.Fprintf(buf, "nil")
} else {
fmt.Fprintf(buf, "%s", v.Value)
}
case reflect.Complex64, reflect.Complex128:
fmt.Fprintf(buf, "(%s + %si)", v.Children[0].Value, v.Children[1].Value)
default:
if v.Value != "" {
buf.Write([]byte(v.Value))
} else {
fmt.Fprintf(buf, "(unknown %s)", v.Kind)
}
}
}
func (v *Variable) writeStringTo(buf io.Writer) {
s := v.Value
if len(s) != int(v.Len) {
s = fmt.Sprintf("%s...+%d more", s, int(v.Len)-len(s))
}
fmt.Fprintf(buf, "%q", s)
}
func (v *Variable) writeSliceTo(buf io.Writer, newlines, includeType bool, indent string) {
if includeType {
fmt.Fprintf(buf, "%s len: %d, cap: %d, ", v.Type, v.Len, v.Cap)
}
v.writeSliceOrArrayTo(buf, newlines, indent)
}
func (v *Variable) writeArrayTo(buf io.Writer, newlines, includeType bool, indent string) {
if includeType {
fmt.Fprintf(buf, "%s ", v.Type)
}
v.writeSliceOrArrayTo(buf, newlines, indent)
}
func (v *Variable) writeStructTo(buf io.Writer, newlines, includeType bool, indent string) {
if int(v.Len) != len(v.Children) && len(v.Children) == 0 {
fmt.Fprintf(buf, "(*%s)(0x%x)", v.Type, v.Addr)
return
}
if includeType {
fmt.Fprintf(buf, "%s ", v.Type)
}
nl := v.shouldNewlineStruct(newlines)
fmt.Fprintf(buf, "{")
for i := range v.Children {
if nl {
fmt.Fprintf(buf, "\n%s%s", indent, indentString)
}
fmt.Fprintf(buf, "%s: ", v.Children[i].Name)
v.Children[i].writeTo(buf, false, nl, true, indent+indentString)
if i != len(v.Children)-1 || nl {
fmt.Fprintf(buf, ",")
if !nl {
fmt.Fprintf(buf, " ")
}
}
}
if len(v.Children) != int(v.Len) {
if nl {
fmt.Fprintf(buf, "\n%s%s", indent, indentString)
} else {
fmt.Fprintf(buf, ",")
}
fmt.Fprintf(buf, "...+%d more", int(v.Len)-len(v.Children))
}
fmt.Fprintf(buf, "}")
}
func (v *Variable) writeMapTo(buf io.Writer, newlines, includeType bool, indent string) {
if includeType {
fmt.Fprintf(buf, "%s ", v.Type)
}
nl := newlines && (len(v.Children) > 0)
fmt.Fprintf(buf, "[")
for i := 0; i < len(v.Children); i += 2 {
key := &v.Children[i]
value := &v.Children[i+1]
if nl {
fmt.Fprintf(buf, "\n%s%s", indent, indentString)
}
key.writeTo(buf, false, false, false, indent+indentString)
fmt.Fprintf(buf, ": ")
value.writeTo(buf, false, nl, false, indent+indentString)
if i != len(v.Children)-1 || nl {
fmt.Fprintf(buf, ", ")
}
}
if len(v.Children)/2 != int(v.Len) {
if len(v.Children) != 0 {
if nl {
fmt.Fprintf(buf, "\n%s%s", indent, indentString)
} else {
fmt.Fprintf(buf, ",")
}
fmt.Fprintf(buf, "...+%d more", int(v.Len)-(len(v.Children)/2))
} else {
fmt.Fprintf(buf, "...")
}
}
if nl {
fmt.Fprintf(buf, "\n%s", indent)
}
fmt.Fprintf(buf, "]")
}
func (v *Variable) shouldNewlineArray(newlines bool) bool {
if !newlines || len(v.Children) == 0 {
return false
}
kind, hasptr := (&v.Children[0]).recursiveKind()
switch kind {
case reflect.Slice, reflect.Array, reflect.Struct, reflect.Map, reflect.Interface:
return true
case reflect.String:
if hasptr {
return true
}
for i := range v.Children {
if len(v.Children[i].Value) > maxShortStringLen {
return true
}
}
return false
default:
return false
}
}
func (v *Variable) recursiveKind() (reflect.Kind, bool) {
hasptr := false
var kind reflect.Kind
for {
kind = v.Kind
if kind == reflect.Ptr {
hasptr = true
v = &(v.Children[0])
} else {
break
}
}
return kind, hasptr
}
func (v *Variable) shouldNewlineStruct(newlines bool) bool {
if !newlines || len(v.Children) == 0 {
return false
}
for i := range v.Children {
kind, hasptr := (&v.Children[i]).recursiveKind()
switch kind {
case reflect.Slice, reflect.Array, reflect.Struct, reflect.Map, reflect.Interface:
return true
case reflect.String:
if hasptr {
return true
}
if len(v.Children[i].Value) > maxShortStringLen {
return true
}
}
}
return false
}
func (v *Variable) writeSliceOrArrayTo(buf io.Writer, newlines bool, indent string) {
nl := v.shouldNewlineArray(newlines)
fmt.Fprintf(buf, "[")
for i := range v.Children {
if nl {
fmt.Fprintf(buf, "\n%s%s", indent, indentString)
}
v.Children[i].writeTo(buf, false, nl, false, indent+indentString)
if i != len(v.Children)-1 || nl {
fmt.Fprintf(buf, ",")
}
}
if len(v.Children) != int(v.Len) {
if len(v.Children) != 0 {
if nl {
fmt.Fprintf(buf, "\n%s%s", indent, indentString)
} else {
fmt.Fprintf(buf, ",")
}
fmt.Fprintf(buf, "...+%d more", int(v.Len)-len(v.Children))
} else {
fmt.Fprintf(buf, "...")
}
}
if nl {
fmt.Fprintf(buf, "\n%s", indent)
}
fmt.Fprintf(buf, "]")
}