tview

repository·master·Indexed 12 days ago

https://github.com/rivo/tview

A Go package providing high-level, interactive widgets for building rich terminal-based user interfaces (TUIs). It includes components such as input forms, text views, data views (tables and trees), lists, and layout managers like Grid and Flexbox. tview features a central Application wrapper for event loop management, concurrency synchronization via QueueUpdate, and utilities for translating ANSI escape codes into internal style tags.

Tokens
24K
Snippets
83
Records
123
Agent score
94%

What's inside tview

  1. Overview of tview components

    master

    The tview package provides a variety of rich interactive widgets for terminal user interfaces, including:

    • Input forms: Text input, selections, checkboxes, and buttons.
    • Text views: Navigable multi-color text views and editable multi-line text areas.
    • Data views: Sophisticated navigable table views and flexible tree views.
    • Lists: Selectable lists.
    • Layouts: Grid, Flexbox, and page layouts.
    • Other components: Images, modal message windows, and an application wrapper.
  2. Use the Pages widget to manage multiple views

    master

    The Pages widget is a container for multiple Primitive objects (like forms, lists, or text areas) laid out on top of each other. It is commonly used as the root primitive of a tview application to allow switching between different full-screen views (e.g., a dashboard, a settings menu, and a login screen).

    Key behaviors:

    • Visibility: You can show multiple pages at once (overlapping) or use SwitchToPage to ensure only one page is visible.
    • Z-Order: Pages are drawn from back to front. Use SendToFront or SendToBack to change the drawing order.
    • Resizing: If resize is set to true when adding a page, the page's dimensions will automatically match the Pages container whenever it is drawn.
    • Focus: Pages manages focus delegation. When a page becomes visible, Pages can automatically delegate focus to that page's internal primitive.
    // Create a new Pages container
    pages := tview.NewPages()
    
    // Add a page that resizes with the container
    pages.AddPage("main", myPrimitive, true, true)
    
    // Switch to a different page (hides all others)
    pages.SwitchToPage("settings")
    
    // Show an additional page on top of the current one
    pages.ShowPage("overlay")
  3. Implement TableContent for custom data structures

    master

    To turn a Table into a view of your own data structure (e.g., for large datasets or virtual scrolling), implement the TableContent interface and pass it to Table.SetContent().

    Required Methods:

    • GetCell(row, column int) *TableCell: Returns the cell at the position or nil.
    • GetRowCount() int: Total number of rows.
    • GetColumnCount() int: Total number of columns.

    Optional Methods (Write operations): If you don't want to implement these, embed TableContentReadOnly in your struct to provide no-op implementations.

    • SetCell(row, column int, cell *TableCell)
    • RemoveRow(row int)
    • RemoveColumn(column int)
    • InsertRow(row int)
    • InsertColumn(column int)
    • Clear()
    type MyData struct {
    	TableContentReadOnly
    	Rows [][]string
    }
    
    func (m *MyData) GetRowCount() int {
    	return len(m.Rows)
    }
    
    func (m *MyData) GetColumnCount() int {
    	return len(m.Rows[0])
    }
    
    func (m *MyData) GetCell(row, column int) *tview.TableCell {
    	return tview.NewTableCell(m.Rows[row][column])
    }
    
    // Usage:
    table := tview.NewTable().SetContent(&MyData{Rows: myData})
  4. Use the List widget to display selectable items

    master

    The List widget displays rows of items that can be navigated and selected. Each item can have a main text, an optional secondary text (shown underneath), and an optional shortcut key (a rune) for direct selection.

    Navigation and Selection:

    • Movement: Use Down arrow/Tab to move down, Up arrow/Backtab to move up, Home for the first item, and End for the last item.
    • Pagination: Use Page down and Page up to scroll through the list.
    • Selection: Press Enter, Space, or the item's assigned shortcut key to select an item. Mouse clicks also trigger selection.
    • Scrolling: Use Left/Right arrows or mouse scrolling to move horizontally if the list is wider than the available space.

    Callbacks:

    • Use SetChangedFunc to be notified when the user navigates to a different item.
    • Use SetSelectedFunc to be notified when an item is selected.
    • Use SetDoneFunc to handle the Escape key.
    list := tview.NewList()
    list.AddItem("Main Text", "Secondary Text", 'a', func() {
        // This is called when the item is selected
    }).SetSelectedFunc(func(index int, mainText, secondaryText string, shortcut rune) {
        // This is also called when the item is selected
    }).SetChangedFunc(func(index int, mainText, secondaryText string, shortcut rune) {
        // This is called when the selection moves
    })
  5. Use the Frame widget to wrap primitives

    master

    The Frame widget is a wrapper that adds space (borders) around another Primitive. It allows you to display text in a header (above the primitive) or a footer (below the primitive). When a primitive is wrapped in a Frame, the Frame automatically adjusts the primitive's size to fit within the available inner space after accounting for borders and text lines.

    // Create a new frame wrapping a primitive (e.g., a TextView or Form)
    frame := tview.NewFrame(myPrimitive)
    
    // Add text to the header and footer
    frame.AddText("Header Text", true, tview.AlignCenter, tcell.ColorWhite)
    frame.AddText("Footer Text", false, tview.AlignRight, tcell.ColorRed)
  6. Use TextView for multi-line text display

    master
    The TextView widget is used to display multi-line, navigable text in a terminal UI. It supports features like text wrapping, scrolling, alignment (Left, Center, Right), and highlighting specific regions of text using tags. It can be configured to be scrollable or non-scrollable, and can automatically track the end of the text (useful for logs).
  7. Handle Checkbox interaction events

    master

    The Checkbox widget responds to both keyboard and mouse inputs.

    Keyboard Interaction

    • Space or Enter: Toggles the checked state.
    • Tab / Shift-Tab: Triggers the done callback (via SetDoneFunc) to move focus to the next/previous field.
    • Escape: Triggers the done callback to abort input.

    Mouse Interaction

    • Left Click: Toggles the checked state.
    • Left Down: Sets focus to the checkbox.

    Programmatic Control

    • SetDisabled(bool): Disables the checkbox, making it read-only and preventing interaction.
  8. How Grid scrolling and offsets work

    master

    If the grid's content exceeds its available space (e.g., due to SetMinSize), you can scroll through the grid using offsets.

    • SetOffset(rows, columns int): Manually sets the number of rows and columns to skip from the top-left.
    • GetOffset() (rows, columns int): Returns the current offset.

    Automatic Scrolling: When the grid has focus and no child primitive has focus, you can navigate the offset using:

    • Arrow Keys: Up/Down/Left/Right.
    • Vim Keys: h, j, k, l.
    • Navigation Keys: g (reset to 0,0), G (scroll to end), Home, End.

    Additionally, the grid automatically adjusts its offset to ensure a focused child primitive remains visible within the viewport.

  9. Use custom data backing for large Tables

    master
    By default, Table keeps all cells in memory. For extremely large datasets that cannot fit in memory, you can implement the TableContent interface and provide it to the table using SetContent(content TableContent). Passing nil to SetContent reverts the table to its default in-memory implementation.
  10. Configure TextView regions and highlights

    master

    You can define text regions within a TextView using square bracket tags. This allows you to apply specific styles or highlights to certain parts of the text.

    Region Syntax:

    • Start a region: ["regionID"]
    • End a region: [""]
    • Region IDs must match: [a-zA-Z0-9_,;: \-\.]+

    Example: We define a ["rg"]region[""] here.

    Highlighting:

    • Use Highlight(regionIDs ...string) to visually invert the background and foreground colors of specified regions.
    • Use SetToggleHighlights(bool) to change whether Highlight toggles existing highlights or overwrites them.
    • Use ScrollToHighlight() to ensure highlighted regions are visible on the next draw.
  11. Manage concurrency with QueueUpdate and QueueUpdateDraw

    master

    Because tview is not thread-safe, you must use QueueUpdate to synchronize access to primitives from non-main goroutines. This ensures the provided function f is executed as part of the main event loop, preventing race conditions.

    • QueueUpdate(f func()): Executes f in the event loop and waits for it to complete. It does not automatically trigger a screen redraw.
    • QueueUpdateDraw(f func()): Executes f in the event loop and immediately triggers a screen redraw after f finishes.

    If you use QueueUpdate, you may need to call Draw() within f if you want the changes to be visible immediately.

    // From a background goroutine:
    app.QueueUpdateDraw(func() {
        // Update widget state safely here
        myWidget.SetText("Updated!")
    })