Skip to content

Commit d231906

Browse files
fix(table): prevent columns from shrinking to zero width (#671)
1 parent d19c46c commit d231906

3 files changed

Lines changed: 162 additions & 136 deletions

File tree

table/resizing.go

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -230,12 +230,19 @@ func (r *resizer) expandTableWidth() (colWidths []int) {
230230
return
231231
}
232232

233+
// minWidth returns the minimum width floor for a column: horizontal padding
234+
// plus at least 1 to ensure the "…" truncation marker or one character is
235+
// always visible. A column must never shrink below this floor.
236+
func (r *resizer) minWidth(j int) int {
237+
return r.xPaddingForCol(j) + max(r.columns[j].min, 1)
238+
}
239+
233240
// shrinkTableWidth shrinks the table width.
234241
func (r *resizer) shrinkTableWidth() (colWidths []int) {
235242
colWidths = r.maxColumnWidths()
236243

237244
// Cut width of columns that are way too big.
238-
shrinkBiggestColumns := func(veryBigOnly bool) {
245+
shrinkBiggestColumns := func(veryBigOnly, useFloor bool) {
239246
for {
240247
totalWidth := sum(colWidths) + r.totalHorizontalBorder()
241248
if totalWidth <= r.tableWidth {
@@ -249,6 +256,9 @@ func (r *resizer) shrinkTableWidth() (colWidths []int) {
249256
if width == r.columns[j].fixedWidth {
250257
continue
251258
}
259+
if useFloor && width <= r.minWidth(j) {
260+
continue
261+
}
252262
if veryBigOnly {
253263
if width >= (r.tableWidth/2) && width > bigColumnWidth { //nolint:mnd
254264
bigColumnWidth = width
@@ -270,7 +280,7 @@ func (r *resizer) shrinkTableWidth() (colWidths []int) {
270280
}
271281

272282
// Cut width of columns that differ the most from the median.
273-
shrinkToMedian := func() {
283+
shrinkToMedian := func(useFloor bool) {
274284
for {
275285
totalWidth := sum(colWidths) + r.totalHorizontalBorder()
276286
if totalWidth <= r.tableWidth {
@@ -284,6 +294,9 @@ func (r *resizer) shrinkTableWidth() (colWidths []int) {
284294
if width == r.columns[j].fixedWidth {
285295
continue
286296
}
297+
if useFloor && width <= r.minWidth(j) {
298+
continue
299+
}
287300
diffToMedian := width - r.columns[j].median
288301
if diffToMedian > 0 && diffToMedian > biggestDiffToMedian {
289302
biggestDiffToMedian = diffToMedian
@@ -298,9 +311,19 @@ func (r *resizer) shrinkTableWidth() (colWidths []int) {
298311
}
299312
}
300313

301-
shrinkBiggestColumns(true)
302-
shrinkToMedian()
303-
shrinkBiggestColumns(false)
314+
// First pass: shrink respecting column minimum widths so short columns
315+
// don't collapse to zero.
316+
shrinkBiggestColumns(true, true)
317+
shrinkToMedian(true)
318+
shrinkBiggestColumns(false, true)
319+
320+
// If the table is still too wide (e.g. impossible width budgets like
321+
// Width(1)), fall back to unreserved shrinking without a floor.
322+
if sum(colWidths)+r.totalHorizontalBorder() > r.tableWidth {
323+
shrinkBiggestColumns(true, false)
324+
shrinkToMedian(false)
325+
shrinkBiggestColumns(false, false)
326+
}
304327

305328
r.expandRowHeights(colWidths)
306329

0 commit comments

Comments
 (0)