• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jedib0t / go-pretty / 19554310240

20 Nov 2025 11:12PM UTC coverage: 98.98% (-1.0%) from 100.0%
19554310240

push

github

jedib0t
table: support filtering rows using FilterBy

208 of 255 new or added lines in 3 files covered. (81.57%)

1 existing line in 1 file now uncovered.

4659 of 4707 relevant lines covered (98.98%)

1.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.6
/table/render_init.go
1
package table
2

3
import (
4
        "fmt"
5
        "sort"
6
        "strings"
7
        "unicode"
8

9
        "github.com/jedib0t/go-pretty/v6/text"
10
)
11

12
func (t *Table) analyzeAndStringify(row Row, hint renderHint) rowStr {
1✔
13
        // update t.numColumns if this row is the longest seen till now
1✔
14
        if len(row) > t.numColumns {
2✔
15
                // init the slice for the first time; and pad it the rest of the time
1✔
16
                if t.numColumns == 0 {
2✔
17
                        t.columnIsNonNumeric = make([]bool, len(row))
1✔
18
                } else {
2✔
19
                        t.columnIsNonNumeric = append(t.columnIsNonNumeric, make([]bool, len(row)-t.numColumns)...)
1✔
20
                }
1✔
21
                // update t.numColumns
22
                t.numColumns = len(row)
1✔
23
        }
24

25
        // convert each column to string and figure out if it has non-numeric data
26
        rowOut := make(rowStr, len(row))
1✔
27
        for colIdx, col := range row {
2✔
28
                // if the column is not a number, keep track of it
1✔
29
                if !hint.isHeaderRow && !hint.isFooterRow && !t.columnIsNonNumeric[colIdx] && !isNumber(col) {
2✔
30
                        t.columnIsNonNumeric[colIdx] = true
1✔
31
                }
1✔
32

33
                rowOut[colIdx] = t.analyzeAndStringifyColumn(colIdx, col, hint)
1✔
34
        }
35
        return rowOut
1✔
36
}
37

38
func (t *Table) analyzeAndStringifyColumn(colIdx int, col interface{}, hint renderHint) string {
1✔
39
        // convert to a string and store it in the row
1✔
40
        var colStr string
1✔
41
        if transformer := t.getColumnTransformer(colIdx, hint); transformer != nil {
2✔
42
                colStr = transformer(col)
1✔
43
        } else if colStrVal, ok := col.(string); ok {
3✔
44
                colStr = colStrVal
1✔
45
        } else {
2✔
46
                colStr = convertValueToString(col)
1✔
47
        }
1✔
48
        colStr = strings.ReplaceAll(colStr, "\t", "    ")
1✔
49
        colStr = text.ProcessCRLF(colStr)
1✔
50
        // Avoid fmt.Sprintf when direction modifier is empty (most common case)
1✔
51
        if t.directionModifier == "" {
2✔
52
                return colStr
1✔
53
        }
1✔
54
        return t.directionModifier + colStr
1✔
55
}
56

57
func (t *Table) extractMaxColumnLengths(rows []rowStr, hint renderHint) {
1✔
58
        for rowIdx, row := range rows {
2✔
59
                hint.rowNumber = rowIdx + 1
1✔
60
                t.extractMaxColumnLengthsFromRow(row, t.getMergedColumnIndices(row, hint))
1✔
61
        }
1✔
62
}
63

64
func (t *Table) extractMaxColumnLengthsFromRow(row rowStr, mci mergedColumnIndices) {
1✔
65
        for colIdx := 0; colIdx < len(row); colIdx++ {
2✔
66
                colStr := row[colIdx]
1✔
67
                longestLineLen := text.LongestLineLen(colStr)
1✔
68
                maxColWidth := t.getColumnWidthMax(colIdx)
1✔
69
                if maxColWidth > 0 && maxColWidth < longestLineLen {
2✔
70
                        longestLineLen = maxColWidth
1✔
71
                }
1✔
72

73
                if mergeEndIndex, ok := mci[colIdx]; ok {
2✔
74
                        startIndexMap := t.maxMergedColumnLengths[mergeEndIndex]
1✔
75
                        if startIndexMap == nil {
2✔
76
                                startIndexMap = make(map[int]int)
1✔
77
                                t.maxMergedColumnLengths[mergeEndIndex] = startIndexMap
1✔
78
                        }
1✔
79
                        if longestLineLen > startIndexMap[colIdx] {
2✔
80
                                startIndexMap[colIdx] = longestLineLen
1✔
81
                        }
1✔
82
                        colIdx = mergeEndIndex
1✔
83
                } else if longestLineLen > t.maxColumnLengths[colIdx] {
2✔
84
                        t.maxColumnLengths[colIdx] = longestLineLen
1✔
85
                }
1✔
86
        }
87
}
88

89
// reBalanceMaxMergedColumnLengths tries to re-balance the merged column lengths
90
// across all columns. It does this from the lowest end index to the highest,
91
// and within that set from the highest start index to the lowest. It
92
// distributes the length across the columns not already exceeding the average.
93
func (t *Table) reBalanceMaxMergedColumnLengths() {
1✔
94
        endIndexKeys, startIndexKeysMap := getSortedKeys(t.maxMergedColumnLengths)
1✔
95
        middleSepLen := text.StringWidthWithoutEscSequences(t.style.Box.MiddleSeparator)
1✔
96
        for _, endIndexKey := range endIndexKeys {
2✔
97
                startIndexKeys := startIndexKeysMap[endIndexKey]
1✔
98
                for idx := len(startIndexKeys) - 1; idx >= 0; idx-- {
2✔
99
                        startIndexKey := startIndexKeys[idx]
1✔
100
                        columnBalanceMap := map[int]struct{}{}
1✔
101
                        for index := startIndexKey; index <= endIndexKey; index++ {
2✔
102
                                columnBalanceMap[index] = struct{}{}
1✔
103
                        }
1✔
104
                        mergedColumnLength := t.maxMergedColumnLengths[endIndexKey][startIndexKey] -
1✔
105
                                ((len(columnBalanceMap) - 1) * middleSepLen)
1✔
106

1✔
107
                        // keep reducing the set of columns until the remainder are the ones less than
1✔
108
                        // the average of the remaining length (total merged length - all lengths > average)
1✔
109
                        for {
2✔
110
                                if mergedColumnLength <= 0 { // already exceeded the merged length
2✔
111
                                        columnBalanceMap = map[int]struct{}{}
1✔
112
                                        break
1✔
113
                                }
114
                                numMergedColumns := len(columnBalanceMap)
1✔
115
                                maxLengthSplitAcrossColumns := mergedColumnLength / numMergedColumns
1✔
116
                                mapReduced := false
1✔
117
                                for mergedColumn := range columnBalanceMap {
2✔
118
                                        maxColumnLength := t.maxColumnLengths[mergedColumn]
1✔
119
                                        if maxColumnLength >= maxLengthSplitAcrossColumns {
2✔
120
                                                mapReduced = true
1✔
121
                                                mergedColumnLength -= maxColumnLength
1✔
122
                                                delete(columnBalanceMap, mergedColumn)
1✔
123
                                        }
1✔
124
                                }
125
                                if !mapReduced {
2✔
126
                                        break
1✔
127
                                }
128
                        }
129

130
                        // act on any remaining columns that need balancing
131
                        if len(columnBalanceMap) > 0 {
2✔
132
                                // remove the max column sizes from the remaining amount to balance, then
1✔
133
                                // share out the remainder amongst the columns.
1✔
134
                                numRebalancedColumns := len(columnBalanceMap)
1✔
135
                                balanceColumns := make([]int, 0, numRebalancedColumns)
1✔
136
                                for balanceColumn := range columnBalanceMap {
2✔
137
                                        mergedColumnLength -= t.maxColumnLengths[balanceColumn]
1✔
138
                                        balanceColumns = append(balanceColumns, balanceColumn)
1✔
139
                                }
1✔
140
                                // pad out the columns one by one
141
                                sort.Ints(balanceColumns)
1✔
142
                                columnLengthRemaining := mergedColumnLength
1✔
143
                                columnsRemaining := numRebalancedColumns
1✔
144
                                for index := 0; index < numRebalancedColumns; index++ {
2✔
145
                                        balancedSpace := columnLengthRemaining / columnsRemaining
1✔
146
                                        balanceColumn := balanceColumns[index]
1✔
147
                                        t.maxColumnLengths[balanceColumn] += balancedSpace
1✔
148
                                        columnLengthRemaining -= balancedSpace
1✔
149
                                        columnsRemaining--
1✔
150
                                }
1✔
151
                        }
152
                }
153
        }
154
}
155

