datatable

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 7, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package datatable is widgets.Table plus row navigation — InkUI's "DataTable". It doesn't own sorting or filtering (the same reasoning tabs doesn't own tab content): the caller passes in already-sorted/ filtered Headers/Rows and DataTable only adds cursor-based row highlighting and a SelectedMsg on top of that.

Example

A datatable draws a header and a window of rows, and tracks the cursor.

package main

import (
	"fmt"
	"strings"

	"github.com/ows4444/tui"
	"github.com/ows4444/tui/ansi"
	"github.com/ows4444/tui/datatable"
)

func main() {
	m := datatable.New([]string{"name", "qty"}, [][]string{{"apple", "3"}, {"pear", "5"}, {"plum", "8"}})
	m.Height = 3
	m, _ = m.Update(tui.Key{Type: tui.KeyDown})
	for _, line := range strings.Split(ansi.StripANSI(m.View()), "\n") {
		fmt.Println(strings.TrimRight(line, " "))
	}
	fmt.Println("cursor row:", m.Cursor())
}
Output:
name   qty
  ──────────
  apple  3
> pear   5
  plum   8
cursor row: 1

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type KeyMap

type KeyMap struct {
	Up, Down         keymap.Binding
	PageUp, PageDown keymap.Binding
	Top, Bottom      keymap.Binding
	// Select confirms the row under the cursor (SelectedMsg).
	Select keymap.Binding
	// Sort orders the rows by the current column, toggling ascending and
	// descending on repeat.
	Sort keymap.Binding
	// Left and Right move the current column, scrolling wide tables.
	Left, Right keymap.Binding
}

KeyMap names the keys Update reacts to.

func DefaultKeyMap

func DefaultKeyMap() KeyMap

DefaultKeyMap returns the default keys: arrows, PgUp/PgDn, Home/End, Enter, "s" to sort, Left/Right for columns.

type Model

type Model struct {
	Headers []string
	Rows    [][]string
	Theme   theme.Theme

	// Raw, when true, draws Headers and Rows unchanged. By default every
	// header and cell is sanitised (ansi.Sanitize): escape sequences and
	// control characters are removed, so untrusted cell text cannot move the
	// cursor, clear the screen or write the clipboard.
	Raw bool

	// Height is the number of data rows shown at once (header and divider
	// not counted). Zero means "derive it": once the Model has seen a
	// tui.ResizeMsg it shows ResizeMsg.Height minus the two header/divider
	// lines (at least one row) and keeps the cursor visible; before any
	// ResizeMsg, zero renders every row. Column widths are computed from
	// the visible window only, so View costs O(Height), not O(len(Rows)).
	Height int

	// Width is the number of columns available to the table. Zero means
	// "no limit": every column is drawn. When the columns are wider than
	// Width, only a horizontal window of them is drawn and KeyMap.Left/Right
	// move the current column, scrolling the window to keep it visible.
	Width int

	// KeyMap holds the keys Update reacts to; New fills it with
	// DefaultKeyMap. A Model built as a struct literal with no KeyMap set
	// uses DefaultKeyMap.
	KeyMap KeyMap

	// Mouse, when true, makes Update handle tui.MouseEvent inside Bounds:
	// the wheel scrolls by WheelStep rows and a left click selects the row
	// under the pointer. The zero value ignores the mouse.
	Mouse bool
	// Bounds is the screen rectangle where the app draws the table (its
	// top-left cell is the header line). The app sets it.
	Bounds hittest.Rect
	// Name is the layout.Named node the table is placed in; WithLayout
	// reads Bounds from that node's rectangle so the app sets no Bounds.
	Name string
	// WheelStep is the rows scrolled per wheel notch; zero means 3.
	WheelStep int

	// ColumnWidths fixes column widths for LayoutNode: entry i, when positive,
	// is the width of column i; zero, a negative entry or a missing entry
	// leaves that column at its natural (content) width. Fixed widths do not
	// depend on the rows, so they stay constant while scrolling and cost no
	// row scan. Cells wider than their column are clipped with an ellipsis.
	// View is unaffected.
	ColumnWidths []int
	// contains filtered or unexported fields
}

Model is a bordered table with keyboard-navigable row selection: Up/Down move the cursor, Enter confirms the row under it.

func New

func New(headers []string, rows [][]string) Model

New builds a Model from headers and rows, with the cursor on row 0.

func (Model) Bindings

func (m Model) Bindings() []keymap.Binding

Bindings returns the active bindings, for help widgets.

func (Model) Cursor

func (m Model) Cursor() int

Cursor returns the index of the row currently under the cursor.

func (Model) DrawCells

func (m Model) DrawCells(buf *cellbuf.Buffer, r cellbuf.Rect)

DrawCells draws the table into the region r of buf, as View would show it (it implements tui.CellDrawer): the header, the divider and the visible rows with the cursor row highlighted, each cell written straight into the grid, with no row or table string built. Column widths come from the width cache when the window is the whole table and every cell is clean, and from the visible rows otherwise, as View computes them. With Raw set, or when a style cannot be drawn in the grid, it draws the View string instead.

func (Model) LayoutNode

func (m Model) LayoutNode() layout.Node

LayoutNode adapts the table to a layout.Node. Measure reports its natural size: the columns at their content widths (two spaces apart) by one row per record plus the header and divider. Render fits the table to the allotted Size: when too narrow it shrinks the widest columns first and truncates cells with an ellipsis, and when too short it pins the header and shows a window of rows that keeps the cursor row visible. The cursor row keeps its highlight; the Model is not changed.

func (Model) Linearize

func (m Model) Linearize() string

Linearize renders the table as plain text for accessible output (see tui.Linearizer): one self-contained line per row pairing each header with its cell, e.g. "Row 2 of 10: Name: x, Status: y", with ", selected" appended on the cursor row. No padding, dividers or styling.

func (Model) Offset

func (m Model) Offset() int

Offset returns the index of the first visible row.

func (*Model) SetCursor

func (m *Model) SetCursor(i int)

SetCursor moves the cursor to row i, clamped to a valid index (or 0 with no rows).

func (*Model) SetRows

func (m *Model) SetRows(rows [][]string)

SetRows replaces the rows and invalidates the cached natural column widths. Call it (rather than assigning Rows) after editing cells in place, which the cache cannot see. The cursor is clamped to the new rows.

func (Model) SetTheme

func (m Model) SetTheme(t theme.Theme) Model

SetTheme returns m with t applied. It makes Model a tui.ThemeSetter, so a root model can forward the Program's theme (see tui.WithTheme).

func (Model) Sorted

func (m Model) Sorted() (col int, desc, ok bool)

Sorted reports the sorted column and direction; ok is false while the rows are in the caller's order.

func (Model) Tokens

func (m Model) Tokens() theme.Tokens

Tokens returns the colour tokens the widget renders with: its theme's roles, overridden by any theme.WithTokens(theme.ComponentDataTable, ...) and then by WithTokens.

func (Model) Update

func (m Model) Update(msg tui.Msg) (Model, tui.Cmd)

Update moves the cursor on Up/Down and confirms the row under it on Enter, returning a Cmd that delivers SelectedMsg. Non-Key Msgs and an empty Model are no-ops.

func (Model) View

func (m Model) View() string

View renders the table with the row under the cursor highlighted, via widgets.TableRows — the same column-width computation, divider, and cell padding widgets.Table uses, so the two never drift apart.

func (Model) WithLayout

func (m Model) WithLayout(root layout.Node, s layout.Size) Model

WithLayout sets Bounds to the rectangle of the layout node named Name in the tree under root laid out at s (typically the last frame's tree and size). With no Name or no such node Bounds is left unchanged.

func (Model) WithTokens

func (m Model) WithTokens(tok theme.Tokens) Model

WithTokens returns m with tok as its per-instance colour override. Nil fields inherit from the theme, so only the roles tok names change; the theme and every other widget are untouched. A second call replaces the first.

type SelectedMsg

type SelectedMsg struct {
	Row   int
	Cells []string
}

SelectedMsg is delivered (via the Cmd Update returns) when the row under the cursor is confirmed with Enter.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL