This commit is contained in:
Geraint Edwards 2019-01-17 15:08:57 +00:00 committed by GitHub
commit 46364ca27e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 93 additions and 0 deletions

View File

@ -62,6 +62,11 @@ var (
closeMapBytes = []byte("]")
lenEqualsBytes = []byte("len=")
capEqualsBytes = []byte("cap=")
highlight1StartBytes = []byte("\x1b[32m")
highlight2StartBytes = []byte("\x1b[33m")
highlight3StartBytes = []byte("\x1b[34m")
highlight4StartBytes = []byte("\x1b[36m")
highlightEndBytes = []byte("\x1b[0m")
)
// hexDigits is used to map a decimal value to a hex digit.

View File

@ -98,6 +98,10 @@ type ConfigState struct {
// be spewed to strings and sorted by those strings. This is only
// considered if SortKeys is true.
SpewKeys bool
// HighlightValues adds colour/color to scalar values in output.
// The colours are suitable for ANSI displays.
HighlightValues bool
}
// Config is the active configuration of the top-level functions.

View File

@ -118,6 +118,10 @@ The following configuration options are available:
spewed to strings and sorted by those strings. This is only
considered if SortKeys is true.
* HighlightValues
When true, values in dumps are highlighted using colours/colors
suitable for ANSI-compatible displays.
Dump Usage
Simply call spew.Dump with a list of variables you want to dump:

View File

@ -309,6 +309,26 @@ func (d *dumpState) dump(v reflect.Value) {
}
}
highlightIsOn := false
if d.cs.HighlightValues {
switch kind {
case reflect.String:
highlightIsOn = true
d.w.Write(highlight1StartBytes)
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int,
reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint,
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
highlightIsOn = true
d.w.Write(highlight2StartBytes)
case reflect.Bool:
highlightIsOn = true
d.w.Write(highlight3StartBytes)
case reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func:
highlightIsOn = true
d.w.Write(highlight4StartBytes)
}
}
switch kind {
case reflect.Invalid:
// Do nothing. We should never get here since invalid has already
@ -446,6 +466,10 @@ func (d *dumpState) dump(v reflect.Value) {
fmt.Fprintf(d.w, "%v", v.String())
}
}
if highlightIsOn {
d.w.Write(highlightEndBytes)
}
}
// fdump is a helper function to consolidate the logic from the various public

View File

@ -64,6 +64,7 @@ package spew_test
import (
"bytes"
"fmt"
"regexp"
"testing"
"unsafe"
@ -1040,3 +1041,58 @@ func TestDumpSortedKeys(t *testing.T) {
}
}
func TestDumpHighlightValues(t *testing.T) {
cfg := spew.ConfigState{SortKeys: true, HighlightValues: true}
col := map[string]string{
"reset": "\x1b[0m",
"str": "\x1b[32m",
"num": "\x1b[33m",
"bool": "\x1b[34m",
"other": "\x1b[36m",
}
s := cfg.Sdump(map[int]string{1: "1", 3: "3", 2: "2"})
expected := "(map[int]string) (len=3) {\n" +
"(int) " + col["num"] + "1" + col["reset"] + ": (string) (len=1) " + col["str"] + "\"1\"" + col["reset"] + ",\n" +
"(int) " + col["num"] + "2" + col["reset"] + ": (string) (len=1) " + col["str"] + "\"2\"" + col["reset"] + ",\n" +
"(int) " + col["num"] + "3" + col["reset"] + ": (string) (len=1) " + col["str"] + "\"3\"" + col["reset"] + "\n" +
"}\n"
if s != expected {
t.Errorf("Highlighted string mismatch:\n %v %v", s, expected)
}
s = cfg.Sdump(map[stringer]int{"1": 1, "3": 3, "2": 2})
expected = "(map[spew_test.stringer]int) (len=3) {\n" +
"(spew_test.stringer) (len=1) stringer 1: (int) " + col["num"] + "1" + col["reset"] + ",\n" +
"(spew_test.stringer) (len=1) stringer 2: (int) " + col["num"] + "2" + col["reset"] + ",\n" +
"(spew_test.stringer) (len=1) stringer 3: (int) " + col["num"] + "3" + col["reset"] + "\n" +
"}\n"
if s != expected {
t.Errorf("Highlighted ints mismatch:\n %v %v", s, expected)
}
s = cfg.Sdump(map[string]bool{"custom1": true, "custom2": false})
expected = "(map[string]bool) (len=2) {\n" +
"(string) (len=7) " + col["str"] + `"custom1"` + col["reset"] + ": (bool) " + col["bool"] + "true" + col["reset"] + ",\n" +
"(string) (len=7) " + col["str"] + `"custom2"` + col["reset"] + ": (bool) " + col["bool"] + "false" + col["reset"] + "\n" +
"}\n"
if s != expected {
t.Errorf("Highlighted keys mismatch:\n %v %v", s, expected)
}
s = cfg.Sdump(map[string]chan int{"chanInt1": make(chan int), "chanInt2": make(chan int)})
dummyPtr := "0x123456789a"
expected = "(map[string]chan int) (len=2) {\n" +
"(string) (len=8) " + col["str"] + `"chanInt1"` + col["reset"] + ": (chan int) " + col["other"] + dummyPtr + col["reset"] + ",\n" +
"(string) (len=8) " + col["str"] + `"chanInt2"` + col["reset"] + ": (chan int) " + col["other"] + dummyPtr + col["reset"] + "\n" +
"}\n"
// replace all pointers with dummyPtr (they will be prefixed by 'm' - from col[], so cannot \b at start) to match expected
re := regexp.MustCompile(`0x[0-9a-f]{10}\b`)
s = re.ReplaceAllString(s, dummyPtr)
if s != expected {
t.Errorf("Highlighted other mismatch:\n %v %v", s, expected)
}
}