-
Notifications
You must be signed in to change notification settings - Fork 1
/
table_helper.go
146 lines (130 loc) · 3.55 KB
/
table_helper.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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package styledconsole
import (
"fmt"
"strings"
"unicode/utf8"
)
func getColumnWidths(headers []string, content [][]string) []int {
columnCount := len(headers)
for _, row := range content {
if columnCount < len(row) {
columnCount = len(row)
}
}
var columnWidths = make([]int, columnCount)
for i, headerItem := range headers {
itemWidth := 0
for _, line := range strings.Split(headerItem, "\n") {
lineLen := utf8.RuneCountInString(line)
if itemWidth < lineLen {
itemWidth = lineLen
}
}
columnWidths[i] = itemWidth
}
for _, row := range content {
for i, rowItem := range row {
itemWidth := 0
for _, line := range strings.Split(rowItem, "\n") {
lineLen := utf8.RuneCountInString(line)
if itemWidth < lineLen {
itemWidth = lineLen
}
}
if columnWidths[i] < itemWidth {
columnWidths[i] = itemWidth
}
}
}
return columnWidths
}
func getTableWidth(widths []int) int {
totalWidth := 0
for _, width := range widths {
totalWidth += width
}
totalWidth += 4 + 3*(len(widths)-1)
return totalWidth
}
func getAcceptableColumnWidths(startingWidths []int, termWidth int) []int {
// Deep copy of startingWidths
columnWidths := make([]int, len(startingWidths))
copy(columnWidths, startingWidths)
for {
if getTableWidth(columnWidths) < termWidth {
// It fits, we can stop
return columnWidths
}
// Every time, we try to reduce the largest column
largestIdx := 0
largestWidth := 0
for i, wid := range columnWidths {
if largestWidth < wid {
largestWidth = wid
largestIdx = i
}
}
if largestWidth > 15 {
if getTableWidth(columnWidths)-termWidth < largestWidth-15 {
// If we reduce the largest column, it will fit
columnWidths[largestIdx] -= getTableWidth(columnWidths) - termWidth
return columnWidths
} else {
// We reduce the largest column to 15char, it won't fit so we continue
columnWidths[largestIdx] = 15
continue
}
}
// If we cannot reduce any column, we try some last resort option
avgWidth := int(termWidth / len(columnWidths))
if avgWidth >= 10 {
for i := range columnWidths {
columnWidths[i] = avgWidth
}
}
// The total width is too wide, but we did our best...
return columnWidths
}
}
func formatOneRow(row []string, columnWidths []int) string {
var preparedSubLines [][]string
totalLines := 1
for cellIdx, cell := range row {
var preparedCellLines []string
for _, subLine := range strings.Split(cell, "\n") {
subLineLen := utf8.RuneCountInString(subLine)
if subLineLen <= columnWidths[cellIdx] {
preparedCellLines = append(preparedCellLines, subLine)
} else {
i := 0
for {
if i+columnWidths[cellIdx] > subLineLen {
preparedCellLines = append(preparedCellLines, subLine[i:])
break
} else {
preparedCellLines = append(preparedCellLines, subLine[i:i+columnWidths[cellIdx]])
i += columnWidths[cellIdx]
}
}
}
}
if len(preparedCellLines) > totalLines {
totalLines = len(preparedCellLines)
}
preparedSubLines = append(preparedSubLines, preparedCellLines)
}
var rowsToPrint []string
for i := 0; i < totalLines; i++ {
rowToPrint := "|"
for columnIdx, column := range preparedSubLines {
if i < len(column) {
columnLen := utf8.RuneCountInString(column[i])
rowToPrint += fmt.Sprintf(" %s%s |", column[i], strings.Repeat(" ", columnWidths[columnIdx]-columnLen))
} else {
rowToPrint += fmt.Sprintf(" %s |", strings.Repeat(" ", columnWidths[columnIdx]))
}
}
rowsToPrint = append(rowsToPrint, rowToPrint)
}
return strings.Join(rowsToPrint, "\n")
}