156
func (t *Table) initForRender(mode renderMode) {
1✔
157
        t.renderMode = mode
1✔
158

1✔
159
        // pick a default style if none was set until now
1✔
160
        t.Style()
1✔
161

1✔
162
        // reset rendering state
1✔
163
        t.reset()
1✔
164

1✔
165
        // cache the direction modifier to avoid repeated calls
1✔
166
        t.directionModifier = t.style.Format.Direction.Modifier()
1✔
167

1✔
168
        // initialize the column configs and normalize them
1✔
169
        t.initForRenderColumnConfigs()
1✔
170

1✔
171
        // initialize and stringify all the raw rows
1✔
172
        t.initForRenderRows()
1✔
173

1✔
174
        // find the longest continuous line in each column
1✔
175
        t.initForRenderColumnLengths()
1✔
176
        t.initForRenderMaxRowLength()
1✔
177
        t.initForRenderPaddedColumns()
1✔
178

1✔
179
        // generate a separator row and calculate maximum row length
1✔
180
        t.initForRenderRowSeparator()
1✔
181

1✔
182
        // reset the counter for the number of lines rendered
1✔
183
        t.numLinesRendered = 0
1✔
184
}
1✔
185

186
func (t *Table) initForRenderColumnConfigs() {
1✔
187
        t.columnConfigMap = map[int]ColumnConfig{}
1✔
188
        for _, colCfg := range t.columnConfigs {
2✔
189
                // find the column number if none provided; this logic can work only if
1✔
190
                // a header row is present and has a column with the given name
1✔
191
                if colCfg.Number == 0 {
2✔
192
                        for _, row := range t.rowsHeaderRaw {
2✔
193
                                colCfg.Number = row.findColumnNumber(colCfg.Name)
1✔
194
                                if colCfg.Number > 0 {
2✔
195
                                        break
1✔
196
                                }
197
                        }
198
                }
199
                if colCfg.Number > 0 {
2✔
200
                        t.columnConfigMap[colCfg.Number-1] = colCfg
1✔
201
                }
1✔
202
        }
203
}
204

205
func (t *Table) initForRenderColumnLengths() {
1✔
206
        t.maxColumnLengths = make([]int, t.numColumns)
1✔
207
        t.maxMergedColumnLengths = make(map[int]map[int]int)
1✔
208
        t.extractMaxColumnLengths(t.rowsHeader, renderHint{isHeaderRow: true})
1✔
209
        t.extractMaxColumnLengths(t.rows, renderHint{})
1✔
210
        t.extractMaxColumnLengths(t.rowsFooter, renderHint{isFooterRow: true})
1✔
211

1✔
212
        // increase the column lengths if any are under the limits
1✔
213
        for colIdx := range t.maxColumnLengths {
2✔
214
                minWidth := t.getColumnWidthMin(colIdx)
1✔
215
                if minWidth > 0 && t.maxColumnLengths[colIdx] < minWidth {
2✔
216
                        t.maxColumnLengths[colIdx] = minWidth
1✔
217
                }
1✔
218
        }
219
        t.reBalanceMaxMergedColumnLengths()
1✔
220
}
221

