catatui

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 7, 2026 License: MIT Imports: 11 Imported by: 0

README

catatui

A Go port of ratatui — immediate-mode terminal UI built on a cell-addressed buffer, a constraint-solved layout, and a diffing terminal.

import (
    "github.com/Fiend3d/catatui"
    "github.com/Fiend3d/catatui/term"
    "github.com/Fiend3d/catatui/widgets"
)

terminal, restore, err := term.Init(term.WithMouse())
if err != nil {
    return err
}
defer restore()

terminal.Draw(func(f *catatui.Frame) {
    rows := catatui.VerticalLayout(
        catatui.Length(3),
        catatui.Fill(1),
    ).Split(f.Area())

    f.RenderWidget(
        widgets.NewParagraph("hello").
            Block(widgets.Bordered().Title("catatui")).
            Wrap(widgets.Wrap{Trim: true}),
        rows[0])
})

Run go run ./examples/apps/hello for a working application.

New here? Start with a happy little cat. Build Purrfect Day, a colorful cat-care dashboard, in five friendly steps: draw your first screen, style it, add a checklist, handle keys, and earn a smile. Try the finished app with go run ./examples/apps/getting-started.

Unicode text and terminal widths

SegmentGraphemes exposes the same segmentation and measurement used by Buffer.SetStringn, cells, spans and widgets. It preserves source bytes, including tabs and zero-width clusters, for editors and viewers that maintain byte offsets. AllGraphemes yields only drawable units. Indic GB9c conjuncts and tailored Tamil ksha/sri ligatures stay intact through buffer diffing and terminal output.

DefaultWidthPolicy selects the terminal advance: WindowsTerminalWidth on Windows and UnicodeWidth elsewhere. Set it once during application startup if the target terminal uses another policy; never change it while buffers or concurrent readers are in use. The explicit policy methods allow measurement without changing the default, for example catatui.WindowsTerminalWidth.StringWidth(text).

The Windows policy counts spacing marks (including Bengali AA) and caps each Unicode cluster at two cells after Indic joining, following Windows Terminal's grapheme measurement. Tamil selection units can span multiple terminal clusters and retain their combined width. Applications do not need forced-width cells or custom drawing code for these scripts.

Why

Go's existing TUI libraries take a different shape: Bubble Tea is the Elm architecture composing styled strings, tview is retained-mode widgets on tcell. Neither gives you ratatui's model — you draw into a Buffer of cells, a Cassowary solver decides where things go, and the Terminal writes only what changed.

This is a near-literal port, not a reinterpretation. Names, structure and semantics follow ratatui 0.30.x (ratatui-core 0.1.2, ratatui-widgets 0.3.2), and every ported file names its Rust source in a header comment.

Status

Working and tested:

Area What is there
Style Color, Modifier, Style, patching
Geometry Rect, Position, Size, Margin, Offset, saturating uint16 math
Text Span, Line, Text, grapheme-cluster measurement
Buffer Cell, Buffer, SetSpan/SetLine/SetStringn, frame diffing
Layout Constraint, seven Flex modes, Spacing, Split, SplitWithSpacers
Terminal Widget, StatefulWidget, Frame, double-buffered Terminal, Viewport
Backends catatui/term (Windows + Unix), TestBackend
Terminal control raw mode, alt screen, mouse, bracketed paste, focus, cursor shape
Symbols box-drawing, block, bar, braille and half-block characters, border merging
Palettes the tailwind and Material design colour ramps
Widgets the whole ratatui-widgets library, listed below

The widget library is complete: Block (borders, titles, padding, shadow, merged borders), Paragraph, List, Table, Tabs, Gauge, LineGauge, Scrollbar, BarChart, Sparkline, Chart, Canvas (with the line, rectangle, circle, points and world-map shapes), Calendar, Clear, Fill, CatatuiLogo and RatatuiMascot.

Adjacent blocks can collapse their borders into single box-drawing characters, as ratatui does. Block.MergeBorders picks the strategy, Cell.MergeSymbol does the work, and symbols.MergeStrategy holds the rules:

widgets.Bordered().Render(catatui.NewRect(0, 0, 5, 5), buf)
widgets.Bordered().
    MergeBorders(symbols.MergeExact).
    Render(catatui.NewRect(4, 0, 5, 5), buf) // the shared edge becomes ┬ │ ┴

Fidelity

The port is checked against ratatui's own tests rather than against expectations written from scratch:

  • 677 layout cases translated mechanically from ratatui's rstest tables by tools/gen_layout_tests.py, covering every constraint type, every flex mode, spacing and overlap. Regenerate with python tools/gen_layout_tests.py && gofmt -w layout_cases_test.go.
  • The colour palettes, translated from ratatui's by tools/gen_palettes.py. The generated values are checked against Tailwind's and Material design's own published tables, and every ramp is asserted to run light to dark, which is what would catch a shade written out of order.
  • kasuari's quadrilateral test, which reproduces the Rust solver's exact values for a mixed system of required, weighted and inequality constraints.
  • ratatui's buffer, style, color, rect and widget tests, ported by hand — both the unit tests next to each widget and the integration tests under ratatui/tests, including the word-wrap cases, which pin down whitespace handling at wrap points.
  • ratatui's cell_width cases, which double as a conformance check that Go's uniseg agrees with Rust's unicode-width.
  • ratatui's three border-merging golden files, copied verbatim into widgets/testdata/block. Each is the 43x1000 buffer ratatui's own test draws for all 100 pairs of border types meeting four different ways, and catatui reproduces all three exactly.

The rules that matter most, and that the tests pin down:

  • A grapheme cluster wider than the space left is dropped, not clipped, and drawing stops there. The continuation columns of a wide cluster are blanked, not styled.
  • There is exactly one width function in the tree, exported as catatui.StringWidth, and a test asserts that what it measures is exactly the number of columns SetString fills. Disagreeing width implementations are what made rows drift in the Go program that ratatui's author replaced.
  • Coordinates are uint16 with saturating arithmetic, as in ratatui.

Deliberate deviations from ratatui

  1. StatefulWidget is generic and renders through the free function RenderStatefulWidget, because Go methods cannot have type parameters.
  2. Unset colors use Color's zero value rather than Option[Color], keeping Style comparable and allocation-free. ColorReset remains a distinct, explicit variant.
  3. Builders return copies of value types rather than consuming the receiver, so a pre-builder value stays usable.
  4. Struct fields are unexported behind ratatui's builder names. Rust allows a field and a method to share a name (style.fg and style.fg(c)); Go does not, so readers use GetFg and the builder keeps the ratatui name.
  5. One width function everywhere. ratatui's Span::width calls unicode-width while Buffer::set_stringn uses cell_width; the two disagree on halfwidth katakana sound marks and some emoji, so a ratatui Line can report a width it does not draw. catatui measures everything the same way.
  6. The layout solver iterates in a deterministic order. The Rust solver scans hash maps where the pivot choice is free; Go randomizes map order per run, which would make a degenerate layout come out differently on each launch.

Documentation

The API reference is on pkg.go.dev. The guides under docs/ cover each area in depth, and are meant to be read rather than searched:

Guide Covers
Getting started Build Purrfect Day: a beginner tutorial with a complete runnable cat-care dashboard
Rendering The immediate-mode cycle, Frame, Buffer, Cell, wide graphemes, the diff, writing a widget
Layout Rect, the six constraints, seven flex modes, spacing, nesting, recipes
Widgets The catalogue, builder conventions, blocks and inner areas, widget state
Text and style Color, Modifier, Style patching, Span/Line/Text, how styles layer
Events EventReader, the Event kinds, the drain-the-queue loop, app structure
Terminal term.Init and its options, raw mode, viewports, InsertBefore, panic recovery
Testing Rendering into a buffer, AssertBuffer, driving an app through TestBackend

Every whole-file Go snippet in the README and the guides is compiled by tools/check_doc_snippets.py, so the documentation cannot drift from the API without the check failing.

Dependencies

github.com/rivo/uniseg, golang.org/x/sys, golang.org/x/term. That is all. uniseg is MIT; the two golang.org/x modules are BSD-3-Clause.

Examples

examples/widgets/ holds one runnable program per widget, ported from ratatui's own widget examples. examples/apps/ holds the whole applications, the split following ratatui's own layout: the original tui-rs demo, the flex layout explorer, a popup, a todo-list, a user-input box, an inline viewport writing to the scrollback, an input-form, a custom-widget driven by the mouse, a release-header banner, mouse-drawing, constraints, a constraint-explorer that lays the same constraints out under every Flex mode at once, calendar-explorer, color-explorer, colors-rgb, canvas, chart, table, gauge, scrollbar, panic, modifiers, weather, tracing, a hyperlink, a widget-ref-container, an advanced-widget-impl on the shapes a widget can take, an async-github fetching in the background, a volatility-surface turning a 3D wireframe on a braille canvas, minimal, and hello, which shows the layout solver, direct buffer drawing and an event loop that blocks when idle:

go run ./examples/apps/demo
go run ./examples/apps/flex
go run ./examples/apps/hello

See examples/README.md for the full list and the keys each one responds to.

Development

go test ./...                          # the full suite, examples included
python tools/check_doc_snippets.py     # compile the code in the docs
go run ./examples/apps/hello

_ref/ holds read-only checkouts of ratatui and kasuari at the versions being ported. It is gitignored; recreate it with:

git clone --depth 1 --branch ratatui-v0.30.2 https://github.com/ratatui/ratatui.git _ref/ratatui
git clone --depth 1 --branch v0.4.11 https://github.com/ratatui/kasuari.git _ref/kasuari

License

MIT. See LICENSE.

catatui is a port, so that file also carries the copyright notices of the work it derives from: ratatui, which nearly every file here is ported from, and kasuari, the Cassowary solver behind internal/kasuari. Both are MIT (kasuari is MIT or Apache-2.0, used here under MIT), and MIT requires their notices to travel with the code.

Documentation

Overview

Unicode 15.1's rule GB9c: do not break an Indic conjunct.

uniseg v0.4.7, the newest release, implements the grapheme rules through GB9b, so it breaks a conjunct in two: पर|ीक्|ष rather than the ligature the terminal draws. Everything downstream of the cluster table inherits that split — a selection edge can land in the middle of क्ष, and then half a glyph is highlighted and the terminal, which groups cells by their attributes before shaping them, draws the two halves separately instead of the conjunct. Telugu and Devanagari are written almost entirely in conjuncts, so this is most of the text.

The rule is:

Consonant (Extend | Linker)* Linker (Extend | Linker)* × Consonant

