Documentation
¶
Overview ¶
Package tui is the pure-Go, Ruby-runtime-independent core of the Ruby `tui` gem: a terminal-cell user-interface toolkit — widgets, layout containers, frame rendering and input routing — shaped so that github.com/go-embedded-ruby/ruby (rbgo) can bind it as `require "tui"`.
It is a thin adapter over github.com/go-widgets/tui, the terminal-cell widget toolkit. It exposes that toolkit through Ruby-facing handles (Module, Widget) whose methods return Ruby-shaped values: a Hash (map[string]any), an Array ([]any) or a scalar. A single dynamic entry point, Call, dispatches a Ruby-style snake_case method name to the matching handle method and coerces the arguments, which is exactly what an rbgo binding drives from method_missing. Nothing here imports the Ruby runtime, so the package is equally usable as a standalone Go library — a sibling of go-ruby-opentype/opentype, go-ruby-regexp/regexp and go-ruby-erb/erb.
Handles ¶
- Module is the package-level receiver: it constructs widgets and layout containers, lays a tree out (SetSize), renders it (Render / RenderCells), decodes an ANSI frame (DecodeCells) and routes input (Dispatch).
- Widget is an opaque handle over one widget or container. Its methods mutate props (SetText, SetFraction, …), compose a tree (SetBody, AddTab, SetLeft, …) and wire callbacks by id (OnClick, OnToggle, …).
Widgets and layouts ¶
Leaves: label, button, entry, check_button, list_box, progress_bar. Containers: container (a border layout — fixed header + footer bands around a filling body, plus floating overlays), h_split / v_split (draggable split panes) and notebook (a card layout — a tab strip selects the visible page).
The render seam ¶
A widget tree renders to a terminal cell grid, emitted as a self-contained ANSI stream. Render returns that stream as a String a Ruby host can print straight to a terminal. RenderCells (and DecodeCells over any ANSI string) return the decoded grid as a Ruby Hash — "cols", "rows", a "cells" Array of rows of {"char", "fg", "bg"} cell Hashes (a color is {"r","g","b"} or nil), and a "text" Array of per-row strings — so a test can assert the output at cell precision. The decode path is backed by go-widgets/tui's DecodeANSI.
Events ¶
Dispatch routes one input event (a Ruby Hash with "kind", "x", "y", "code" and modifier flags) into the tree, whose containers translate coordinates and deliver it to the right leaf. It returns the ids of the callbacks that fired and whether a repaint is warranted.
Usage from Go ¶
m := tui.NewModule()
root := m.Container()
_ = root.SetHeaderHeight(1)
_ = root.SetHeader(m.Label("Title"))
_ = root.SetBody(m.Button("OK"))
_ = m.SetSize(root, 40, 10)
frame, _ := m.Render(root, 40, 10) // an ANSI String
grid, _ := m.RenderCells(root, 40, 10) // a Ruby Hash of cells
_ = frame
_ = grid
Usage from Ruby ¶
Under rbgo, `require "tui"` gives a Tui module whose snake_case methods are these operations, returning Ruby Hashes, Arrays and scalars:
require "tui"
root = Tui.container
root.set_header_height(1)
root.set_header(Tui.label("Title"))
root.set_body(Tui.button("OK"))
Tui.set_size(root, 40, 10)
frame = Tui.render(root, 40, 10) # => String (ANSI)
fired = Tui.dispatch(root, {"kind" => "click", "x" => 1, "y" => 2})
The `require "tui"` binding lives in rbgo (a thin method_missing shim over Call); it is pending in that repo.
Example ¶
Example mirrors the README: build a border-layout container with a titled header over a clickable body, render it to a cell grid, then route a click — every result a Ruby-shaped value.
package main
import (
"fmt"
"github.com/go-ruby-widgets/tui"
)
func main() {
m := tui.NewModule()
button := m.Button("OK")
_ = button.OnClick("ok")
root := m.Container()
_ = root.SetHeaderHeight(1)
_ = root.SetHeader(m.Label("Title"))
_ = root.SetBody(button)
_ = m.SetSize(root, 20, 5)
grid, _ := m.RenderCells(root, 20, 5) // a Ruby Hash of decoded cells
fmt.Println("cols:", grid["cols"], "rows:", grid["rows"])
res, _ := m.Dispatch(button, map[string]any{"kind": "click"})
fmt.Println("fired:", res["fired"], "repaint:", res["repaint"])
}
Output: cols: 20 rows: 5 fired: [ok] repaint: true
Index ¶
- func Bounds(w *Widget) (map[string]any, error)
- func Call(recv any, method string, args ...any) (any, error)
- func DecodeCells(ansi string, cols, rows int) map[string]any
- func Dispatch(root *Widget, ev map[string]any) (map[string]any, error)
- func Methods(recv any) []string
- func Render(root *Widget, cols, rows int) (string, error)
- func RenderCells(root *Widget, cols, rows int) (map[string]any, error)
- func SetSize(root *Widget, cols, rows int) error
- type Module
- func (m *Module) Bounds(w *Widget) (map[string]any, error)
- func (m *Module) Button(label string) *Widget
- func (m *Module) CheckButton(label string, checked bool) *Widget
- func (m *Module) Container() *Widget
- func (m *Module) DecodeCells(ansi string, cols, rows int) map[string]any
- func (m *Module) Dispatch(root *Widget, ev map[string]any) (map[string]any, error)
- func (m *Module) Entry(initial string) *Widget
- func (m *Module) HSplit() *Widget
- func (m *Module) Label(text string) *Widget
- func (m *Module) ListBox(items []any) *Widget
- func (m *Module) Notebook() *Widget
- func (m *Module) ProgressBar() *Widget
- func (m *Module) Render(root *Widget, cols, rows int) (string, error)
- func (m *Module) RenderCells(root *Widget, cols, rows int) (map[string]any, error)
- func (m *Module) SetSize(root *Widget, cols, rows int) error
- func (m *Module) VSplit() *Widget
- type Widget
- func Button(label string) *Widget
- func CheckButton(label string, checked bool) *Widget
- func Container() *Widget
- func Entry(initial string) *Widget
- func HSplit() *Widget
- func Label(text string) *Widget
- func ListBox(items []any) *Widget
- func Notebook() *Widget
- func ProgressBar() *Widget
- func VSplit() *Widget
- func (w *Widget) Active() (int, error)
- func (w *Widget) AddOverlay(child *Widget) error
- func (w *Widget) AddTab(label string, page *Widget) error
- func (w *Widget) Checked() (bool, error)
- func (w *Widget) Fraction() (float64, error)
- func (w *Widget) Items() ([]any, error)
- func (w *Widget) Kind() string
- func (w *Widget) OnChange(id string) error
- func (w *Widget) OnClick(id string) error
- func (w *Widget) OnSelect(id string) error
- func (w *Widget) OnTabChanged(id string) error
- func (w *Widget) OnToggle(id string) error
- func (w *Widget) Selected() (int, error)
- func (w *Widget) SetActive(i int) error
- func (w *Widget) SetAlign(align string) error
- func (w *Widget) SetBody(child *Widget) error
- func (w *Widget) SetBottom(child *Widget) error
- func (w *Widget) SetChecked(v bool) error
- func (w *Widget) SetFooter(child *Widget) error
- func (w *Widget) SetFooterHeight(n int) error
- func (w *Widget) SetFraction(f float64) error
- func (w *Widget) SetHeader(child *Widget) error
- func (w *Widget) SetHeaderHeight(n int) error
- func (w *Widget) SetItems(items []any) error
- func (w *Widget) SetLabel(s string) error
- func (w *Widget) SetLeft(child *Widget) error
- func (w *Widget) SetLeftFraction(n int) error
- func (w *Widget) SetPlaceholder(s string) error
- func (w *Widget) SetRight(child *Widget) error
- func (w *Widget) SetSelected(i int) error
- func (w *Widget) SetText(s string) error
- func (w *Widget) SetTop(child *Widget) error
- func (w *Widget) SetTopFraction(n int) error
- func (w *Widget) Text() (string, error)
- func (w *Widget) Underlying() toolkit.Widget
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Call ¶
Call dispatches a Ruby-style snake_case method name to the matching exported method of recv (a *Module or *Widget), coercing each Ruby-supplied argument to the Go parameter type. Trailing arguments may be omitted; they default to nil. The result is the method's Ruby-shaped return value (or nil for a method that returns nothing); a trailing error return is unwrapped into Call's own error. This is the single entry point an rbgo binding drives.
func DecodeCells ¶
DecodeCells decodes an ANSI frame to a cell grid via the default Module.
func RenderCells ¶
RenderCells renders root to a cell grid via the default Module.
Types ¶
type Module ¶
type Module struct {
// contains filtered or unexported fields
}
Module is the package-level Ruby receiver: the `Tui` module under rbgo. Its methods construct terminal-cell widgets and layout containers, lay them out, render them to a frame (an ANSI string and a decoded cell grid), and route input events — all returning Ruby-shaped values (a Hash is a map[string]any, an Array a []any, and scalars stay scalars).
A Module carries the per-session callback log that Module.Dispatch drains, so it is stateful and NOT safe for concurrent use: give each terminal session its own Module (the package-level convenience functions share one default Module and are likewise single-threaded).
func NewModule ¶
func NewModule() *Module
NewModule returns a fresh Module with an empty callback log. The package-level convenience functions delegate to a shared default Module.
func (*Module) Bounds ¶
Bounds returns a widget's current placement as a Hash with "x", "y", "w" and "h".
func (*Module) Button ¶
Button builds a clickable action widget. Wire a handler with Widget.OnClick.
func (*Module) CheckButton ¶
CheckButton builds a boolean toggle with the given label and initial state.
func (*Module) Container ¶
Container builds a border-layout container: a fixed-height header band at the top, a fixed-height footer band at the bottom, a body filling the middle, and floating overlays. Compose it with SetHeader/SetBody/SetFooter/AddOverlay.
func (*Module) DecodeCells ¶
DecodeCells decodes an ANSI frame into a cell grid, returning a Ruby Hash with "cols", "rows", "cells" and "text". "cells" is an Array of rows, each an Array of cell Hashes {"char" => String, "fg" => color|nil, "bg" => color|nil}; a color is a Hash {"r","g","b"} or nil for the terminal default. "text" is an Array of per-row strings for coarse assertions. It is backed by go-widgets/tui's DecodeANSI.
func (*Module) Dispatch ¶
Dispatch routes one input event to root's widget tree and returns a Hash with "fired" (an Array of the callback ids that ran) and "repaint" (always true — an event may change state, so the caller should re-render). The event Hash carries "kind" (e.g. "click", "key_down", "char", "mouse_drag", "mouse_up", "tick"), "x", "y", "code"/"key"/"rune", "ctrl" and "shift"; all are optional.
func (*Module) HSplit ¶
HSplit builds a horizontal split container (a left pane and a right pane separated by a draggable grip), left pane 50% by default.
func (*Module) ListBox ¶
ListBox builds a single-selection list over the given items (a Ruby Array of strings).
func (*Module) Notebook ¶
Notebook builds a card-layout (tabbed) container: a tab strip selects which child page fills the body. Add pages with Widget.AddTab.
func (*Module) ProgressBar ¶
ProgressBar builds an empty horizontal progress indicator.
func (*Module) Render ¶
Render lays root out to (cols, rows) and returns the frame as a self-contained ANSI string a Ruby host can print straight to a terminal.
func (*Module) RenderCells ¶
RenderCells lays root out, renders it, and returns the decoded cell grid as a Ruby Hash (see Module.DecodeCells for the shape). This is the DecodeANSI-backed form a test asserts against at cell precision.
type Widget ¶
type Widget struct {
// contains filtered or unexported fields
}
Widget is a Ruby-facing opaque handle over one go-widgets/tui widget or layout container. Kind names the concrete widget ("label", "button", "container", …) so a caller can branch on it, and every mutator checks it so a method that does not apply to the handle's kind returns a clear error rather than mis-typing. A Widget belongs to the Module that built it, which is where its callbacks log.
func CheckButton ¶
CheckButton builds a check button on the default Module.
func Container ¶
func Container() *Widget
Container builds a border-layout container on the default Module.
func ProgressBar ¶
func ProgressBar() *Widget
ProgressBar builds a progress bar on the default Module.
func (*Widget) AddOverlay ¶
AddOverlay floats a child on top of a container's body.
func (*Widget) OnClick ¶
OnClick wires a button so that a click (or Enter while focused) records id in the owning Module's callback log; Module.Dispatch returns those ids.
func (*Widget) OnTabChanged ¶
OnTabChanged wires a notebook so a tab switch records id.
func (*Widget) SetAlign ¶
SetAlign sets a label's horizontal alignment ("left", "center" or "right"; any other value is treated as "left").
func (*Widget) SetChecked ¶
SetChecked sets a check button's state.
func (*Widget) SetFooterHeight ¶
SetFooterHeight sets a container's footer band height in rows.
func (*Widget) SetFraction ¶
SetFraction sets a progress bar's fill in [0,1] (clamped).
func (*Widget) SetHeaderHeight ¶
SetHeaderHeight sets a container's header band height in rows.
func (*Widget) SetItems ¶
SetItems replaces a list box's items (a Ruby Array of strings) and resets the selection to the first row.
func (*Widget) SetLeftFraction ¶
SetLeftFraction sets a horizontal split's left-pane width percentage.
func (*Widget) SetPlaceholder ¶
SetPlaceholder sets an entry's muted placeholder text.
func (*Widget) SetSelected ¶
SetSelected sets a list box's selected row index.
func (*Widget) SetTopFraction ¶
SetTopFraction sets a vertical split's top-pane height percentage.
func (*Widget) Underlying ¶
Underlying returns the wrapped go-widgets/tui widget as a toolkit.Widget, for Go callers that want to reach past the adapter. Ruby callers never need it.