222
func (t *Table) initForRenderHideColumns() {
1✔
223
        if !t.hasHiddenColumns() {
2✔
224
                return
1✔
225
        }
1✔
226
        colIdxMap := t.hideColumns()
1✔
227

1✔
228
        // re-create columnIsNonNumeric with new column indices
1✔
229
        columnIsNonNumeric := make([]bool, t.numColumns)
1✔
230
        for oldColIdx, nonNumeric := range t.columnIsNonNumeric {
2✔
231
                if newColIdx, ok := colIdxMap[oldColIdx]; ok {
2✔
232
                        columnIsNonNumeric[newColIdx] = nonNumeric
1✔
233
                }
1✔
234
        }
235
        t.columnIsNonNumeric = columnIsNonNumeric
1✔
236

1✔
237
        // re-create columnConfigMap with new column indices
1✔
238
        columnConfigMap := make(map[int]ColumnConfig)
1✔
239
        for oldColIdx, cc := range t.columnConfigMap {
2✔
240
                if newColIdx, ok := colIdxMap[oldColIdx]; ok {
2✔
241
                        columnConfigMap[newColIdx] = cc
1✔
242
                }
1✔
243
        }
244
        t.columnConfigMap = columnConfigMap
1✔
245
}
246

247
func (t *Table) initForRenderMaxRowLength() {
1✔
248
        t.maxRowLength = 0
1✔
249
        if t.autoIndex {
2✔
250
                t.maxRowLength += text.StringWidthWithoutEscSequences(t.style.Box.PaddingLeft)
1✔
251
                t.maxRowLength += len(fmt.Sprint(len(t.rows)))
1✔
252
                t.maxRowLength += text.StringWidthWithoutEscSequences(t.style.Box.PaddingRight)
1✔
253
                if t.style.Options.SeparateColumns {
2✔
254
                        t.maxRowLength += text.StringWidthWithoutEscSequences(t.style.Box.MiddleSeparator)
1✔
255
                }
1✔
256
        }
257
        if t.style.Options.SeparateColumns {
2✔
258
                t.maxRowLength += text.StringWidthWithoutEscSequences(t.style.Box.MiddleSeparator) * (t.numColumns - 1)
1✔
259
        }
1✔
260
        for _, maxColumnLength := range t.maxColumnLengths {
2✔
261
                maxColumnLength += text.StringWidthWithoutEscSequences(t.style.Box.PaddingLeft + t.style.Box.PaddingRight)
1✔
262
                t.maxRowLength += maxColumnLength
1✔
263
        }
1✔
264
        if t.style.Options.DrawBorder {
2✔
265
                t.maxRowLength += text.StringWidthWithoutEscSequences(t.style.Box.Left + t.style.Box.Right)
1✔
266
        }
1✔
267
}
268

269
func (t *Table) initForRenderPaddedColumns() {
1✔
270
        paddingSize := t.style.Size.WidthMin - t.maxRowLength
1✔
271
        for paddingSize > 0 {
2✔
272
                // distribute padding equally among all columns
1✔
273
                numColumnsPadded := 0
1✔
274
                for colIdx := 0; paddingSize > 0 && colIdx < t.numColumns; colIdx++ {
2✔
275
                        colWidthMax := t.getColumnWidthMax(colIdx)
1✔
276
                        if colWidthMax == 0 || t.maxColumnLengths[colIdx] < colWidthMax {
2✔
277
                                t.maxColumnLengths[colIdx]++
1✔
278
                                numColumnsPadded++
1✔
279
                                paddingSize--
1✔
280
                        }
1✔
281
                }
282

283
                // avoid endless looping because all columns are at max size and cannot
284
                // be expanded any further
285
                if numColumnsPadded == 0 {
2✔
286
                        break
1✔
287
                }
288
        }
289
}
290

