2020-11-23 15:42:05 +01:00
|
|
|
/*
|
2020-11-26 14:27:42 +01:00
|
|
|
Package notation can be used to print (or sprint) Go objects with optional wrapping (and indentation) and
|
2020-11-23 15:42:05 +01:00
|
|
|
optional type information.
|
|
|
|
*/
|
2020-10-20 02:43:52 +02:00
|
|
|
package notation
|
|
|
|
|
|
|
|
import (
|
2020-10-22 20:55:32 +02:00
|
|
|
"bytes"
|
2020-11-10 00:56:25 +01:00
|
|
|
"fmt"
|
2020-10-22 20:55:32 +02:00
|
|
|
"io"
|
|
|
|
"os"
|
2020-10-20 02:43:52 +02:00
|
|
|
"reflect"
|
2020-10-22 20:55:32 +02:00
|
|
|
"strconv"
|
2020-10-20 02:43:52 +02:00
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
type opts int
|
|
|
|
|
|
|
|
const none opts = 0
|
|
|
|
|
|
|
|
const (
|
|
|
|
wrap opts = 1 << iota
|
|
|
|
types
|
|
|
|
skipTypes
|
|
|
|
allTypes
|
2020-11-10 00:56:25 +01:00
|
|
|
randomMaps
|
2020-12-06 22:30:19 +01:00
|
|
|
pointerValues
|
2020-10-20 02:43:52 +02:00
|
|
|
)
|
|
|
|
|
2020-11-10 00:56:25 +01:00
|
|
|
type wrapLen struct {
|
|
|
|
first, max, last int
|
|
|
|
}
|
|
|
|
|
2020-11-22 23:22:20 +01:00
|
|
|
type nodeRef struct {
|
|
|
|
id, refCount int
|
|
|
|
}
|
|
|
|
|
|
|
|
type pending struct {
|
2020-11-23 00:46:14 +01:00
|
|
|
values map[uintptr]nodeRef
|
2020-11-22 23:22:20 +01:00
|
|
|
idCounter int
|
|
|
|
}
|
|
|
|
|
2020-10-22 20:55:32 +02:00
|
|
|
type node struct {
|
2020-11-26 14:27:42 +01:00
|
|
|
parts []interface{}
|
2020-11-10 00:56:25 +01:00
|
|
|
len int
|
|
|
|
wrapLen wrapLen
|
|
|
|
fullWrap wrapLen
|
|
|
|
wrap bool
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-22 19:14:45 +01:00
|
|
|
type str struct {
|
|
|
|
val string
|
|
|
|
raw string
|
|
|
|
rawLen wrapLen
|
2020-11-26 14:27:42 +01:00
|
|
|
useRaw bool
|
2020-11-22 19:14:45 +01:00
|
|
|
}
|
|
|
|
|
2020-11-10 00:56:25 +01:00
|
|
|
type wrapMode int
|
|
|
|
|
|
|
|
const (
|
|
|
|
block wrapMode = iota
|
|
|
|
line
|
|
|
|
)
|
|
|
|
|
2020-10-22 20:55:32 +02:00
|
|
|
type wrapper struct {
|
2020-11-22 19:14:45 +01:00
|
|
|
mode wrapMode
|
|
|
|
sep, suffix string
|
|
|
|
items []node
|
|
|
|
lineEnds []int
|
2020-11-10 00:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
type writer struct {
|
|
|
|
w io.Writer
|
|
|
|
n int
|
|
|
|
err error
|
|
|
|
}
|
|
|
|
|
2020-11-23 00:46:14 +01:00
|
|
|
var stderr io.Writer = os.Stderr
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
func nodeOf(parts ...interface{}) node {
|
|
|
|
return node{parts: parts}
|
|
|
|
}
|
|
|
|
|
|
|
|
// used only for debugging
|
2020-11-10 00:56:25 +01:00
|
|
|
func (n node) String() string {
|
|
|
|
var b bytes.Buffer
|
|
|
|
w := &writer{w: &b}
|
|
|
|
fprint(w, 0, n)
|
|
|
|
return b.String()
|
|
|
|
}
|
|
|
|
|
2020-11-22 19:14:45 +01:00
|
|
|
func (s str) String() string {
|
|
|
|
if s.useRaw {
|
|
|
|
return s.raw
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.val
|
|
|
|
}
|
|
|
|
|
2020-11-10 00:56:25 +01:00
|
|
|
func (w *writer) write(o interface{}) {
|
|
|
|
if w.err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
n, err := fmt.Fprint(w.w, o)
|
|
|
|
w.n += n
|
|
|
|
w.err = err
|
|
|
|
}
|
|
|
|
|
2020-11-22 19:14:45 +01:00
|
|
|
func (w *writer) blankLine() {
|
2020-11-10 00:56:25 +01:00
|
|
|
w.write("\n")
|
2020-11-22 19:14:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (w *writer) tabs(n int) {
|
|
|
|
for i := 0; i < n; i++ {
|
2020-11-10 00:56:25 +01:00
|
|
|
w.write("\t")
|
|
|
|
}
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-22 19:14:45 +01:00
|
|
|
func (w *writer) line(t int) {
|
|
|
|
w.blankLine()
|
|
|
|
w.tabs(t)
|
|
|
|
}
|
|
|
|
|
2020-10-22 20:55:32 +02:00
|
|
|
func config(name string, dflt int) int {
|
|
|
|
s := os.Getenv(name)
|
|
|
|
if s == "" {
|
|
|
|
s = os.Getenv(strings.ToLower(name))
|
|
|
|
}
|
|
|
|
|
|
|
|
if s == "" {
|
|
|
|
return dflt
|
|
|
|
}
|
|
|
|
|
|
|
|
v, err := strconv.Atoi(s)
|
|
|
|
if err != nil {
|
|
|
|
return dflt
|
|
|
|
}
|
|
|
|
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
func fprintValues(w io.Writer, o opts, v []interface{}) (int, error) {
|
|
|
|
tab := config("TABWIDTH", 8)
|
2020-11-10 00:56:25 +01:00
|
|
|
cols0 := config("LINEWIDTH", 80-tab)
|
|
|
|
cols1 := config("LINEWIDTH1", (cols0+tab)*3/2-tab)
|
|
|
|
sortMaps := config("MAPSORT", 1)
|
|
|
|
if sortMaps == 0 {
|
|
|
|
o |= randomMaps
|
|
|
|
}
|
|
|
|
|
2020-10-22 20:55:32 +02:00
|
|
|
wr := &writer{w: w}
|
|
|
|
for i, vi := range v {
|
|
|
|
if wr.err != nil {
|
|
|
|
return wr.n, wr.err
|
|
|
|
}
|
|
|
|
|
|
|
|
if i > 0 {
|
|
|
|
if o&wrap == 0 {
|
|
|
|
wr.write(" ")
|
|
|
|
} else {
|
|
|
|
wr.write("\n")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if vi == nil {
|
|
|
|
fprint(wr, 0, nodeOf("nil"))
|
2020-10-20 02:43:52 +02:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
p := &pending{values: make(map[uintptr]nodeRef)}
|
|
|
|
n := reflectValue(o, p, reflect.ValueOf(vi))
|
2020-10-22 20:55:32 +02:00
|
|
|
if o&wrap != 0 {
|
|
|
|
n = nodeLen(tab, n)
|
2020-11-22 19:14:45 +01:00
|
|
|
n = wrapNode(tab, cols0, cols0, cols1, n)
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
2020-10-20 02:43:52 +02:00
|
|
|
|
2020-10-22 20:55:32 +02:00
|
|
|
fprint(wr, 0, n)
|
2020-10-20 02:43:52 +02:00
|
|
|
}
|
|
|
|
|
2020-10-22 20:55:32 +02:00
|
|
|
return wr.n, wr.err
|
|
|
|
}
|
|
|
|
|
2020-11-23 00:46:14 +01:00
|
|
|
func printValues(o opts, v []interface{}) (int, error) {
|
|
|
|
return fprintValues(stderr, o, v)
|
|
|
|
}
|
|
|
|
|
|
|
|
func printlnValues(o opts, v []interface{}) (int, error) {
|
|
|
|
n, err := fprintValues(stderr, o, v)
|
|
|
|
if err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
nn, err := stderr.Write([]byte("\n"))
|
|
|
|
return n + nn, err
|
|
|
|
}
|
|
|
|
|
2020-10-22 20:55:32 +02:00
|
|
|
func sprintValues(o opts, v []interface{}) string {
|
|
|
|
var b bytes.Buffer
|
|
|
|
fprintValues(&b, o, v)
|
|
|
|
return b.String()
|
|
|
|
}
|
|
|
|
|
2020-11-23 15:42:05 +01:00
|
|
|
// Fprint prints the provided objects to the provided writer. When multiple objects are printed, they'll be
|
|
|
|
// separated by a space.
|
2020-10-22 20:55:32 +02:00
|
|
|
func Fprint(w io.Writer, v ...interface{}) (int, error) {
|
|
|
|
return fprintValues(w, none, v)
|
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
// Fprintw prints the provided objects to the provided writer, with wrapping (and indentation) where necessary.
|
2020-11-23 15:42:05 +01:00
|
|
|
// When multiple objects are printed, they'll be separated by a newline.
|
2020-10-22 20:55:32 +02:00
|
|
|
func Fprintw(w io.Writer, v ...interface{}) (int, error) {
|
|
|
|
return fprintValues(w, wrap, v)
|
|
|
|
}
|
|
|
|
|
2020-11-23 15:42:05 +01:00
|
|
|
// Fprintt prints the provided objects to the provided writer with moderate type information. When multiple
|
|
|
|
// objects are printed, they'll be separated by a space.
|
2020-10-22 20:55:32 +02:00
|
|
|
func Fprintt(w io.Writer, v ...interface{}) (int, error) {
|
|
|
|
return fprintValues(w, types, v)
|
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
// Fprintwt prints the provided objects to the provided writer, with wrapping (and indentation) where necessary,
|
2020-11-23 15:42:05 +01:00
|
|
|
// and with moderate type information. When multiple objects are printed, they'll be separated by a newline.
|
2020-10-22 20:55:32 +02:00
|
|
|
func Fprintwt(w io.Writer, v ...interface{}) (int, error) {
|
|
|
|
return fprintValues(w, wrap|types, v)
|
|
|
|
}
|
|
|
|
|
2020-11-23 15:42:05 +01:00
|
|
|
// Fprintv prints the provided objects to the provided writer with verbose type information. When multiple
|
|
|
|
// objects are printed, they'll be separated by a space.
|
2020-10-22 20:55:32 +02:00
|
|
|
func Fprintv(w io.Writer, v ...interface{}) (int, error) {
|
|
|
|
return fprintValues(w, allTypes, v)
|
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
// Fprintwv prints the provided objects to the provided writer, with wrapping (and indentation) where necessary,
|
2020-11-23 15:42:05 +01:00
|
|
|
// and with verbose type information. When multiple objects are printed, they'll be separated by a newline.
|
2020-10-22 20:55:32 +02:00
|
|
|
func Fprintwv(w io.Writer, v ...interface{}) (int, error) {
|
|
|
|
return fprintValues(w, wrap|allTypes, v)
|
2020-10-20 02:43:52 +02:00
|
|
|
}
|
|
|
|
|
2020-11-23 15:42:05 +01:00
|
|
|
// Print prints the provided objects to stderr. When multiple objects are printed, they'll be separated by a
|
|
|
|
// space.
|
2020-11-23 00:46:14 +01:00
|
|
|
func Print(v ...interface{}) (int, error) {
|
|
|
|
return printValues(none, v)
|
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
// Printw prints the provided objects to stderr, with wrapping (and indentation) where necessary. When multiple
|
2020-11-23 15:42:05 +01:00
|
|
|
// objects are printed, they'll be separated by a newline.
|
2020-11-23 00:46:14 +01:00
|
|
|
func Printw(v ...interface{}) (int, error) {
|
|
|
|
return printValues(wrap, v)
|
|
|
|
}
|
|
|
|
|
2020-11-23 15:42:05 +01:00
|
|
|
// Printt prints the provided objects to stderr with moderate type information. When multiple objects are
|
|
|
|
// printed, they'll be separated by a space.
|
2020-11-23 00:46:14 +01:00
|
|
|
func Printt(v ...interface{}) (int, error) {
|
|
|
|
return printValues(types, v)
|
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
// Printwt prints the provided objects to stderr, with wrapping (and indentation) where necessary, and with
|
2020-11-23 15:42:05 +01:00
|
|
|
// moderate type information. When multiple objects are printed, they'll be separated by a newline.
|
2020-11-23 00:46:14 +01:00
|
|
|
func Printwt(v ...interface{}) (int, error) {
|
|
|
|
return printValues(wrap|types, v)
|
|
|
|
}
|
|
|
|
|
2020-11-23 15:42:05 +01:00
|
|
|
// Printv prints the provided objects to stderr with verbose type information. When multiple objects are
|
|
|
|
// printed, they'll be separated by a space.
|
2020-11-23 00:46:14 +01:00
|
|
|
func Printv(v ...interface{}) (int, error) {
|
|
|
|
return printValues(allTypes, v)
|
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
// Printwv prints the provided objects to stderr, with wrapping (and indentation) where necessary, and with
|
2020-11-23 15:42:05 +01:00
|
|
|
// verbose type information. When multiple objects are printed, they'll be separated by a newline.
|
2020-11-23 00:46:14 +01:00
|
|
|
func Printwv(v ...interface{}) (int, error) {
|
|
|
|
return printValues(wrap|allTypes, v)
|
|
|
|
}
|
|
|
|
|
2020-11-23 15:42:05 +01:00
|
|
|
// Println prints the provided objects to stderr with a closing newline. When multiple objects are printed,
|
|
|
|
// they'll be separated by a space.
|
2020-11-23 00:46:14 +01:00
|
|
|
func Println(v ...interface{}) (int, error) {
|
|
|
|
return printlnValues(none, v)
|
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
// Printlnw prints the provided objects to stderr with a closing newline, with wrapping (and indentation) where
|
2020-11-23 15:42:05 +01:00
|
|
|
// necessary. When multiple objects are printed, they'll be separated by a newline.
|
2020-11-23 00:46:14 +01:00
|
|
|
func Printlnw(v ...interface{}) (int, error) {
|
|
|
|
return printlnValues(wrap, v)
|
|
|
|
}
|
|
|
|
|
2020-11-23 15:42:05 +01:00
|
|
|
// Printlnt prints the provided objects to stderr with a closing newline, and with moderate type information. When
|
|
|
|
// multiple objects are printed, they'll be separated by a space.
|
2020-11-23 00:46:14 +01:00
|
|
|
func Printlnt(v ...interface{}) (int, error) {
|
|
|
|
return printlnValues(types, v)
|
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
// Printlnwt prints the provided objects to stderr with a closing newline, with wrapping (and indentation) where
|
2020-11-23 15:42:05 +01:00
|
|
|
// necessary, and with moderate type information. When multiple objects are printed, they'll be separated by a
|
|
|
|
// newline.
|
2020-11-23 00:46:14 +01:00
|
|
|
func Printlnwt(v ...interface{}) (int, error) {
|
|
|
|
return printlnValues(wrap|types, v)
|
|
|
|
}
|
|
|
|
|
2020-11-23 15:42:05 +01:00
|
|
|
// Printlnv prints the provided objects to stderr with a closing newline, and with verbose type information. When
|
|
|
|
// multiple objects are printed, they'll be separated by a space.
|
2020-11-23 00:46:14 +01:00
|
|
|
func Printlnv(v ...interface{}) (int, error) {
|
|
|
|
return printlnValues(allTypes, v)
|
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
// Printlnwv prints the provided objects to stderr with a closing newline, with wrapping (and indentation) where
|
2020-11-23 15:42:05 +01:00
|
|
|
// necessary, and with verbose type information. When multiple objects are printed, they'll be separated by a
|
|
|
|
// newline.
|
2020-11-23 00:46:14 +01:00
|
|
|
func Printlnwv(v ...interface{}) (int, error) {
|
|
|
|
return printlnValues(wrap|allTypes, v)
|
|
|
|
}
|
|
|
|
|
2020-11-23 15:42:05 +01:00
|
|
|
// Sprint returns the string representation of the Go objects. When multiple objects are provided, they'll be
|
|
|
|
// seprated by a space.
|
2020-10-20 02:43:52 +02:00
|
|
|
func Sprint(v ...interface{}) string {
|
|
|
|
return sprintValues(none, v)
|
|
|
|
}
|
|
|
|
|
2020-11-26 18:05:14 +01:00
|
|
|
// Sprintw returns the string representation of the Go objects, with wrapping (and indentation) where necessary.
|
2020-11-23 15:42:05 +01:00
|
|
|
// When multiple objects are provided, they'll be seprated by a newline.
|
2020-10-20 02:43:52 +02:00
|
|
|
func Sprintw(v ...interface{}) string {
|
|
|
|
return sprintValues(wrap, v)
|
|
|
|
}
|
|
|
|
|
2020-11-26 18:05:14 +01:00
|
|
|
// Sprintt returns the string representation of the Go objects, with moderate type information. When multiple
|
2020-11-23 15:42:05 +01:00
|
|
|
// objects are provided, they'll be seprated by a space.
|
2020-10-20 02:43:52 +02:00
|
|
|
func Sprintt(v ...interface{}) string {
|
|
|
|
return sprintValues(types, v)
|
|
|
|
}
|
|
|
|
|
2020-11-26 18:05:14 +01:00
|
|
|
// Sprintwt returns the string representation of the Go objects, with wrapping (and indentation) where necessary,
|
2020-11-23 15:42:05 +01:00
|
|
|
// and with moderate type information. When multiple objects are provided, they'll be seprated by a newline.
|
2020-10-20 02:43:52 +02:00
|
|
|
func Sprintwt(v ...interface{}) string {
|
|
|
|
return sprintValues(wrap|types, v)
|
|
|
|
}
|
|
|
|
|
2020-11-26 18:05:14 +01:00
|
|
|
// Sprintv returns the string representation of the Go objects, with verbose type information. When multiple
|
2020-11-23 15:42:05 +01:00
|
|
|
// objects are provided, they'll be seprated by a space.
|
2020-10-20 02:43:52 +02:00
|
|
|
func Sprintv(v ...interface{}) string {
|
|
|
|
return sprintValues(allTypes, v)
|
|
|
|
}
|
|
|
|
|
2020-11-26 18:05:14 +01:00
|
|
|
// Sprintwv returns the string representation of the Go objects, with wrapping (and indentation) where necessary,
|
2020-11-23 15:42:05 +01:00
|
|
|
// and with verbose type information. When multiple objects are provided, they'll be seprated by a newline.
|
2020-10-20 02:43:52 +02:00
|
|
|
func Sprintwv(v ...interface{}) string {
|
|
|
|
return sprintValues(wrap|allTypes, v)
|
|
|
|
}
|