where Consonant, Extend and Linker are the Indic_Conjunct_Break property values. Applied on top of uniseg's own segmentation it comes to joining two adjacent clusters, since uniseg has already gathered each base with its marks: the left one has to start with a consonant and carry a linker, and the right one has to start with a consonant.

Package catatui draws terminal user interfaces: a cell-addressed buffer, a constraint-solved layout, and a terminal that writes only what changed.

It is a near-literal Go port of ratatui, following the structure and semantics of ratatui 0.30.x. Names, behaviour and edge cases match, and every ported file names its Rust source in a header comment.

The model

catatui is immediate mode. There is no widget tree that lives between frames: every frame your code builds widget values, renders them into a buffer, and throws them away. Whatever the UI has to remember lives in your own structs.

One frame is one call to Terminal.Draw, which:

  1. resizes its buffers if the terminal changed size,
  2. hands your callback a blank Frame,
  3. diffs what you drew against the previous frame,
  4. writes only the cells that differ, then places or hides the cursor.

Nothing is written to the terminal until the callback returns, so a frame is atomic: the screen never shows a half-drawn UI.

A whole program

package main

import (
	"os"

	"github.com/Fiend3d/catatui"
	"github.com/Fiend3d/catatui/term"
	"github.com/Fiend3d/catatui/widgets"
)

func main() {
	defer term.RecoverAndRestore()

	terminal, restore, err := term.Init()
	if err != nil {
		panic(err)
	}
	defer restore()

	events := term.NewEventReader(os.Stdin, os.Stdout)
	defer events.Close()

	for {
		terminal.Draw(func(f *catatui.Frame) {
			rows := catatui.VerticalLayout(
				catatui.Length(3),
				catatui.Fill(1),
			).Split(f.Area())

			f.RenderWidget(
				widgets.NewParagraph("hello").
					Block(widgets.Bordered().Title("catatui")),
				rows[0])
		})

		ev, ok := <-events.Events()
		if !ok || ev.IsRune('q') {
			return
		}
	}
}

The packages

Things worth knowing early

Coordinates are uint16 with saturating arithmetic (SatAdd, SatSub), as in ratatui, so a rect can never wrap around into a huge one. Rect.Right and Rect.Bottom are exclusive: they name the first column and row past the rect.

There is exactly one width function, StringWidth, and what it measures is exactly the number of columns Buffer.SetString fills. A grapheme cluster that does not fit in the space left is dropped rather than clipped, and drawing stops there.

The zero Color means "unset" — inherit whatever is underneath — while ColorReset is an explicit reset to the terminal's default. This is the one place where catatui's model differs from ratatui's Option[Color], and it is what keeps Style comparable and allocation-free.

Builders return modified copies rather than consuming the receiver, so a half-built widget stays usable:

base := widgets.Bordered().Title("Files")
left := base.BorderStyle(cyan)  // base is unchanged

Widgets hold no state. A widget that has to remember something — which row of a list is selected, how far a view is scrolled — takes that state from the caller through RenderStatefulWidget, which is a free function because Go methods cannot have type parameters of their own.

Where to read next

The guides under docs/concepts cover each area in depth: rendering, layout, text and style, events, the terminal, and testing. The examples directory has a runnable program for every widget.

Example

A whole frame: split the area, then render a widget into each part. This is what the body of a Terminal.Draw callback looks like, and TestBackend is how it is exercised without a terminal.

package main

import (
	"fmt"
	"strings"

	"github.com/Fiend3d/catatui"
	"github.com/Fiend3d/catatui/widgets"
)

// printBuffer writes a buffer one row per line, with the padding on the right
// trimmed so that the expected output of an example stays readable.
func printBuffer(buf *catatui.Buffer) {
	for row := range strings.SplitSeq(buf.String(), "\n") {
		fmt.Println(strings.TrimRight(row, " "))
	}
}

func main() {
	backend := catatui.NewTestBackend(24, 5)
	terminal, err := catatui.NewTerminal(backend)
	if err != nil {
		panic(err)
	}

	terminal.Draw(func(f *catatui.Frame) {
		rows := catatui.VerticalLayout(
			catatui.Length(3),
			catatui.Fill(1),
		).Split(f.Area())

		f.RenderWidget(
			widgets.NewParagraph("hello").
				Block(widgets.Bordered().Title("catatui")),
			rows[0])
		f.RenderWidget(widgets.NewParagraph("q to quit"), rows[1])
	})

	printBuffer(backend.Buffer())
}
Output:
┌catatui───────────────┐
│hello                 │
└──────────────────────┘
q to quit

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// CellDiffNone is the default: the cell is diffed normally.
	CellDiffNone = CellDiffOption{/* contains filtered or unexported fields */}
	// CellDiffSkip prevents the buffer from overwriting a cell covered by
	// something outside its control, such as a sixel or kitty image.
	CellDiffSkip = CellDiffOption{/* contains filtered or unexported fields */}
	// CellDiffAlwaysUpdate bypasses the equality check against the previous
	// buffer, so the cell is redrawn every frame.
	CellDiffAlwaysUpdate = CellDiffOption{/* contains filtered or unexported fields */}
)

The diff options that carry no payload.

View Source
var (
	ColorReset = Color{/* contains filtered or unexported fields */}

	ColorBlack        = Color{/* contains filtered or unexported fields */}
	ColorRed          = Color{/* contains filtered or unexported fields */}
	ColorGreen        = Color{/* contains filtered or unexported fields */}
	ColorYellow       = Color{/* contains filtered or unexported fields */}
	ColorBlue         = Color{/* contains filtered or unexported fields */}
	ColorMagenta      = Color{/* contains filtered or unexported fields */}
	ColorCyan         = Color{/* contains filtered or unexported fields */}
	ColorGray         = Color{/* contains filtered or unexported fields */}
	ColorDarkGray     = Color{/* contains filtered or unexported fields */}
	ColorLightRed     = Color{/* contains filtered or unexported fields */}
	ColorLightGreen   = Color{/* contains filtered or unexported fields */}
	ColorLightYellow  = Color{/* contains filtered or unexported fields */}
	ColorLightBlue    = Color{/* contains filtered or unexported fields */}
	ColorLightMagenta = Color{/* contains filtered or unexported fields */}
	ColorLightCyan    = Color{/* contains filtered or unexported fields */}
	ColorWhite        = Color{/* contains filtered or unexported fields */}
)

The named ANSI colors. The ordinals match ratatui's enum order, which is also the order the ANSI SGR codes fall in: 30..37 then 90..97.

View Source
var DefaultWidthPolicy = func() WidthPolicy {
	if runtime.GOOS == "windows" {
		return WindowsTerminalWidth
	}
	return UnicodeWidth
}()

DefaultWidthPolicy is shared by cells, buffers, text and widgets. It defaults to WindowsTerminalWidth on Windows and UnicodeWidth elsewhere. Applications targeting another terminal may set it during startup, before measuring text or creating buffers. Do not change it while buffers or concurrent readers are in use; their existing column positions would become invalid.

View Source
var PositionOrigin = Position{0, 0}

PositionOrigin is the top left corner.

View Source
var ZeroRect = Rect{}

ZeroRect is an empty rect at the origin.

Functions

func AllGraphemes

func AllGraphemes(s string) iter.Seq[Grapheme]

AllGraphemes yields only drawable clusters, without allocating a slice.

func AssertBuffer

func AssertBuffer(t TestingT, got, want *Buffer)

AssertBuffer fails the test unless got and want hold the same cells, and reports what differed as a side-by-side rendering plus a per-cell list.

This is the Go counterpart of ratatui's assert_eq!(buf, Buffer::with_lines(..)), and the main way widget behaviour is pinned down:

buf := catatui.NewBuffer(catatui.NewRect(0, 0, 10, 2))
widget.Render(buf.Area, buf)
catatui.AssertBuffer(t, buf, catatui.NewBufferWithStrings(
	"┌────────┐",
	"└────────┘",
))

func BufferEqual

func BufferEqual(got, want *Buffer) error

BufferEqual reports whether two buffers hold the same cells, returning nil if they do and an error describing every difference if they do not.

Symbols are compared as ratatui compares them, so a cell with no symbol equals a cell holding a single space. Styles are compared in full: two cells showing the same character in different colors are not equal.

func ClampU16

func ClampU16(v, lo, hi uint16) uint16

ClampU16 returns v confined to the range [lo, hi]. An empty range pins to lo.

func GraphemeWidth

func GraphemeWidth(cluster string, unisegWidth int) int

GraphemeWidth measures a single uniseg segment with its stepper-provided width. For full Indic conjunct boundaries, use SegmentGraphemes instead.

func MaxU16

func MaxU16(a, b uint16) uint16

MaxU16 returns the larger of a and b.

func MinU16

func MinU16(a, b uint16) uint16

MinU16 returns the smaller of a and b.

func RenderStatefulWidget

func RenderStatefulWidget[S any](w StatefulWidget[S], area Rect, buf *Buffer, state *S)

RenderStatefulWidget draws a stateful widget into a buffer at the given area, clipped to the buffer, letting it update state.

func RenderStatefulWidgetOn

func RenderStatefulWidgetOn[S any](f *Frame, w StatefulWidget[S], area Rect, state *S)

RenderStatefulWidgetOn draws a stateful widget into a frame.

It is a free function rather than a method on Frame because Go methods cannot have their own type parameters. See StatefulWidget.

func RenderWidget

func RenderWidget(w Widget, area Rect, buf *Buffer)

RenderWidget draws a widget into a buffer at the given area, clipped to the buffer. Widgets normally reach a buffer through Frame.RenderWidget; this is the direct form, useful for composing one widget inside another.

func SatAdd

func SatAdd(a, b uint16) uint16

SatAdd returns a+b, clamped at uint16 max instead of wrapping.

func SatMul

func SatMul(a, b uint16) uint16

SatMul returns a*b, clamped at uint16 max instead of wrapping.

func SatSub

func SatSub(a, b uint16) uint16

SatSub returns a-b, clamped at zero instead of wrapping.

func SegmentGraphemes

func SegmentGraphemes(s string) iter.Seq[Grapheme]

SegmentGraphemes preserves every byte of s, including tabs, controls and zero-width clusters. Controls have width zero. Layout callers can expand tabs themselves and retain byte offsets by summing len(g.Symbol).

Segmentation adds Unicode 15.1 GB9c to uniseg's boundaries and tailors Tamil ksha/sri ligatures. The same units are used by Buffer.SetStringn and the diff.

func StringWidth

func StringWidth(s string) int

StringWidth is the terminal advance under DefaultWidthPolicy, matching cells, Buffer.SetStringn, spans and widgets. Controls occupy no columns.

