-
Notifications
You must be signed in to change notification settings - Fork 2.7k
/
info.go
124 lines (106 loc) · 2.56 KB
/
info.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium
package cell
import (
"bufio"
"fmt"
"io"
"os"
"strings"
"github.com/davecgh/go-spew/spew"
"golang.org/x/term"
)
const (
// indentBy is the number of spaces nested elements should be indented by
indentBy = 4
)
type InfoPrinter struct {
io.Writer
width int
}
func NewInfoPrinter() *InfoPrinter {
width, _, err := term.GetSize(int(os.Stdout.Fd()))
if err != nil {
width = 120
}
return &InfoPrinter{
Writer: os.Stdout,
width: width,
}
}
// Info provides a simple way of printing cells hierarchically in
// textual form.
type Info interface {
Print(indent int, w *InfoPrinter)
}
type InfoLeaf string
func (l InfoLeaf) Print(indent int, w *InfoPrinter) {
buf := bufio.NewWriter(w)
indentString := strings.Repeat(" ", indent)
buf.WriteString(indentString)
currentLineLength := len(indentString)
wrapped := false
for _, f := range strings.Fields(string(l)) {
newLineLength := currentLineLength + len(f) + 1
if newLineLength >= w.width {
buf.WriteByte('\n')
if !wrapped {
// Increase the indent for the wrapped lines so it's clear we
// wrapped.
wrapped = true
indent += 2
indentString = strings.Repeat(" ", indent)
}
buf.WriteString(indentString)
currentLineLength = indent + len(f) + 1
} else {
currentLineLength = newLineLength
}
buf.WriteString(f)
buf.WriteByte(' ')
}
buf.WriteByte('\n')
buf.Flush()
}
type InfoNode struct {
// Header line. If missing, no header printed and children
// not indented.
header string
condensed bool
children []Info
}
func NewInfoNode(header string) *InfoNode {
return &InfoNode{header: header}
}
func (n *InfoNode) Add(child Info) {
n.children = append(n.children, child)
}
func (n *InfoNode) AddLeaf(format string, args ...any) {
n.Add(InfoLeaf(fmt.Sprintf(format, args...)))
}
func (n *InfoNode) Print(indent int, w *InfoPrinter) {
if n.header != "" {
fmt.Fprintf(w, "%s%s:\n", strings.Repeat(" ", indent), n.header)
indent += indentBy
}
for i, child := range n.children {
child.Print(indent, w)
if !n.condensed && i != len(n.children)-1 {
w.Write([]byte{'\n'})
}
}
}
type InfoStruct struct {
value any
}
func (n *InfoStruct) Print(indent int, w *InfoPrinter) {
scs := spew.ConfigState{Indent: strings.Repeat(" ", indentBy), SortKeys: true}
indentString := strings.Repeat(" ", indent)
for i, line := range strings.Split(scs.Sdump(n.value), "\n") {
if i == 0 {
fmt.Fprintf(w, "%s⚙️ %s\n", indentString, line)
} else {
fmt.Fprintf(w, "%s%s\n", indentString, line)
}
}
}