291
func (t *Table) initForRenderRows() {
1✔
292
        // auto-index: calc the index column's max length
1✔
293
        t.autoIndexVIndexMaxLength = len(fmt.Sprint(len(t.rowsRaw)))
1✔
294

1✔
295
        // filter the rows as requested (before stringification and sorting)
1✔
296
        filteredRows := t.initForRenderFilterRows()
1✔
297

1✔
298
        // stringify the filtered rows
1✔
299
        t.numColumns = 0
1✔
300
        t.rows = t.initForRenderRowsStringify(filteredRows, renderHint{})
1✔
301
        t.rowsFooter = t.initForRenderRowsStringify(t.rowsFooterRaw, renderHint{isFooterRow: true})
1✔
302
        t.rowsHeader = t.initForRenderRowsStringify(t.rowsHeaderRaw, renderHint{isHeaderRow: true})
1✔
303

1✔
304
        // sort the rows as requested
1✔
305
        t.initForRenderSortRows()
1✔
306

1✔
307
        // find the row colors (if any)
1✔
308
        t.initForRenderRowPainterColors()
1✔
309

1✔
310
        // suppress columns without any content
1✔
311
        t.initForRenderSuppressColumns()
1✔
312

1✔
313
        // strip out hidden columns
1✔
314
        t.initForRenderHideColumns()
1✔
315
}
1✔
316

317
// initForRenderFilterRows filters the raw rows and returns the filtered rows.
318
// It does not modify t.rowsRaw to preserve the original data.
319
func (t *Table) initForRenderFilterRows() []Row {
1✔
320
        // Get filtered indices from original rows - don't modify t.rowsRaw
1✔
321
        filteredIndices := t.getFilteredRowIndices()
1✔
322

1✔
323
        // Create filtered rows from original rows (create a copy, don't modify t.rowsRaw)
1✔
324
        filteredRows := make([]Row, len(filteredIndices))
1✔
325
        for idx, origIdx := range filteredIndices {
2✔
326
                if origIdx < len(t.rowsRaw) {
2✔
327
                        origRow := t.rowsRaw[origIdx]
1✔
328
                        filteredRow := make(Row, len(origRow))
1✔
329
                        copy(filteredRow, origRow)
1✔
330
                        filteredRows[idx] = filteredRow
1✔
331
                }
1✔
332
        }
333

334
        // Store filtered indices for use in sorting, row painter, and separators
335
        t.filteredRowIndices = filteredIndices
1✔
336

1✔
337
        // Update separators map to reflect filtered indices
1✔
338
        if len(t.separators) > 0 {
2✔
339
                newSeparators := make(map[int]bool)
1✔
340
                for origIdx := range t.separators {
2✔
341
                        // find the position of origIdx in filteredRowIndices
1✔
342
                        for newIdx, filteredIdx := range filteredIndices {
2✔
343
                                if filteredIdx == origIdx {
2✔
344
                                        newSeparators[newIdx] = true
1✔
345
                                        break
1✔
346
                                }
347
                        }
348
                }
349
                t.separators = newSeparators
1✔
350
        }
351

352
        return filteredRows
1✔
353
}
354

355
func (t *Table) initForRenderRowsStringify(rows []Row, hint renderHint) []rowStr {
1✔
356
        rowsStr := make([]rowStr, len(rows))
1✔
357
        for idx, row := range rows {
2✔
358
                hint.rowNumber = idx + 1
1✔
359
                rowsStr[idx] = t.analyzeAndStringify(row, hint)
1✔
360
        }
1✔
361
        return rowsStr
1✔
362
}
363