func TrimLeftColumns

func TrimLeftColumns(s string, n int) string

TrimLeftColumns drops the first n columns of s, working in grapheme clusters so that a wide cluster is never cut in half. A cluster straddling the cut is dropped whole, which is the same rule Buffer.SetStringn applies at the right edge.

Types

type Alignment

type Alignment uint8

Alignment is the horizontal alignment of a line within its area.

The zero value, AlignmentNone, means "not specified" and stands in for ratatui's Option<Alignment>::None: the containing widget decides. Note that ratatui's standalone Alignment defaults to Left instead, so write AlignmentLeft when you mean left rather than relying on the zero value.

const (
	// AlignmentNone leaves alignment up to the containing widget.
	AlignmentNone Alignment = iota
	// AlignmentLeft aligns to the left edge.
	AlignmentLeft
	// AlignmentCenter centers within the area.
	AlignmentCenter
	// AlignmentRight aligns to the right edge.
	AlignmentRight
)

func (Alignment) String

func (a Alignment) String() string

String returns the alignment's name.

type Backend

type Backend interface {
	// Draw writes the given cells to the terminal.
	Draw(cells []PositionedCell) error

	// HideCursor hides the terminal cursor.
	HideCursor() error

	// ShowCursor shows the terminal cursor.
	ShowCursor() error

	// GetCursorPosition reports where the cursor is.
	GetCursorPosition() (Position, error)

	// SetCursorPosition moves the cursor.
	SetCursorPosition(p Position) error

	// Clear erases the whole screen.
	Clear() error

	// ClearRegion erases part of the screen.
	ClearRegion(t ClearType) error

	// Size reports the terminal's size in cells.
	Size() (Size, error)

	// WindowSize reports the terminal's size in cells and pixels.
	WindowSize() (WindowSize, error)

	// Flush writes any buffered output to the terminal.
	Flush() error

	// AppendLines scrolls the terminal up by n lines, for drawing above an
	// inline viewport.
	AppendLines(n uint16) error
}

Backend is the boundary between catatui and an actual terminal.

Terminal drives a Backend: it works out which cells changed and hands them to Draw, then flushes. Implementations exist for a real terminal (package catatui/term) and for tests (TestBackend), and anything else that can paint cells can implement this.

Draw receives only the cells that changed, in row-major order, and the positions are absolute. An implementation must not assume the cells are contiguous.

type Buffer

type Buffer struct {
	// Area is the region of the terminal this buffer maps to.
	Area Rect
	// Content holds Area.Area() cells in row-major order.
	Content []Cell
}

Buffer is a rectangular grid of Cells: the surface widgets draw into.

Cells are stored row-major in Content, so the cell at (x, y) lives at index (y-Area.Y)*Area.Width + (x-Area.X). Coordinates are absolute, not relative to the buffer's origin: a Buffer whose Area starts at (10, 5) is indexed with x >= 10, y >= 5.

Invariant: len(Content) == Area.Area(). Resize and Merge maintain it; if you assign to the fields directly, you must too.

func NewBuffer

func NewBuffer(area Rect) *Buffer

NewBuffer returns a buffer covering area with every cell empty.

func NewBufferFilled

func NewBufferFilled(area Rect, cell Cell) *Buffer

NewBufferFilled returns a buffer covering area with every cell a copy of cell.

func NewBufferWithLines

func NewBufferWithLines(lines ...Line) *Buffer

NewBufferWithLines returns a buffer just large enough to hold the given lines, with them drawn into it starting at the origin. Its width is that of the widest line.

This is the workhorse of widget tests: build the buffer a widget should have produced, then compare. See AssertBuffer.

func NewBufferWithStrings

func NewBufferWithStrings(lines ...string) *Buffer

NewBufferWithStrings is NewBufferWithLines for unstyled text, which is how most buffer assertions are written.

func (*Buffer) Cell

func (b *Buffer) Cell(p Position) *Cell

Cell returns a pointer to the cell at the given position, or nil if the position lies outside the buffer. Writing through the pointer edits the buffer.

func (*Buffer) CellAt

func (b *Buffer) CellAt(x, y uint16) *Cell

CellAt is Cell taking loose coordinates.

func (*Buffer) Diff

func (b *Buffer) Diff(next *Buffer) []PositionedCell

Diff collects the cells that must be written to turn b into next.

The two buffers must share an X, Y and Width; only the height may differ.

func (*Buffer) DiffInto

func (b *Buffer) DiffInto(dst []PositionedCell, next *Buffer) []PositionedCell

DiffInto is Diff appending into dst, so a caller that diffs every frame can reuse one slice instead of allocating a new one each time. Pass dst[:0] to reuse the storage; the returned slice may have been reallocated if it grew.

The Terminal draws through here: on a full-screen redraw the update list is as large as the screen, and allocating that per frame was the single biggest source of garbage in a scrolling application.

func (*Buffer) DiffSeq

func (b *Buffer) DiffSeq(next *Buffer) iter.Seq[PositionedCell]

DiffSeq yields the cells that must be written to turn prev into next.

The two buffers must share an X, Y and Width; only the height may differ, in which case the shorter one wins. Prefer this over Diff to avoid building the intermediate slice.

func (*Buffer) Get

func (b *Buffer) Get(x, y uint16) *Cell

Get returns a pointer to the cell at (x, y), panicking if it is out of bounds. Use Cell when a position outside the buffer is expected.

func (*Buffer) IndexOf

func (b *Buffer) IndexOf(x, y uint16) int

IndexOf returns the index in Content of the cell at the absolute position (x, y). It panics if the position is outside the buffer, since that always means a widget drew outside the area it was given.

func (*Buffer) Merge

func (b *Buffer) Merge(other *Buffer)

Merge draws another buffer into this one, growing this buffer's area to the union of the two. Where they overlap, the other buffer wins.

func (*Buffer) PosOf

func (b *Buffer) PosOf(index int) (x, y uint16)

PosOf returns the absolute position of the cell at the given index in Content. It panics if the index is out of range.

func (*Buffer) Reset

func (b *Buffer) Reset()

Reset blanks every cell, keeping the area.

func (*Buffer) Resize

func (b *Buffer) Resize(area Rect)

Resize remaps the buffer onto a new area, growing or shrinking Content to match. Cells are not moved, so after a resize the contents are only meaningful once redrawn.

func (*Buffer) SetLine

func (b *Buffer) SetLine(x, y uint16, line Line, maxWidth uint16) (nextX, nextY uint16)

SetLine draws a line at (x, y), clipped to maxWidth. Each span is drawn in the line's style patched with the span's own.

func (*Buffer) SetSpan

func (b *Buffer) SetSpan(x, y uint16, span Span, maxWidth uint16) (nextX, nextY uint16)

SetSpan draws a span at (x, y), in the span's own style, clipped to maxWidth.

func (*Buffer) SetString

func (b *Buffer) SetString(x, y uint16, s string, style Style) (nextX, nextY uint16)

SetString draws s at (x, y) in the given style, stopping at the right edge of the buffer.

func (*Buffer) SetStringn

func (b *Buffer) SetStringn(x, y uint16, s string, maxWidth uint16, style Style) (nextX, nextY uint16)

SetStringn draws at most maxWidth columns of s at (x, y) in the given style, and returns the position just past what it drew.

This is the single place text becomes cells, and its edge behaviour is load bearing:

  • Grapheme clusters are the unit, so a base character and its combining marks land in one cell together.
  • Control characters and zero-width clusters are dropped.
  • A cluster wider than the space left is NOT clipped. It is dropped, the cell keeps whatever it held, and drawing stops there — the rest of the string is not drawn either. Callers that must fill every column have to pad the remainder themselves.
  • The continuation columns of a wide cluster are reset to blank cells, not to the style being drawn.
Example

A grapheme cluster that does not fit in the space left is dropped rather than clipped, and drawing stops there. StringWidth measures exactly what SetStringn fills.

package main

import (
	"fmt"

	"github.com/Fiend3d/catatui"
)

func main() {
	buf := catatui.NewBuffer(catatui.NewRect(0, 0, 5, 1))

	// "日" is two columns wide, so three of them need six.
	buf.SetStringn(0, 0, "日本語", 5, catatui.NewStyle())

	fmt.Printf("%q width=%d\n", buf.String(), catatui.StringWidth("日本語"))
}
Output:
"日本 " width=6

func (*Buffer) SetStyle

func (b *Buffer) SetStyle(area Rect, style Style)

SetStyle applies a style to every cell in the given area, clipped to the buffer. It changes styling only, leaving the symbols alone.

func (*Buffer) String

func (b *Buffer) String() string

String renders the buffer as one string per row, joined by newlines, with all styling dropped. It is meant for test failure messages.

A symbol wider than one cell is written once, and the cells it covers are stepped over, so a row of the string is as wide as the row of the terminal rather than wider.

type Cell

type Cell struct {
	// Symbol is the grapheme cluster drawn in this cell, which may be wider
	// than one column. The empty string means the default symbol, a space.
	Symbol string

	// Fg is the foreground color.
	Fg Color

	// Bg is the background color.
	Bg Color

	// UnderlineColor is the underline color, which only some terminals render
	// separately from the text color.
	UnderlineColor Color

	// Modifier holds the text attributes.
	Modifier Modifier

	// DiffOption controls how the cell takes part in the frame diff.
	DiffOption CellDiffOption
}

Cell is a single character cell of the terminal: a grapheme cluster plus the style it is drawn in.

The zero Cell is a valid empty cell, equivalent to EmptyCell: an empty Symbol reads back as a single space, and unset colors read back as ColorReset. Unlike Style, a Cell's colors are always concrete, never "inherit".

Do not compare Cells with ==. A cell with no symbol and a cell holding a single space are the same cell, and only Equal knows that.

func EmptyCell

func EmptyCell() Cell

EmptyCell returns a blank cell: no symbol, every color reset, no modifiers.

func NewCell

func NewCell(symbol string) Cell

NewCell returns an empty cell displaying the given symbol.

func (Cell) Equal

func (c Cell) Equal(other Cell) bool

Equal reports whether two cells would draw identically. A cell with no symbol and a cell holding a single space compare equal, as do unset and reset colors, so that cells built different ways still diff as unchanged.

func (Cell) GetStyle

func (c Cell) GetStyle() Style

GetStyle returns the cell's style. Every color is set, since a cell always has concrete colors, and no modifiers are subtracted.

func (Cell) GetSymbol

func (c Cell) GetSymbol() string

GetSymbol returns the symbol drawn in the cell, which is a single space when no symbol is set.

func (*Cell) MergeSymbol

