[GH-ISSUE #498] Invalid selection in tables with rows of different lengths #363

Closed
opened 2026-03-04 01:04:20 +03:00 by kerem · 1 comment
Owner

Originally created by @rlmaers on GitHub (Sep 10, 2020).
Original GitHub issue: https://github.com/rivo/tview/issues/498

Background

I'm working on an application that use the table primitive and where each row might have different number of columns, and I've stumbled upon a bug regarding selection.

Description

The following code creates a table with an non-selectable header row with one column and a selectable second row with two columns. When pressing up, the initial selection of the second row simply disappears.

package main

import "github.com/rivo/tview"

func main() {
	table := tview.NewTable()
	table.SetSelectable(true, false)
	table.SetCell(0, 0, tview.NewTableCell("A").SetSelectable(false))
	table.SetCell(1, 0, tview.NewTableCell("B").SetSelectable(true))
	table.SetCell(1, 1, tview.NewTableCell("C").SetSelectable(true))
	table.Select(1, 0)

	if err := tview.NewApplication().SetRoot(table, true).Run(); err != nil {
		panic(err)
	}
}

Cause

I believe the bug (in this case) is caused by the following code in the Draw method.

// If this cell is not selectable, find the next one.
if t.rowsSelectable || t.columnsSelectable {
	if t.selectedColumn < 0 {
		t.selectedColumn = 0
	}
	if t.selectedRow < 0 {
		t.selectedRow = 0
	}
	for t.selectedRow < len(t.cells) {
		cell := getCell(t.selectedRow, t.selectedColumn)
		if cell == nil || !cell.NotSelectable {
			break
		}
		t.selectedColumn++
		if t.selectedColumn > t.lastColumn {
			t.selectedColumn = 0
			t.selectedRow++
		}
	}
}

After pressing up both t.selectedRow == -1 and t.selectedColumn == t.lastColumn are true before this code is executed. On the loops first iteration we have getCell(0, 1) == nil because the first row only has one column, and the loop is terminated resulting in an invalid selection.

Workaround

A simple workaround is to make sure that all rows have the same number of columns, and inserting dummy columns where needed.

Fix

I'm not that familiar with the library, so I might be wrong; but a possible fix is probably to replace the static value t.lastColumn with the dynamic value len(t.cells[t.selectedRow])-1 in all appropriate places.


I understand if fixing this issue is not prioritized given that there's a simple workaround.

Originally created by @rlmaers on GitHub (Sep 10, 2020). Original GitHub issue: https://github.com/rivo/tview/issues/498 # Background I'm working on an application that use the table primitive and where each row might have different number of columns, and I've stumbled upon a bug regarding selection. # Description The following code creates a table with an non-selectable header row with one column and a selectable second row with two columns. When pressing up, the initial selection of the second row simply disappears. ```go package main import "github.com/rivo/tview" func main() { table := tview.NewTable() table.SetSelectable(true, false) table.SetCell(0, 0, tview.NewTableCell("A").SetSelectable(false)) table.SetCell(1, 0, tview.NewTableCell("B").SetSelectable(true)) table.SetCell(1, 1, tview.NewTableCell("C").SetSelectable(true)) table.Select(1, 0) if err := tview.NewApplication().SetRoot(table, true).Run(); err != nil { panic(err) } } ``` # Cause I believe the bug (in this case) is caused by the following code in the `Draw` method. ```go // If this cell is not selectable, find the next one. if t.rowsSelectable || t.columnsSelectable { if t.selectedColumn < 0 { t.selectedColumn = 0 } if t.selectedRow < 0 { t.selectedRow = 0 } for t.selectedRow < len(t.cells) { cell := getCell(t.selectedRow, t.selectedColumn) if cell == nil || !cell.NotSelectable { break } t.selectedColumn++ if t.selectedColumn > t.lastColumn { t.selectedColumn = 0 t.selectedRow++ } } } ``` After pressing up both `t.selectedRow == -1` and `t.selectedColumn == t.lastColumn` are true before this code is executed. On the loops first iteration we have `getCell(0, 1) == nil` because the first row only has one column, and the loop is terminated resulting in an invalid selection. # Workaround A simple workaround is to make sure that all rows have the same number of columns, and inserting dummy columns where needed. # Fix I'm not that familiar with the library, so I might be wrong; but a possible fix is probably to replace the static value `t.lastColumn` with the dynamic value `len(t.cells[t.selectedRow])-1` in all appropriate places. --- I understand if fixing this issue is not prioritized given that there's a simple workaround.
kerem closed this issue 2026-03-04 01:04:20 +03:00
Author
Owner

@rivo commented on GitHub (Dec 4, 2020):

Thanks for letting me know about this. There were still bugs in finding the next selectable cell. The latest commit should resolve your problem (and hopefully similar other ones, too).

<!-- gh-comment-id:738963909 --> @rivo commented on GitHub (Dec 4, 2020): Thanks for letting me know about this. There were still bugs in finding the next selectable cell. The latest commit should resolve your problem (and hopefully similar other ones, too).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/tview#363
No description provided.