364
func (t *Table) initForRenderRowPainterColors() {
1✔
365
        if !t.hasRowPainter() {
2✔
366
                return
1✔
367
        }
1✔
368

369
        // generate the colors for the final rows (after filtering and sorting)
370
        // rowsColors will be indexed by the final position in t.rows
371
        t.rowsColors = make([]text.Colors, len(t.rows))
1✔
372

1✔
373
        // For each final position, find the original row index
1✔
374
        for finalPos := range t.rows {
2✔
375
                var origIdx int
1✔
376

1✔
377
                if len(t.filteredRowIndices) > 0 {
2✔
378
                        // Rows were filtered
1✔
379
                        if len(t.sortedRowIndices) > 0 {
2✔
380
                                // Rows were also sorted: finalPos -> sortedRowIndices[finalPos] -> filteredRowIndices[sortedIdx] -> origIdx
1✔
381
                                sortedIdx := t.sortedRowIndices[finalPos]
1✔
382
                                if sortedIdx < len(t.filteredRowIndices) {
2✔
383
                                        origIdx = t.filteredRowIndices[sortedIdx]
1✔
384
                                } else {
1✔
NEW
385
                                        continue // Invalid index
×
386
                                }
NEW
387
                        } else {
×
NEW
388
                                // Only filtered, not sorted: finalPos -> filteredRowIndices[finalPos] -> origIdx
×
NEW
389
                                if finalPos < len(t.filteredRowIndices) {
×
NEW
390
                                        origIdx = t.filteredRowIndices[finalPos]
×
NEW
391
                                } else {
×
NEW
392
                                        continue // Invalid index
×
393
                                }
394
                        }
NEW
395
                } else if len(t.sortedRowIndices) > 0 {
×
NEW
396
                        // Only sorted, not filtered: finalPos -> sortedRowIndices[finalPos] -> origIdx
×
NEW
397
                        origIdx = t.sortedRowIndices[finalPos]
×
NEW
398
                } else {
×
NEW
399
                        // No filtering or sorting: finalPos -> origIdx
×
NEW
400
                        origIdx = finalPos
×
UNCOV
401
                }
×
402

403
                if origIdx >= 0 && origIdx < len(t.rowsRaw) {
2✔
404
                        row := t.rowsRaw[origIdx]
1✔
405
                        if t.rowPainter != nil {
2✔
406
                                t.rowsColors[finalPos] = t.rowPainter(row)
1✔
407
                        } else if t.rowPainterWithAttributes != nil {
3✔
408
                                t.rowsColors[finalPos] = t.rowPainterWithAttributes(row, RowAttributes{
1✔
409
                                        Number:       origIdx + 1,
1✔
410
                                        NumberSorted: finalPos + 1,
1✔
411
                                })
1✔
412
                        }
1✔
413
                }
414
        }
415
}
416

417
func (t *Table) initForRenderRowSeparator() {
1✔
418
        // this is needed only for default render mode
1✔
419
        if t.renderMode != renderModeDefault {
2✔
420
                return
1✔
421
        }
1✔
422

423
        // init the separatorType -> separator-string map
424
        t.initForRenderRowSeparatorStrings()
1✔
425

1✔
426
        // init the separator-string -> separator-row map
1✔
427
        t.rowSeparators = make(map[string]rowStr, len(t.rowSeparatorStrings))
1✔
428
        paddingLength := text.StringWidthWithoutEscSequences(t.style.Box.PaddingLeft + t.style.Box.PaddingRight)
1✔
429
        for _, separator := range t.rowSeparatorStrings {
2✔
430
                t.rowSeparators[separator] = make(rowStr, t.numColumns)
1✔
431
                for colIdx, maxColumnLength := range t.maxColumnLengths {
2✔
432
                        t.rowSeparators[separator][colIdx] = text.RepeatAndTrim(separator, maxColumnLength+paddingLength)
1✔
433
                }
1✔
434
        }
435
}
436