func (c *Cell) MergeSymbol(symbol string, strategy symbols.MergeStrategy) *Cell

MergeSymbol draws symbol over whatever the cell already holds, combining the two into a single box-drawing character where one exists. It is how a Block collapses its border into the border of the block beside it; see symbols.MergeStrategy for what each strategy does.

A cell with no symbol set takes the new symbol as it is, rather than merging, so drawing onto a fresh buffer behaves the same as SetSymbol. Merging is limited to characters in Unicode's Box Drawing block.

buf.Get(x, y).MergeSymbol(symbols.Horizontal, symbols.MergeExact)

func (*Cell) Reset

func (c *Cell) Reset()

Reset returns the cell to the empty state.

func (*Cell) SetBg

func (c *Cell) SetBg(color Color) *Cell

SetBg sets the background color.

func (*Cell) SetChar

func (c *Cell) SetChar(r rune) *Cell

SetChar sets the cell's symbol to a single rune.

func (*Cell) SetDiffOption

func (c *Cell) SetDiffOption(o CellDiffOption) *Cell

SetDiffOption sets how the cell takes part in the frame diff.

func (*Cell) SetFg

func (c *Cell) SetFg(color Color) *Cell

SetFg sets the foreground color.

func (*Cell) SetSkip

func (c *Cell) SetSkip(skip bool) *Cell

SetSkip is shorthand for setting CellDiffSkip or CellDiffNone.

func (*Cell) SetStyle

func (c *Cell) SetStyle(s Style) *Cell

SetStyle applies a style to the cell. Colors the style leaves unset are kept, which is what makes styles layer.

func (*Cell) SetSymbol

func (c *Cell) SetSymbol(symbol string) *Cell

SetSymbol sets the grapheme cluster drawn in the cell.

func (Cell) Skip

func (c Cell) Skip() bool

Skip reports whether the cell is skipped when flushed to the screen.

func (Cell) Width

func (c Cell) Width() uint16

Width is the number of columns the cell occupies, honouring a forced width.

type CellDiffOption

type CellDiffOption struct {
	// contains filtered or unexported fields
}

CellDiffOption controls how a cell takes part in the diff against the previous frame.

It exists for cells whose on-screen appearance the buffer cannot infer from the symbol alone: cells covered by terminal graphics, cells another renderer draws over, and escape sequences whose printed width differs from their text width.

func CellForcedWidth

func CellForcedWidth(width uint16) CellDiffOption

CellForcedWidth forces the cell to occupy the given number of columns regardless of the width of its symbol. The width must be greater than zero; CellForcedWidth(0) returns CellDiffNone, matching the NonZeroU16 that ratatui's ForcedWidth carries.

func (CellDiffOption) ForcedWidth

func (o CellDiffOption) ForcedWidth() (uint16, bool)

ForcedWidth reports whether the option forces a width, returning it if so.

func (CellDiffOption) Kind

Kind returns which diff option this is.

type CellDiffOptionKind

type CellDiffOptionKind uint8

CellDiffOptionKind tags a CellDiffOption.

const (
	// DiffNone applies no special handling.
	DiffNone CellDiffOptionKind = iota
	// DiffSkip omits the cell when the buffer is flushed to the screen.
	DiffSkip
	// DiffAlwaysUpdate redraws the cell even when it is unchanged.
	DiffAlwaysUpdate
	// DiffForcedWidth overrides the width computed from the symbol.
	DiffForcedWidth
)

type ClearType

type ClearType uint8

ClearType selects how much of the screen a ClearRegion call erases.

const (
	// ClearAll erases the whole screen.
	ClearAll ClearType = iota
	// ClearAfterCursor erases from the cursor to the end of the screen.
	ClearAfterCursor
	// ClearBeforeCursor erases from the start of the screen to the cursor.
	ClearBeforeCursor
	// ClearCurrentLine erases the line the cursor is on.
	ClearCurrentLine
	// ClearUntilNewLine erases from the cursor to the end of its line.
	ClearUntilNewLine
)

func (ClearType) String

func (c ClearType) String() string

String returns the clear type's name.

type Color

type Color struct {
	// contains filtered or unexported fields
}

Color is an ANSI color: a named 4-bit color, an 8-bit indexed color, a 24-bit RGB color, an explicit reset, or unset.

Color is comparable, so colors and the Styles containing them can be compared with == and used as map keys.

func Indexed

func Indexed(i uint8) Color

Indexed returns an 8-bit color from the 256-color palette.

func ParseColor

func ParseColor(s string) (Color, error)

ParseColor parses a color name, a decimal 8-bit index, or a "#RRGGBB" hex string. It accepts the same spellings ratatui does: "bright" and "light" prefixes, "grey" and "gray", "silver", and space, dash or underscore separators.

func Rgb

func Rgb(r, g, b uint8) Color

Rgb returns a 24-bit true color. Only terminals with true color support will display it correctly.

func RgbFromU32

func RgbFromU32(u uint32) Color

RgbFromU32 returns an RGB color from a 0x00RRGGBB value.

func (Color) Index

func (c Color) Index() (index uint8, ok bool)

Index reports whether c is an 8-bit indexed color, returning its index if so.

func (Color) IsReset

func (c Color) IsReset() bool

IsReset reports whether the color is an explicit ColorReset.

func (Color) IsSet

func (c Color) IsSet() bool

IsSet reports whether the color is anything other than the zero value. An unset color leaves whatever color is already in the cell untouched.

func (Color) Named

func (c Color) Named() (ordinal uint8, ok bool)

Named reports whether c is one of the sixteen named ANSI colors, returning its ordinal (0..15) if so.

func (Color) RGB

func (c Color) RGB() (r, g, b uint8, ok bool)

RGB reports whether c is a 24-bit color, returning its components if so.

func (Color) String

func (c Color) String() string

String formats the color the way ratatui's Display impl does: named colors by name, RGB as "#RRGGBB", indexed as a decimal number. The result round-trips through ParseColor.

type Constraint

type Constraint struct {
	// contains filtered or unexported fields
}

Constraint describes how much of an area one segment of a Layout should take.

Constraints are requests, not guarantees. When they cannot all be met, the solver honours them in this order of priority: Min and Max first, then Length, then Percentage, then Ratio, then Fill.

The zero value is Min(0), matching the first variant of ratatui's enum, but build them with the constructors rather than relying on that.

func Fill

func Fill(scale uint16) Constraint

Fill requests whatever space is left, shared with the other Fill constraints in proportion to their scaling factors. It has the lowest priority.

func Length

func Length(n uint16) Constraint

Length requests exactly n cells.

func Max

func Max(n uint16) Constraint

Max requests at most n cells.

func Min

func Min(n uint16) Constraint

Min requests at least n cells. It has the highest priority alongside Max, and grows to fill leftover space.

func Percentage

func Percentage(p uint16) Constraint

Percentage requests p percent of the available space, rounded to the nearest cell.

func Ratio

func Ratio(num, den uint32) Constraint

Ratio requests num/den of the available space. A zero denominator is treated as one.

func (Constraint) IsPercentage

func (c Constraint) IsPercentage() (uint16, bool)

IsPercentage reports whether c is a Percentage constraint, and if so what percentage it asks for.

func (Constraint) Kind

func (c Constraint) Kind() ConstraintKind

Kind returns which kind of constraint this is.

switch constraint.Kind() {
case catatui.ConstraintMin:
	...
}

func (Constraint) String

func (c Constraint) String() string

String formats the constraint the way ratatui's Display impl does.

type ConstraintKind

type ConstraintKind uint8

ConstraintKind is which of ratatui's Constraint variants a Constraint is.

Rust makes Constraint an enum, so code that has to treat each kind differently — colouring them, say, or reporting a layout — matches on it. Go has no enums with payloads, so Constraint is an opaque value and Kind is how that code asks.

const (
	// ConstraintMin is Min(n), and the zero value.
	ConstraintMin ConstraintKind = iota
	// ConstraintMax is Max(n).
	ConstraintMax
	// ConstraintLength is Length(n).
	ConstraintLength
	// ConstraintPercentage is Percentage(p).
	ConstraintPercentage
	// ConstraintRatio is Ratio(num, den).
	ConstraintRatio
	// ConstraintFill is Fill(scale).
	ConstraintFill
)

func (ConstraintKind) String

func (k ConstraintKind) String() string

String returns the kind's name, which is the constructor's name.

type Direction

type Direction uint8

Direction is the axis a Layout splits along.

const (
	// Vertical splits into rows, top to bottom. It is the zero value, because
	// ratatui marks Vertical as Direction's default even though it lists
	// Horizontal first. Matching the default matters here; matching the
	// declaration order would not, since nothing depends on the ordinal.
	Vertical Direction = iota
	// Horizontal splits into columns, left to right.
	Horizontal
)

func (Direction) String

func (d Direction) String() string

String returns the direction's name.

type Flex

type Flex uint8

Flex decides what to do with space left over once every Constraint is satisfied.

const (
	// FlexStart packs segments at the start and leaves the excess at the end.
	// This is the zero value and ratatui's default.
	FlexStart Flex = iota
	// FlexLegacy puts the excess into the last constraint, which is how ratatui
	// and tui-rs behaved before Flex existed.
	FlexLegacy
	// FlexEnd packs segments at the end and leaves the excess at the start.
	FlexEnd
	// FlexCenter centers the segments, splitting the excess between both ends.
	FlexCenter
	// FlexSpaceBetween spreads the excess evenly between segments, with none at
	// the ends.
	FlexSpaceBetween
	// FlexSpaceEvenly spreads the excess evenly between segments and at both
	// ends.
	FlexSpaceEvenly
	// FlexSpaceAround spreads the excess between segments, giving the ends half
	// as much as the gaps between segments.
	FlexSpaceAround
)

func (Flex) String

func (f Flex) String() string

String returns the flex mode's name.

type Frame

type Frame struct {
	// contains filtered or unexported fields
}

Frame is the drawing surface for a single frame.

A Frame is handed to the callback passed to Terminal.Draw and is only valid for the duration of that call; do not keep it.

func (*Frame) Area

func (f *Frame) Area() Rect

Area returns the region the frame covers.

func (*Frame) Buffer

func (f *Frame) Buffer() *Buffer

Buffer returns the frame's buffer, for widgets that draw cells directly rather than through a Widget. This is how a program can bypass the widget layer entirely and treat catatui as a cell grid.

func (*Frame) Count

func (f *Frame) Count() uint64

Count returns how many frames have been drawn before this one, which is handy for driving animations.

func (*Frame) RenderWidget

func (f *Frame) RenderWidget(w Widget, area Rect)

