Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions table/target_height_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,37 @@ func TestTargetHeightVisibleDataLinesWithSeparator(t *testing.T) {
assert.Greater(t, len(lines), 0, "table should not be empty")
}

// TestTargetHeightWithRowBorderNoMultilineRespectsHeight checks that enabling
// WithRowBorder on a non-multiline table does not cause the rendered output to
// exceed targetHeight when WithMinimumHeight is also set. Previously,
// visibleDataLines ignored separator lines in non-multiline mode, so
// calculatePadding added too many blank rows and the table overflowed.
func TestTargetHeightWithRowBorderNoMultilineRespectsHeight(t *testing.T) {
rows := []Row{
shortRow(1),
shortRow(2),
shortRow(3),
}

const target = 12

model := New([]Column{
NewColumn("id", "ID", 3),
NewColumn("content", "Content", 20),
}).
WithRows(rows).
WithRowBorder(true).
WithTargetHeight(target).
WithMinimumHeight(target)

rendered := model.View()
lines := strings.Split(rendered, "\n")

assert.LessOrEqual(t, len(lines), target,
"rendered height (%d lines) exceeded target (%d)", len(lines), target)
assert.Greater(t, len(lines), 0, "table should not be empty")
}

// TestTargetHeightNoFooterOnSinglePage checks that no page-count footer is
// rendered when all rows fit on a single page.
func TestTargetHeightNoFooterOnSinglePage(t *testing.T) {
Expand Down
15 changes: 12 additions & 3 deletions table/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,21 @@ import (
)

// visibleDataLines returns the total terminal lines occupied by visible rows in
// the range [startRowIndex, endRowIndex]. When multiline is disabled every row
// is one line, so the result equals endRowIndex - startRowIndex + 1.
// the range [startRowIndex, endRowIndex], including any separator lines between
// rows when WithRowBorder is active.
func (m *Model) visibleDataLines(startRowIndex, endRowIndex int) int {
numRows := endRowIndex - startRowIndex + 1

if !m.multiline || numRows <= 0 {
if numRows <= 0 {
return numRows
}

if !m.multiline {
if m.rowSeparator {
// Each pair of adjacent rows has one separator line between them.
return 2*numRows - 1
}

return numRows
}

Expand Down
8 changes: 4 additions & 4 deletions table/view_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1959,9 +1959,10 @@ func TestOuterBorderTrueMatchesDefault(t *testing.T) {
}

func TestRowBorderNoSeparatorBeforePaddingRows(t *testing.T) {
// WithMinimumHeight(7) with 2 data rows produces 1 padding row.
// The separator should appear between the two data rows but NOT
// between the last data row and the blank padding row.
// WithMinimumHeight(7) with 2 data rows and 1 separator between them
// occupies 3 data lines; header=3, bottom border=1 → total=7=minimumHeight.
// No blank padding row is needed because the separators are now counted
// as data lines, so the budget is already satisfied.
model := New([]Column{
NewColumn("1", "1", 4),
NewColumn("2", "2", 4),
Expand All @@ -1976,7 +1977,6 @@ func TestRowBorderNoSeparatorBeforePaddingRows(t *testing.T) {
┃ a┃ b┃
┣━━━━╋━━━━┫
┃ c┃ d┃
┃ ┃ ┃
┗━━━━┻━━━━┛`

rendered := model.View()
Expand Down
Loading