From 9fc5e014191f41d4b5dbd1080b56841da732d913 Mon Sep 17 00:00:00 2001 From: LeSingh1 Date: Fri, 12 Jun 2026 00:09:48 -0700 Subject: [PATCH] fix(table): clamp cursor to 0 when SetRows is called with empty slice When SetRows was called with an empty rows slice, len(m.rows)-1 evaluated to -1, causing cursor to be set to -1. Subsequent calls to Cursor() would return -1, which is out of bounds and breaks callers that expect a valid index. The fix guards for the empty case and resets cursor to 0, consistent with the initial state of a new table. The existing shrink-to-fewer-rows guard is preserved for the non-empty case. Adds a regression test covering both the empty-rows reset and the previously-tested shrink case. --- table/cursor_shrink_test.go | 42 +++++++++++++++++++++++++++++++++++++ table/table.go | 4 +++- 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 table/cursor_shrink_test.go diff --git a/table/cursor_shrink_test.go b/table/cursor_shrink_test.go new file mode 100644 index 000000000..62394327f --- /dev/null +++ b/table/cursor_shrink_test.go @@ -0,0 +1,42 @@ +package table + +import ( + "testing" +) + +func TestSetRows_CursorClampsToZeroOnEmpty(t *testing.T) { + cols := []Column{{Title: "Name", Width: 10}} + rows := []Row{{"a"}, {"b"}, {"c"}} + tbl := New(WithColumns(cols), WithRows(rows), WithHeight(5)) + + // Move to last row + tbl.GotoBottom() + if tbl.Cursor() != 2 { + t.Fatalf("expected cursor at 2, got %d", tbl.Cursor()) + } + + // Replace with empty rows + tbl.SetRows([]Row{}) + + got := tbl.Cursor() + if got < 0 { + t.Fatalf("SetRows(empty): Cursor() = %d, want >= 0 (got negative cursor on empty table)", got) + } +} + +func TestSetRows_CursorClampsOnShrink(t *testing.T) { + cols := []Column{{Title: "Name", Width: 10}} + rows := []Row{{"a"}, {"b"}, {"c"}} + tbl := New(WithColumns(cols), WithRows(rows), WithHeight(5)) + + // Move to last row (index 2) + tbl.GotoBottom() + + // Shrink to 1 row + tbl.SetRows([]Row{{"x"}}) + + got := tbl.Cursor() + if got != 0 { + t.Fatalf("SetRows(fewer rows): Cursor() = %d, want 0", got) + } +} diff --git a/table/table.go b/table/table.go index 39f9a4003..e75910618 100644 --- a/table/table.go +++ b/table/table.go @@ -306,7 +306,9 @@ func (m Model) Columns() []Column { func (m *Model) SetRows(r []Row) { m.rows = r - if m.cursor > len(m.rows)-1 { + if len(m.rows) == 0 { + m.cursor = 0 + } else if m.cursor > len(m.rows)-1 { m.cursor = len(m.rows) - 1 }