437
func (t *Table) initForRenderRowSeparatorStrings() {
1✔
438
        // allocate and init only the separators that are needed
1✔
439
        t.rowSeparatorStrings = make(map[separatorType]string)
1✔
440
        addSeparatorType := func(st separatorType) {
2✔
441
                t.rowSeparatorStrings[st] = t.style.Box.middleHorizontal(st)
1✔
442
        }
1✔
443

444
        // for other render modes, we need all the separators
445
        if t.title != "" {
2✔
446
                addSeparatorType(separatorTypeTitleTop)
1✔
447
                addSeparatorType(separatorTypeTitleBottom)
1✔
448
        }
1✔
449
        if len(t.rowsHeader) > 0 || t.autoIndex {
2✔
450
                addSeparatorType(separatorTypeHeaderTop)
1✔
451
                addSeparatorType(separatorTypeHeaderBottom)
1✔
452
                if len(t.rowsHeader) > 1 {
2✔
453
                        addSeparatorType(separatorTypeHeaderMiddle)
1✔
454
                }
1✔
455
        }
456
        if len(t.rows) > 0 {
2✔
457
                addSeparatorType(separatorTypeRowTop)
1✔
458
                addSeparatorType(separatorTypeRowBottom)
1✔
459
                if len(t.rows) > 1 {
2✔
460
                        addSeparatorType(separatorTypeRowMiddle)
1✔
461
                }
1✔
462
        }
463
        if len(t.rowsFooter) > 0 || t.autoIndex {
2✔
464
                addSeparatorType(separatorTypeFooterTop)
1✔
465
                addSeparatorType(separatorTypeFooterBottom)
1✔
466
                if len(t.rowsFooter) > 1 {
2✔
467
                        addSeparatorType(separatorTypeFooterMiddle)
1✔
468
                }
1✔
469
        }
470
}
471

472
func (t *Table) initForRenderSortRows() {
1✔
473
        if len(t.sortBy) == 0 {
2✔
474
                return
1✔
475
        }
1✔
476

477
        // sort the rows
478
        t.sortedRowIndices = t.getSortedRowIndices()
1✔
479
        sortedRows := make([]rowStr, len(t.rows))
1✔
480
        for idx := range t.rows {
2✔
481
                sortedRows[idx] = t.rows[t.sortedRowIndices[idx]]
1✔
482
        }
1✔
483
        t.rows = sortedRows
1✔
484
}
485

486
func (t *Table) initForRenderSuppressColumns() {
1✔
487
        shouldSuppressColumn := func(colIdx int) bool {
2✔
488
                for _, row := range t.rows {
2✔
489
                        if colIdx < len(row) && row[colIdx] != "" {
2✔
490
                                // Columns may contain non-printable characters. For example
1✔
491
                                // the text.Direction modifiers. These should not be considered
1✔
492
                                // when deciding to suppress a column.
1✔
493
                                for _, r := range row[colIdx] {
2✔
494
                                        if unicode.IsPrint(r) {
2✔
495
                                                return false
1✔
496
                                        }
1✔
497
                                }
498
                                return true
1✔
499
                        }
500
                }
501
                return true
1✔
502
        }
503

504
        if t.suppressEmptyColumns {
2✔
505
                for colIdx := 0; colIdx < t.numColumns; colIdx++ {
2✔
506
                        if shouldSuppressColumn(colIdx) {
2✔
507
                                cc := t.columnConfigMap[colIdx]
1✔
508
                                cc.Hidden = true
1✔
509
                                t.columnConfigMap[colIdx] = cc
1✔
510
                        }
1✔
511
                }
512
        }
513
}
514

515
// reset initializes all the variables used to maintain rendering information
516
// that are written to in this file
517
func (t *Table) reset() {
1✔
518
        t.autoIndexVIndexMaxLength = 0
1✔
519
        t.columnConfigMap = nil
1✔
520
        t.columnIsNonNumeric = nil
1✔
521
        t.firstRowOfPage = true
1✔
522
        t.filteredRowIndices = nil
1✔
523
        t.maxColumnLengths = nil
1✔
524
        t.maxRowLength = 0
1✔
525
        t.numColumns = 0
1✔
526
        t.numLinesRendered = 0
1✔
527
        t.rowSeparators = nil
1✔
528
        t.rows = nil
1✔
529
        t.rowsColors = nil
1✔
530
        t.rowsFooter = nil
1✔
531
        t.rowsHeader = nil
1✔
532
        t.sortedRowIndices = nil
1✔
533
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc