notation/notation.go

349 lines
9.2 KiB
Go
Raw Normal View History

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"
"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
randomMaps
pointerValues
2020-10-20 02:43:52 +02: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{}
len int
wrapLen wrapLen
fullWrap wrapLen
wrap bool
2020-10-22 20:55:32 +02:00
}
type str struct {
val string
raw string
rawLen wrapLen
2020-11-26 14:27:42 +01:00
useRaw bool
}
type wrapMode int
const (
block wrapMode = iota
line
)
2020-10-22 20:55:32 +02:00
type wrapper struct {
mode wrapMode
sep, suffix string
items []node
lineEnds []int
}
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
func (n node) String() string {
var b bytes.Buffer
w := &writer{w: &b}
fprint(w, 0, n)
return b.String()
}
func (s str) String() string {
if s.useRaw {
return s.raw
}
return s.val
}
func (w *writer) write(o interface{}) {
if w.err != nil {
return
}
n, err := fmt.Fprint(w.w, o)
w.n += n
w.err = err
}
func (w *writer) blankLine() {
w.write("\n")
}
func (w *writer) tabs(n int) {
for i := 0; i < n; i++ {
w.write("\t")
}
2020-10-22 20:55:32 +02: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)
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)
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)
}