RenderWidget draws a widget into the given area of the frame.

func (*Frame) SetCursor

func (f *Frame) SetCursor(x, y uint16)

SetCursor is SetCursorPosition taking loose coordinates.

func (*Frame) SetCursorPosition

func (f *Frame) SetCursorPosition(p Position)

SetCursorPosition puts the terminal cursor at the given position after the frame is drawn. A frame that never calls this hides the cursor.

func (*Frame) Size

func (f *Frame) Size() Rect

Size returns the frame's area. It is a synonym for Area, kept because ratatui has both.

type Grapheme

type Grapheme struct {
	Symbol string
	Width  uint16
}

Grapheme is a complete drawing unit and its terminal advance. Indic conjuncts and the Tamil ksha/sri ligatures are kept together for shaping.

func Graphemes

func Graphemes(s string) []Grapheme

Graphemes collects the drawable clusters used by Buffer.SetStringn.

type Layout

type Layout struct {
	// contains filtered or unexported fields
}

Layout splits an area into segments according to a list of Constraints.

Build one with NewLayout, Horizontal or Vertical layouts via the direction helpers, then call Split:

rows := catatui.VerticalLayout(catatui.Length(3), catatui.Fill(1)).Split(area)

A Layout is a value; every builder returns a modified copy, so a Layout can be stored and reused safely.

func HorizontalLayout

func HorizontalLayout(constraints ...Constraint) Layout

HorizontalLayout returns a left-to-right layout with the given constraints.

func NewLayout

func NewLayout() Layout

NewLayout returns a vertical layout with no constraints, matching ratatui's Layout::default.

func VerticalLayout

func VerticalLayout(constraints ...Constraint) Layout

VerticalLayout returns a top-to-bottom layout with the given constraints.

func (Layout) Constraints

func (l Layout) Constraints(constraints ...Constraint) Layout

Constraints returns a copy of l with the given constraints.

func (Layout) Direction

func (l Layout) Direction(d Direction) Layout

Direction returns a copy of l splitting along the given axis.

func (Layout) Flex

func (l Layout) Flex(f Flex) Layout

Flex returns a copy of l with the given handling of leftover space.

func (Layout) GetConstraints

func (l Layout) GetConstraints() []Constraint

GetConstraints returns the layout's constraints.

func (Layout) GetDirection

func (l Layout) GetDirection() Direction

GetDirection returns the layout's axis.

func (Layout) GetFlex

func (l Layout) GetFlex() Flex

GetFlex returns how the layout handles leftover space.

func (Layout) GetMargin

func (l Layout) GetMargin() Margin

GetMargin returns the layout's margin.

func (Layout) GetSpacing

func (l Layout) GetSpacing() Spacing

GetSpacing returns the gap between segments.

func (Layout) Horizontal

func (l Layout) Horizontal() Layout

Horizontal returns a copy of l splitting into columns.

func (Layout) HorizontalMargin

func (l Layout) HorizontalMargin(n uint16) Layout

HorizontalMargin returns a copy of l inset by n cells on the left and right.

func (Layout) Margin

func (l Layout) Margin(n uint16) Layout

Margin returns a copy of l inset by n cells on every side.

func (Layout) Spacing

func (l Layout) Spacing(s Spacing) Layout

Spacing returns a copy of l with the given gap between segments.

Example

Spacing puts a gap between the parts; Overlap makes them share cells, which is how neighbouring blocks come to share a border.

package main

import (
	"fmt"

	"github.com/Fiend3d/catatui"
)

func main() {
	area := catatui.NewRect(0, 0, 20, 3)

	spaced := catatui.HorizontalLayout(catatui.Fill(1), catatui.Fill(1)).
		Spacing(catatui.Space(2)).Split(area)
	overlapped := catatui.HorizontalLayout(catatui.Fill(1), catatui.Fill(1)).
		Spacing(catatui.Overlap(1)).Split(area)

	fmt.Println("spaced:    ", spaced[0], spaced[1])
	fmt.Println("overlapped:", overlapped[0], overlapped[1])
}
Output:
spaced:     {0 0 9 3} {11 0 9 3}
overlapped: {0 0 11 3} {10 0 10 3}

func (Layout) Split

func (l Layout) Split(area Rect) []Rect

Split divides area into one Rect per constraint.

The returned slice always has exactly len(constraints) entries. Segments may be empty when the area is too small to satisfy everything.

Example

Constraints decide how a rect is divided. Length takes a fixed number of cells, Fill shares out what is left.

package main

import (
	"fmt"

	"github.com/Fiend3d/catatui"
)

func main() {
	area := catatui.NewRect(0, 0, 20, 10)

	columns := catatui.HorizontalLayout(
		catatui.Length(4),
		catatui.Fill(1),
		catatui.Percentage(25),
	).Split(area)

	for _, column := range columns {
		fmt.Printf("x=%d width=%d\n", column.X, column.Width)
	}
}
Output:
x=0 width=4
x=4 width=11
x=15 width=5

func (Layout) SplitWithSpacers

func (l Layout) SplitWithSpacers(area Rect) (segments, spacers []Rect)

SplitWithSpacers divides area into one Rect per constraint, and also returns the gaps between them.

There is always one more spacer than there are segments: one before the first segment, one between each adjacent pair, and one after the last. Widgets that draw in the gaps, such as collapsed borders, use these.

func (Layout) String

func (l Layout) String() string

String describes the layout, for debugging.

func (Layout) Vertical

func (l Layout) Vertical() Layout

Vertical returns a copy of l splitting into rows.

func (Layout) VerticalMargin

func (l Layout) VerticalMargin(n uint16) Layout

VerticalMargin returns a copy of l inset by n cells on the top and bottom.

type Line

type Line struct {
	// contains filtered or unexported fields
}

Line is a single row of styled text, made of one or more Spans.

A Line's own Style sits underneath its spans' styles, and its Alignment overrides whatever the containing widget would otherwise use.

func LineFromString

func LineFromString(s string) Line

LineFromString returns an unstyled single-span line.

func LineFromStyledString

func LineFromStyledString(s string, style Style) Line

LineFromStyledString returns a single-span line in the given style. The style is applied to the span, matching ratatui's Line::styled.

func NewLine

func NewLine(spans ...Span) Line

NewLine returns a line made of the given spans.

func (Line) Alignment

func (l Line) Alignment(a Alignment) Line

Alignment returns a copy of l with the alignment replaced.

func (Line) Centered

func (l Line) Centered() Line

Centered returns a copy of l centered in its area.

func (Line) GetAlignment

func (l Line) GetAlignment() Alignment

GetAlignment returns the line's alignment, which may be AlignmentNone.

func (Line) GetSpans

func (l Line) GetSpans() []Span

GetSpans returns the line's spans. The slice is the line's own; do not modify it.

func (Line) GetStyle

func (l Line) GetStyle() Style

GetStyle returns the line's style.

func (Line) Left

func (l Line) Left() Line

Left returns a copy of l aligned to the left.

func (Line) Patch

func (l Line) Patch(style Style) Line

Patch returns a copy of l with the given style layered on top of its own.

func (Line) Render

func (l Line) Render(area Rect, buf *Buffer)

Render draws the line on the first row of the area, honouring its own alignment.

func (Line) RenderWithFallbackAlignment

func (l Line) RenderWithFallbackAlignment(area Rect, buf *Buffer, parent Alignment)

RenderWithFallbackAlignment draws the line, falling back to the given alignment when the line does not set one of its own. Container widgets use it to impose their alignment on the lines they hold.

A line that is too wide is truncated on the right, so the alignment decides how much is skipped on the left: a right-aligned line drops its beginning, a centered one drops half from each side.

func (Line) Right

func (l Line) Right() Line

Right returns a copy of l aligned to the right.

func (Line) Spans

func (l Line) Spans(spans ...Span) Line

Spans returns a copy of l with the spans replaced.

func (Line) String

func (l Line) String() string

String returns the line's text with all styling dropped.

func (Line) Style

func (l Line) Style(style Style) Line

Style returns a copy of l with the line style replaced. The line style sits beneath the spans' own styles.

func (Line) Width

func (l Line) Width() int

Width is the number of columns the line occupies when drawn.

type Margin

type Margin struct {
	Horizontal uint16
	Vertical   uint16
}

Margin is a horizontal and vertical inset, applied to both sides of each axis.

func NewMargin

func NewMargin(horizontal, vertical uint16) Margin

NewMargin returns a Margin with the given horizontal and vertical insets.

type Modifier

type Modifier uint16

Modifier is a set of text attributes, held as a bitflag exactly as ratatui's bitflags-generated Modifier is.

Note that not every terminal supports every modifier, and some that do support them render several identically.

const (
	ModifierBold Modifier = 1 << iota
	ModifierDim
	ModifierItalic
	ModifierUnderlined
	ModifierSlowBlink
	ModifierRapidBlink
	ModifierReversed
	ModifierHidden
	ModifierCrossedOut

	// ModifierNone is the empty set.
	ModifierNone Modifier = 0
	// ModifierAll is every modifier at once. Style.Reset uses it as the
	// sub_modifier so that a reset clears whatever was set beneath it.
	ModifierAll Modifier = 1<<9 - 1
)

func (Modifier) Contains

func (m Modifier) Contains(other Modifier) bool

Contains reports whether every modifier in other is set in m.

func (Modifier) Insert

func (m Modifier) Insert(other Modifier) Modifier

Insert returns m with every modifier in other added.

func (Modifier) Intersects

func (m Modifier) Intersects(other Modifier) bool

Intersects reports whether any modifier in other is set in m.

func (Modifier) IsEmpty

func (m Modifier) IsEmpty() bool

IsEmpty reports whether no modifiers are set.

func (Modifier) Remove

func (m Modifier) Remove(other Modifier) Modifier

Remove returns m with every modifier in other cleared.

func (Modifier) String

func (m Modifier) String() string

String formats the set the way the bitflags crate does, e.g. "BOLD | ITALIC" or "NONE" when empty.

type Offset

type Offset struct {
	X int32
	Y int32
}

Offset is a signed displacement applied to a Rect. Positive X moves right, positive Y moves down.

type Position

type Position struct {
	X uint16
	Y uint16
}

Position is a single point in the terminal, in cells, measured from the top left corner.

type PositionedCell

type PositionedCell struct {
	X    uint16
	Y    uint16
	Cell Cell
}

PositionedCell is one cell of a diff: the cell together with where it goes.

type Rect

type Rect struct {
	X      uint16
	Y      uint16
	Width  uint16
	Height uint16
}

Rect is a rectangular area of the terminal, in cells.

The zero value is an empty rect at the origin. A Rect built with NewRect is guaranteed never to extend past uint16 max: the constructor clamps Width and Height so that Right and Bottom stay in range.

func NewRect

func NewRect(x, y, width, height uint16) Rect

NewRect returns a Rect, clamping Width and Height so the right and bottom edges stay within uint16.

func (Rect) Area

func (r Rect) Area() uint32

Area is the number of cells in the rect. It is a uint32 because a full uint16-by-uint16 rect overflows uint16.

func (Rect) AsPosition

func (r Rect) AsPosition() Position

AsPosition returns the rect's top left corner.

func (Rect) AsSize

func (r Rect) AsSize() Size

AsSize returns the rect's size, discarding its position.

func (Rect) Bottom

func (r Rect) Bottom() uint16

Bottom is the first y coordinate below the rect, clamped to uint16 max.

func (Rect) Clamp

func (r Rect) Clamp(other Rect) Rect

Clamp moves and shrinks r so it fits inside other.

This differs from Intersection: Clamp slides r to fit, preserving as much of its size as it can, while Intersection keeps r's position and truncates.

func (Rect) Columns

func (r Rect) Columns() []Rect

Columns returns one width-1 rect per column of r, left to right.

func (Rect) Contains

func (r Rect) Contains(p Position) bool

Contains reports whether the position lies inside the rect. Positions on the left and top borders are inside; the right and bottom edges are not.

func (Rect) Inner

func (r Rect) Inner(m Margin) Rect

Inner returns the rect inset by the margin on each side. If the margin is larger than the rect, the result is empty.

func (Rect) Intersection

func (r Rect) Intersection(other Rect) Rect

Intersection returns the overlap of r and other, which is empty if they do not overlap.

func (Rect) Intersects

func (r Rect) Intersects(other Rect) bool

Intersects reports whether r and other overlap.

func (Rect) IsEmpty

func (r Rect) IsEmpty() bool

IsEmpty reports whether the rect has no area.

func (Rect) Left

func (r Rect) Left() uint16

Left is the x coordinate of the leftmost column in the rect.

func (Rect) Offset

func (r Rect) Offset(o Offset) Rect

Offset moves the rect without changing its size. If the offset would push an edge outside uint16, the position is clamped to the nearest edge.

func (Rect) Outer

func (r Rect) Outer(m Margin) Rect

Outer returns the rect grown by the margin on each side, truncated to keep the bounds within uint16. The result may fall outside the containing area, so consider Clamp before using it.

func (Rect) Positions

func (r Rect) Positions() []Position

Positions returns every position in r in row-major order.

func (Rect) Resize

func (r Rect) Resize(s Size) Rect

Resize changes the size, keeping the position and clamping so that Right and Bottom stay within uint16.

func (Rect) Right

func (r Rect) Right() uint16

Right is the first x coordinate to the right of the rect, clamped to uint16 max.

func (Rect) Rows

func (r Rect) Rows() []Rect

Rows returns one height-1 rect per row of r, top to bottom.

func (Rect) Top

func (r Rect) Top() uint16

Top is the y coordinate of the topmost row in the rect.

func (Rect) Union

func (r Rect) Union(other Rect) Rect

Union returns the smallest rect containing both r and other.

type Size

type Size struct {
	Width  uint16
	Height uint16
}

Size is a width and height in cells, with no position.

type Spacing

type Spacing struct {
	// contains filtered or unexported fields
}

Spacing is the gap between segments. A positive spacing separates them; an overlap makes them share cells, which is how collapsed borders are drawn.

func Overlap

func Overlap(n uint16) Spacing

Overlap returns a negative spacing, so that adjacent segments share n cells.

func Space

func Space(n uint16) Spacing

Space returns a spacing of n cells between segments.

func (Spacing) String

func (s Spacing) String() string

String returns the spacing's description.

type Span

type Span struct {
	// contains filtered or unexported fields
}

Span is a run of text drawn in a single style. It is the smallest unit of styled text, and never contains a line break.

func NewSpan

func NewSpan(content string) Span

NewSpan returns an unstyled span holding the given content. It is the equivalent of ratatui's Span::raw.

func NewStyledSpan

func NewStyledSpan(content string, style Style) Span

NewStyledSpan returns a span holding the given content in the given style.

func (Span) Content

func (s Span) Content(content string) Span

Content returns a copy of s with the content replaced.

func (Span) GetContent

func (s Span) GetContent() string

GetContent returns the span's text.

func (Span) GetStyle

func (s Span) GetStyle() Style

GetStyle returns the span's style.

func (Span) Patch

func (s Span) Patch(style Style) Span

Patch returns a copy of s with the given style layered on top of its own.

func (Span) Render

func (s Span) Render(area Rect, buf *Buffer)

Render draws the span at the top left of the area, clipped to its width.

func (Span) String

func (s Span) String() string

String returns the span's text, so a Span prints as its content.

func (Span) Style

func (s Span) Style(style Style) Span

Style returns a copy of s with the style replaced. The style is not patched onto the existing one; use Patch for that.

func (Span) Width

func (s Span) Width() int

Width is the number of columns the span occupies when drawn.

type StatefulWidget

type StatefulWidget[S any] interface {
	RenderStateful(area Rect, buf *Buffer, state *S)
}

StatefulWidget is a Widget that reads and updates caller-owned state, such as which row of a list is selected or how far a view is scrolled.

The state lives with the caller and outlives the widget, which is what lets a list remember its selection while the widget itself is rebuilt each frame.

Deviation from ratatui: Rust declares the state as an associated type on the trait. Go has no associated types, so the interface is generic over the state and rendering goes through the free function RenderStatefulWidget rather than a method on Frame — Go methods cannot have their own type parameters.

type Style

type Style struct {
	// contains filtered or unexported fields
}

Style is a set of optional styling attributes applied to a run of text.

A Style is a *diff* against whatever is already in the cell, not an absolute description of it. An unset color or an absent modifier leaves the underlying value alone; this is what lets styles be layered with Patch. Use ResetStyle for a Style that overrides everything.

Style is comparable, so styles can be compared with == and used as map keys.

style := NewStyle().Fg(ColorRed).Bg(ColorBlack).AddModifier(ModifierBold)

Deviation from ratatui: Rust exposes both public fields (`style.fg`) and same-named builder methods (`style.fg(color)`). Go allows only one, so the fields are unexported, the builders keep ratatui's names, and readers use the Get* accessors.

func NewStyle

func NewStyle() Style

NewStyle returns the empty style, which changes nothing. It is identical to the zero value and exists for symmetry with ratatui's Style::new().

func ResetStyle

func ResetStyle() Style

ResetStyle returns a Style that resets every property: all three colors are set to ColorReset and every modifier is cleared.

func (Style) AddModifier

func (s Style) AddModifier(m Modifier) Style

AddModifier returns a copy of s with the given modifiers added, and removed from the set of modifiers s clears.

func (Style) Bg

func (s Style) Bg(c Color) Style

Bg returns a copy of s with the background color set.

func (Style) Fg

func (s Style) Fg(c Color) Style

Fg returns a copy of s with the foreground color set.

func (Style) GetAddModifier

func (s Style) GetAddModifier() Modifier

GetAddModifier returns the modifiers this style turns on.

func (Style) GetBg

func (s Style) GetBg() Color

GetBg returns the background color, which may be unset.

func (Style) GetFg

func (s Style) GetFg() Color

GetFg returns the foreground color, which may be unset.

func (Style) GetSubModifier

func (s Style) GetSubModifier() Modifier

GetSubModifier returns the modifiers this style turns off.

func (Style) GetUnderlineColor

func (s Style) GetUnderlineColor() Color

GetUnderlineColor returns the underline color, which may be unset.

func (Style) IsEmpty

func (s Style) IsEmpty() bool

IsEmpty reports whether the style changes nothing.

func (Style) Patch

func (s Style) Patch(other Style) Style

Patch layers other on top of s and returns the result. Set properties of other win; unset ones leave s's values in place.

Patching is associative: patching with the result of patching two styles together is the same as patching with each in turn.

Example

Styles layer rather than replace: an unset color inherits whatever is underneath, so patching a foreground over a background keeps both.

package main

import (
	"fmt"

	"github.com/Fiend3d/catatui"
)

func main() {
	base := catatui.NewStyle().
		Fg(catatui.ColorWhite).
		Bg(catatui.ColorBlue)

	// Only the foreground is set here, so the blue background survives.
	patched := base.Patch(catatui.NewStyle().
		Fg(catatui.ColorYellow).
		AddModifier(catatui.ModifierBold))

	fmt.Println(patched.GetFg(), patched.GetBg(), patched.GetAddModifier())
}
Output:
Yellow Blue BOLD

func (Style) RemoveModifier

func (s Style) RemoveModifier(m Modifier) Style

RemoveModifier returns a copy of s with the given modifiers cleared, and removed from the set of modifiers s adds.

func (Style) UnderlineColor

func (s Style) UnderlineColor(c Color) Style

UnderlineColor returns a copy of s with the underline color set. Only some terminals support colouring the underline separately from the text.

type Terminal

type Terminal struct {
	// contains filtered or unexported fields
}

Terminal drives a Backend, keeping two buffers so that each frame only writes the cells that actually changed.

Draw is the whole interface in normal use: it resizes if the terminal changed, hands a Frame to the callback, diffs the result against the previous frame, and writes only the difference.

func NewTerminal

func NewTerminal(backend Backend) (*Terminal, error)

NewTerminal returns a Terminal drawing to the whole of the given backend.

func NewTerminalWithViewport

func NewTerminalWithViewport(backend Backend, viewport Viewport) (*Terminal, error)

NewTerminalWithViewport returns a Terminal drawing into the given viewport.

func (*Terminal) Autoresize

func (t *Terminal) Autoresize() error

Autoresize resizes the terminal if it has changed size since the last frame. Fixed viewports are left alone.

func (*Terminal) Backend

func (t *Terminal) Backend() Backend

Backend returns the terminal's backend.

func (*Terminal) Clear

func (t *Terminal) Clear() error

Clear erases the viewport and forces the next frame to redraw every cell.

func (*Terminal) CurrentBuffer

func (t *Terminal) CurrentBuffer() *Buffer

CurrentBuffer returns the buffer being drawn into. It is exposed mainly for tests and for code that draws cells outside the normal Draw cycle.

func (*Terminal) Draw

func (t *Terminal) Draw(render func(*Frame)) error

Draw renders one frame.

It resizes to match the terminal if needed, calls render into a fresh Frame, writes only the cells that changed since the previous frame, and positions the cursor where the frame asked (hiding it if the frame did not ask).

func (*Terminal) FrameCount

func (t *Terminal) FrameCount() uint64

FrameCount returns how many frames have been drawn.

func (*Terminal) GetCursorPosition

func (t *Terminal) GetCursorPosition() (Position, error)

GetCursorPosition reports where the cursor is.

func (*Terminal) GetFrame

func (t *Terminal) GetFrame() *Frame

GetFrame returns a Frame for the current buffer without drawing anything.

func (*Terminal) HideCursor

func (t *Terminal) HideCursor() error

HideCursor hides the terminal cursor.

func (*Terminal) InsertBefore

func (t *Terminal) InsertBefore(height uint16, draw func(*Buffer)) error

InsertBefore draws height lines above the viewport, pushing it down the screen or scrolling the screen up to make room, so that the lines become part of the scrollback.

This is how a program with an inline viewport emits log lines that stay on screen while the viewport keeps redrawing beneath them. It does nothing at all for a fullscreen or fixed viewport, which have no scrollback to write to.

The buffer handed to draw starts at the origin and is height rows of the viewport's width, whatever row the lines end up on.

The viewport is cleared afterwards, and the whole of it is rewritten by the next Draw: the screen has moved underneath the previous frame, so a diff against it would leave the parts that did not change where they used to be.

func (*Terminal) Resize

func (t *Terminal) Resize(area Rect) error

Resize remaps the terminal onto a new area and clears it.

func (*Terminal) SetCursorPosition

func (t *Terminal) SetCursorPosition(p Position) error

SetCursorPosition moves the cursor and records the position, so that an inline viewport can restore it across a resize.

func (*Terminal) ShowCursor

func (t *Terminal) ShowCursor() error

ShowCursor shows the terminal cursor.

func (*Terminal) Size

func (t *Terminal) Size() (Size, error)

Size reports the terminal's size in cells.

func (*Terminal) TryDraw

func (t *Terminal) TryDraw(render func(*Frame) error) error

TryDraw is Draw for a render callback that can fail. If the callback returns an error, nothing is written to the backend.

func (*Terminal) ViewportArea

func (t *Terminal) ViewportArea() Rect

ViewportArea returns the region the terminal draws into.

type TestBackend

type TestBackend struct {
	// contains filtered or unexported fields
}

TestBackend is a Backend that draws into an in-memory Buffer instead of a terminal.

It is how widget and terminal behaviour is tested without a tty: render a frame, then compare the backend's buffer against an expected one.

backend := catatui.NewTestBackend(10, 3)
term, _ := catatui.NewTerminal(backend)
term.Draw(func(f *catatui.Frame) {
	f.RenderWidget(myWidget, f.Area())
})
catatui.AssertBuffer(t, backend.Buffer(), expected)

func NewTestBackend

func NewTestBackend(width, height uint16) *TestBackend

NewTestBackend returns a TestBackend with a blank buffer of the given size.

func (*TestBackend) AppendLines

func (b *TestBackend) AppendLines(n uint16) error

AppendLines scrolls the buffer up by n lines, recording what fell off the top in Scrollback.

func (*TestBackend) Buffer

func (b *TestBackend) Buffer() *Buffer

Buffer returns the backend's buffer, holding everything drawn so far.

func (*TestBackend) Clear

func (b *TestBackend) Clear() error

Clear blanks the whole buffer.

func (*TestBackend) ClearRegion

func (b *TestBackend) ClearRegion(t ClearType) error

ClearRegion blanks part of the buffer.

func (*TestBackend) CursorHidden

func (b *TestBackend) CursorHidden() bool

CursorHidden reports whether the cursor is currently hidden.

func (*TestBackend) Draw

func (b *TestBackend) Draw(cells []PositionedCell) error

Draw writes cells into the backend's buffer.

func (*TestBackend) Flush

func (b *TestBackend) Flush() error

Flush does nothing; a TestBackend has no output to flush.

func (*TestBackend) GetCursorPosition

func (b *TestBackend) GetCursorPosition() (Position, error)

GetCursorPosition reports the cursor position.

func (*TestBackend) HideCursor

func (b *TestBackend) HideCursor() error

HideCursor hides the cursor.

func (*TestBackend) Resize

func (b *TestBackend) Resize(width, height uint16)

Resize changes the backend's size, discarding its contents.

func (*TestBackend) Scrollback

func (b *TestBackend) Scrollback() []string

Scrollback returns the lines that AppendLines has pushed off the top.

func (*TestBackend) SetCursorPosition

func (b *TestBackend) SetCursorPosition(p Position) error

SetCursorPosition moves the cursor.

func (*TestBackend) ShowCursor

func (b *TestBackend) ShowCursor() error

ShowCursor shows the cursor.

func (*TestBackend) Size

func (b *TestBackend) Size() (Size, error)

Size reports the buffer's size.

func (*TestBackend) WindowSize

func (b *TestBackend) WindowSize() (WindowSize, error)

WindowSize reports the buffer's size, with no pixel dimensions.

type TestingT

type TestingT interface {
	Helper()
	Errorf(format string, args ...any)
	FailNow()
}

TestingT is the slice of *testing.T that the assertion helpers need.

It is declared here rather than importing "testing" so that the assertions can live in the main package, where widgets and backends can reach them, without pulling the testing package's flags into a production binary.

type Text

type Text struct {
	// contains filtered or unexported fields
}

Text is a block of styled Lines.

Its Style sits underneath every line's style, and its Alignment applies to any line that does not set its own.

func NewText

func NewText(lines ...Line) Text

NewText returns a Text made of the given lines.

func TextFromString

func TextFromString(s string) Text

TextFromString returns a Text by splitting s on newlines, so that multi-line strings become multiple Lines. This matches ratatui's From<&str> for Text.

func TextFromStyledString

func TextFromStyledString(s string, style Style) Text

TextFromStyledString is TextFromString with a style applied to the whole block.

func (Text) Alignment

func (t Text) Alignment(a Alignment) Text

Alignment returns a copy of t with the alignment replaced.

func (Text) Centered

func (t Text) Centered() Text

Centered returns a copy of t centered in its area.

func (Text) GetAlignment

func (t Text) GetAlignment() Alignment

GetAlignment returns the text's alignment, which may be AlignmentNone.

func (Text) GetLines

func (t Text) GetLines() []Line

GetLines returns the text's lines. The slice is the text's own; do not modify it.

func (Text) GetStyle

func (t Text) GetStyle() Style

GetStyle returns the text's style.

func (Text) Height

func (t Text) Height() int

Height is the number of lines.

func (Text) Left

func (t Text) Left() Text

Left returns a copy of t aligned to the left.

func (Text) Lines

func (t Text) Lines(lines ...Line) Text

Lines returns a copy of t with the lines replaced.

func (Text) Patch

func (t Text) Patch(style Style) Text

Patch returns a copy of t with the given style layered on top of its own.

func (Text) Render

func (t Text) Render(area Rect, buf *Buffer)

Render draws the text, one line per row, honouring the text's alignment for any line that does not set its own.

func (Text) Right

func (t Text) Right() Text

Right returns a copy of t aligned to the right.

func (Text) String

func (t Text) String() string

String returns the text with all styling dropped, lines joined by newlines.

func (Text) Style

func (t Text) Style(style Style) Text

Style returns a copy of t with the style replaced.

func (Text) Width

func (t Text) Width() int

Width is the number of columns of the widest line.

type Viewport

type Viewport struct {
	// contains filtered or unexported fields
}

Viewport is the region of the terminal a Terminal draws into.

func FixedViewport

func FixedViewport(area Rect) Viewport

FixedViewport uses an explicit region that never autoresizes.

func FullscreenViewport

func FullscreenViewport() Viewport

FullscreenViewport uses the whole terminal.

func InlineViewport

func InlineViewport(height uint16) Viewport

InlineViewport uses height lines at the bottom of the terminal.

func (Viewport) Kind

func (v Viewport) Kind() ViewportKind

Kind returns which sort of viewport this is.

type ViewportKind

type ViewportKind uint8

ViewportKind selects how much of the terminal a Terminal owns.

const (
	// ViewportFullscreen uses the whole terminal, which is the usual choice for
	// an application drawing on the alternate screen.
	ViewportFullscreen ViewportKind = iota
	// ViewportInline uses a fixed number of lines at the bottom of the terminal,
	// leaving the scrollback above it intact.
	ViewportInline
	// ViewportFixed uses an explicit region and never resizes with the terminal.
	ViewportFixed
)

type Widget

type Widget interface {
	Render(area Rect, buf *Buffer)
}

Widget is anything that can draw itself into a region of a Buffer.

Widgets are immediate mode: they hold no state between frames and are built fresh each time, so a widget value is cheap and disposable. Implement Render on a value receiver, and treat the widget as consumed by the call, as ratatui does.

type Banner struct{ Text string }

func (b Banner) Render(area catatui.Rect, buf *catatui.Buffer) {
	buf.SetStringn(area.X, area.Y, b.Text, area.Width, catatui.NewStyle())
}

Render must not draw outside area. Buffer.Get panics on out-of-bounds coordinates precisely so that this shows up immediately rather than as corruption elsewhere on screen.

type WidgetFunc

type WidgetFunc func(area Rect, buf *Buffer)

WidgetFunc adapts a plain function to the Widget interface.

func (WidgetFunc) Render

func (f WidgetFunc) Render(area Rect, buf *Buffer)

Render calls f.

type WidthPolicy

type WidthPolicy uint8

WidthPolicy selects how grapheme clusters advance the terminal cursor.

const (
	// UnicodeWidth uses uniseg's widths, with halfwidth sound marks counted.
	UnicodeWidth WidthPolicy = iota
	// WindowsTerminalWidth implements Windows Terminal's grapheme mode:
	// spacing marks consume cells and Unicode clusters advance at most two.
	WindowsTerminalWidth
)

func (WidthPolicy) SegmentGraphemes

func (p WidthPolicy) SegmentGraphemes(s string) iter.Seq[Grapheme]

SegmentGraphemes segments and measures using p without changing the default.

func (WidthPolicy) StringWidth

func (p WidthPolicy) StringWidth(s string) int

StringWidth measures s under p without changing the default policy.

type WindowSize

type WindowSize struct {
	Columns Size
	Pixels  Size
}

WindowSize is the terminal's size in cells and, where the terminal reports it, in pixels. A zero pixel size means the terminal did not say.

Directories

Path Synopsis
examples
apps/advanced-widget-impl command
Command advanced-widget-impl shows the ways a type can be a widget, and what each one is for.
Command advanced-widget-impl shows the ways a type can be a widget, and what each one is for.
apps/async-github command
Command async-github fetches ratatui's open pull requests in the background and shows them in a table while the UI keeps running.
Command async-github fetches ratatui's open pull requests in the background and shows them in a table while the UI keeps running.
apps/calendar-explorer command
Command calendar-explorer draws a whole year of Monthly calendars, with the holidays and the solstices marked, in each of the styles the widget offers.
Command calendar-explorer draws a whole year of Monthly calendars, with the holidays and the solstices marked, in each of the styles the widget offers.
apps/canvas command
Command canvas draws four canvases at once: a world map, a scratchpad, a bouncing ball and a row of rectangles.
Command canvas draws four canvases at once: a world map, a scratchpad, a bouncing ball and a row of rectangles.
apps/chart command
Command chart draws four charts at once: a scrolling pair of sine waves, a bell curve as bars, a line through two points, and a scatter plot.
Command chart draws four charts at once: a scrolling pair of sine waves, a bell curve as bars, a line through two points, and a scatter plot.
apps/color-explorer command
Command color-explorer draws every colour catatui can name or number, so you can see what your terminal actually makes of them.
Command color-explorer draws every colour catatui can name or number, so you can see what your terminal actually makes of them.
apps/colors-rgb command
Command colors-rgb fills the terminal with every colour it can show, and animates them.
Command colors-rgb fills the terminal with every colour it can show, and animates them.
apps/constraint-explorer command
Command constraint-explorer lets you build a set of constraints and watch every Flex mode lay them out at once.
Command constraint-explorer lets you build a set of constraints and watch every Flex mode lay them out at once.
apps/constraints command
Command constraints shows what each kind of Constraint does, a tab per kind.
Command constraints shows what each kind of Constraint does, a tab per kind.
apps/custom-widget command
Command custom-widget is a button drawn from scratch, and three of them wired to the mouse.
Command custom-widget is a button drawn from scratch, and three of them wired to the mouse.
apps/demo command
Command demo is the original tui-rs demo, the one the ratatui README shows: three tabs of gauges, lists, charts, a table and a world map, all animating on a tick.
Command demo is the original tui-rs demo, the one the ratatui README shows: three tabs of gauges, lists, charts, a table and a world map, all animating on a tick.
apps/flex command
Command flex shows what each Flex mode does to the same set of constraints.
Command flex shows what each Flex mode does to the same set of constraints.
apps/gauge command
Command gauge fills four gauges at once, which is what shows the difference between the ways of measuring them.
Command gauge fills four gauges at once, which is what shows the difference between the ways of measuring them.
apps/getting-started command
Command getting-started is Purrfect Day, the app built in docs/getting-started.md.
Command getting-started is Purrfect Day, the app built in docs/getting-started.md.
apps/hello command
Command hello is a minimal catatui application: a constraint-driven layout, direct buffer drawing, and an event loop that blocks when idle.
Command hello is a minimal catatui application: a constraint-driven layout, direct buffer drawing, and an event loop that blocks when idle.
apps/hyperlink command
Command hyperlink draws a line of text that is a clickable link, using the OSC 8 escape sequence.
Command hyperlink draws a line of text that is a clickable link, using the OSC 8 escape sequence.
apps/inline command
Command inline shows the inline viewport: a fixed block of the terminal that redraws in place while finished lines scroll away above it.
Command inline shows the inline viewport: a fixed block of the terminal that redraws in place while finished lines scroll away above it.
apps/input-form command
Command input-form is a form with three fields and a focus that moves between them.
Command input-form is a form with three fields and a focus that moves between them.
apps/minimal command
Command minimal is the smallest catatui program that draws something: set up the terminal, draw one frame, quit on the first key.
Command minimal is the smallest catatui program that draws something: set up the terminal, draw one frame, quit on the first key.
apps/modifiers command
Command modifiers draws every modifier against every pairing of five foreground and background colours, so you can see which of them your terminal actually renders.
Command modifiers draws every modifier against every pairing of five foreground and background colours, so you can see which of them your terminal actually renders.
apps/mouse-drawing command
Command mouse-drawing is a scratchpad you draw on with the mouse.
Command mouse-drawing is a scratchpad you draw on with the mouse.
apps/panic command
Command panic shows what a panic does to the terminal, with catatui's recovery in place and without it.
Command panic shows what a panic does to the terminal, with catatui's recovery in place and without it.
apps/popup command
Command popup shows how to draw a popup over the top of the rest of the UI.
Command popup shows how to draw a popup over the top of the rest of the UI.
apps/release-header command
Command release-header draws the banner that goes with a catatui release: the logo over a rainbow shadow, the version, and a menu of the packages.
Command release-header draws the banner that goes with a catatui release: the logo over a rainbow shadow, the version, and a menu of the packages.
apps/scrollbar command
Command scrollbar draws four scrollbars over the same text, each built a different way.
Command scrollbar draws four scrollbars over the same text, each built a different way.
apps/table command
Command table is a table of people with a scrollbar, a moving selection and a colour scheme that can be changed while it runs.
Command table is a table of people with a scrollbar, a moving selection and a colour scheme that can be changed while it runs.
apps/todo-list command
Command todo-list is a todo list whose items can be selected and ticked off.
Command todo-list is a todo list whose items can be selected and ticked off.
apps/tracing command
Command tracing logs to a file while the terminal is given over to the UI, and shows the last few events it handled.
Command tracing logs to a file while the terminal is given over to the UI, and shows the last few events it handled.
apps/user-input command
Command user-input shows how to handle keyboard input: an input box that records what is typed, and a list of the messages entered so far.
Command user-input shows how to handle keyboard input: an input box that records what is typed, and a list of the messages entered so far.
apps/volatility-surface command
Command volatility-surface draws a 3D wireframe in the terminal: an implied volatility surface you can turn, tilt and zoom while it moves.
Command volatility-surface draws a 3D wireframe in the terminal: an implied volatility surface you can turn, tilt and zoom while it moves.
apps/weather command
Command weather draws a day of made-up temperatures as a vertical bar chart, one bar per hour, coloured from yellow through to red.
Command weather draws a day of made-up temperatures as a vertical bar chart, one bar per hour, coloured from yellow through to red.
apps/widget-ref-container command
Command widget-ref-container keeps widgets of different types in one container and renders them down the screen.
Command widget-ref-container keeps widgets of different types in one container and renders them down the screen.
widgets/barchart command
Command barchart shows catatui's BarChart widget in both directions.
Command barchart shows catatui's BarChart widget in both directions.
widgets/barchart-grouped command
Command barchart-grouped shows catatui's BarChart widget with grouped bars.
Command barchart-grouped shows catatui's BarChart widget with grouped bars.
widgets/block command
Command block shows catatui's Block widget: borders, styles and border types.
Command block shows catatui's Block widget: borders, styles and border types.
widgets/calendar command
Command calendar shows catatui's Monthly widget with two styled months.
Command calendar shows catatui's Monthly widget with two styled months.
widgets/canvas command
Command canvas shows catatui's Canvas widget: a world map with shapes and points drawn over it.
Command canvas shows catatui's Canvas widget: a world map with shapes and points drawn over it.
widgets/chart command
Command chart shows catatui's Chart widget: a line plot and a filled area plot sharing a pair of axes.
Command chart shows catatui's Chart widget: a line plot and a filled area plot sharing a pair of axes.
widgets/collapsed-borders command
Command collapsed-borders shows four blocks sharing their borders, with the selected one drawn on top in a thick border.
Command collapsed-borders shows four blocks sharing their borders, with the selected one drawn on top in a thick border.
widgets/gauge command
Command gauge shows catatui's Gauge and LineGauge widgets.
Command gauge shows catatui's Gauge and LineGauge widgets.
widgets/line-gauge command
Command line-gauge shows catatui's LineGauge widget filling up over time.
Command line-gauge shows catatui's LineGauge widget filling up over time.
widgets/list command
Command list shows catatui's List widget, including a bottom-to-top list.
Command list shows catatui's List widget, including a bottom-to-top list.
widgets/logo command
Command logo draws the catatui logo in an inline viewport: three rows at the shell's cursor, leaving the scrollback above them untouched.
Command logo draws the catatui logo in an inline viewport: three rows at the shell's cursor, leaving the scrollback above them untouched.
widgets/paragraph command
Command paragraph shows catatui's Paragraph widget: alignment and wrapping.
Command paragraph shows catatui's Paragraph widget: alignment and wrapping.
widgets/scrollbar command
Command scrollbar shows catatui's Scrollbar widget, vertical and horizontal, scrolling a paragraph.
Command scrollbar shows catatui's Scrollbar widget, vertical and horizontal, scrolling a paragraph.
widgets/shadow command
Command shadow shows catatui's Shadow widget: four ways to cast a shadow behind a popup.
Command shadow shows catatui's Shadow widget: four ways to cast a shadow behind a popup.
widgets/sparkline command
Command sparkline shows catatui's Sparkline widget, including an animated sine wave.
Command sparkline shows catatui's Sparkline widget, including an animated sine wave.
widgets/table command
Command table shows catatui's Table widget with row, column and cell selection.
Command table shows catatui's Table widget with row, column and cell selection.
widgets/tabs command
Command tabs shows catatui's Tabs widget over a block of content.
Command tabs shows catatui's Tabs widget over a block of content.
internal
kasuari
Package kasuari is a Go port of the kasuari crate @ v0.4.11, the incremental Cassowary constraint solver that ratatui's Layout is built on.
Package kasuari is a Go port of the kasuari crate @ v0.4.11, the incremental Cassowary constraint solver that ratatui's Layout is built on.
palette
material
Package material holds Google's 2014 Material design colour palettes, as ratatui does.
Package material holds Google's 2014 Material design colour palettes, as ratatui does.
tailwind
Package tailwind holds the Tailwind CSS colour palettes, as ratatui does.
Package tailwind holds the Tailwind CSS colour palettes, as ratatui does.
Package symbols holds the Unicode characters catatui draws with: box-drawing lines, block elements, braille dots and bar segments.
Package symbols holds the Unicode characters catatui draws with: box-drawing lines, block elements, braille dots and bar segments.
Package term is catatui's terminal driver: raw mode, the alternate screen, input events, and the Backend that a catatui.Terminal writes through.
Package term is catatui's terminal driver: raw mode, the alternate screen, input events, and the Backend that a catatui.Terminal writes through.
Package widgets holds catatui's widget library: the ready-made things you render into a Frame.
Package widgets holds catatui's widget library: the ready-made things you render into a Frame.

Jump to

Keyboard shortcuts

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