...
1 package utils
2
3 import (
4 "fmt"
5 "strings"
6 "unicode/utf8"
7 )
8
9 type TextFormatter struct {
10 table *Table
11 colSizes []int
12 }
13
14 func (t *TextFormatter) tableWidth() int {
15 res := 0
16 for _, cs := range t.colSizes {
17 res = res + cs
18 }
19 return res
20 }
21 func (t *Table) ToPrettyString() string {
22 tf := &TextFormatter{table: t}
23 return tf.ToPrettyString()
24 }
25 func (tf *TextFormatter) adjustColsToMatchTerminal() {
26 di, err := TerminalSize()
27 if err != nil {
28 fmt.Printf("[go-easyops] unable to determine terminal size (%s)\n", err)
29 return
30 }
31 if di.Columns() < len(tf.colSizes) {
32 fmt.Printf("[go-easyops] terminal has %d columns, but table has %d columns\n", di.Columns(), len(tf.colSizes))
33 return
34 }
35
36 extraSize := len(tf.colSizes)*3 + 2
37 if di.Columns() < extraSize {
38 return
39 }
40
41 shrank := false
42 for tf.tableWidth() > di.Columns()-extraSize {
43
44
45 col_shrink := -1
46 for col, size := range tf.colSizes {
47 if col_shrink == -1 || tf.colSizes[col_shrink] < size {
48 col_shrink = col
49 }
50 }
51 if col_shrink == -1 {
52
53 return
54 }
55 tf.colSizes[col_shrink]--
56 shrank = true
57 }
58 for col, size := range tf.colSizes {
59 tf.table.SetMaxLen(col, size)
60 }
61 if shrank {
62
68 }
69
70 }
71 func (tf *TextFormatter) ToPrettyString() string {
72 r := tf.table.GetPrintingRows()
73 if tf.table.headerRow != nil {
74 r = append(r, tf.table.headerRow)
75 }
76 tf.colSizes = getCharWidth(r)
77 tf.adjustColsToMatchTerminal()
78 var sb strings.Builder
79 if tf.table.headerRow != nil {
80 sb.WriteString(tf.renderRow(tf.table.headerRow, 2))
81 sb.WriteString(tf.seperatorRow())
82 }
83 for _, row := range tf.table.GetPrintingRows() {
84 sb.WriteString(tf.renderRow(row, 0))
85 }
86 sb.WriteString(tf.seperatorRow())
87 return sb.String()
88 }
89 func (tf *TextFormatter) seperatorRow() string {
90 s := ""
91 for _, cs := range tf.colSizes {
92 xs := "|"
93 for len(xs) < (cs + 3) {
94 xs = xs + "="
95 }
96 s = s + xs
97 }
98 return s + "|\n"
99
100 }
101
102
103 func (tf *TextFormatter) renderRow(row *Row, pos int) string {
104 res := "| "
105 l := false
106 for i, c := range row.Cells() {
107 s := c.String()
108 for len(s) < tf.colSizes[i] {
109 if pos == 2 {
110 if l {
111 l = false
112 s = " " + s
113 } else {
114 l = true
115 s = s + " "
116 }
117 } else if pos == 0 {
118 s = s + " "
119 } else {
120 s = " " + s
121 }
122 }
123 res = res + s + " | "
124 }
125 res = res + "\n"
126 return res
127
128 }
129
130
131 func getCharWidth(rows []*Row) []int {
132 maxCols := 0
133 for _, r := range rows {
134 if r.Cols() > maxCols {
135 maxCols = r.Cols()
136 }
137 }
138 sz := make(map[int]int)
139 for _, r := range rows {
140 for i := 0; i < maxCols; i++ {
141 c := r.GetCell(i)
142 if c == nil {
143 continue
144 }
145 w := utf8.RuneCountInString(c.String())
146 if w > sz[i] {
147 sz[i] = w
148 }
149 }
150 }
151
152
153 var res []int
154 for i := 0; i < len(sz); i++ {
155 res = append(res, sz[i])
156 }
157 return res
158 }
159
View as plain text