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:
- resizes its buffers if the terminal changed size,
- hands your callback a blank Frame,
- diffs what you drew against the previous frame,
- 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 ¶
- catatui, this package: Rect and layout, Buffer and Cell, Style and styled text, Widget, Frame and Terminal.
- github.com/Fiend3d/catatui/term: the terminal driver — raw mode, the alternate screen, input events, and the Backend that Terminal writes through. This is what crossterm is to ratatui.
- github.com/Fiend3d/catatui/widgets: the widget library — Block, Paragraph, List, Table, Chart, Canvas and the rest.
- github.com/Fiend3d/catatui/symbols: the characters widgets draw with.
- github.com/Fiend3d/catatui/palette/tailwind and github.com/Fiend3d/catatui/palette/material: named colour ramps, for when the sixteen ANSI colours are not enough.
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 ¶
- Variables
- func AllGraphemes(s string) iter.Seq[Grapheme]
- func AssertBuffer(t TestingT, got, want *Buffer)
- func BufferEqual(got, want *Buffer) error
- func ClampU16(v, lo, hi uint16) uint16
- func GraphemeWidth(cluster string, unisegWidth int) int
- func MaxU16(a, b uint16) uint16
- func MinU16(a, b uint16) uint16
- func RenderStatefulWidget[S any](w StatefulWidget[S], area Rect, buf *Buffer, state *S)
- func RenderStatefulWidgetOn[S any](f *Frame, w StatefulWidget[S], area Rect, state *S)
- func RenderWidget(w Widget, area Rect, buf *Buffer)
- func SatAdd(a, b uint16) uint16
- func SatMul(a, b uint16) uint16
- func SatSub(a, b uint16) uint16
- func SegmentGraphemes(s string) iter.Seq[Grapheme]
- func StringWidth(s string) int
- func TrimLeftColumns(s string, n int) string
- type Alignment
- type Backend
- type Buffer
- func (b *Buffer) Cell(p Position) *Cell
- func (b *Buffer) CellAt(x, y uint16) *Cell
- func (b *Buffer) Diff(next *Buffer) []PositionedCell
- func (b *Buffer) DiffInto(dst []PositionedCell, next *Buffer) []PositionedCell
- func (b *Buffer) DiffSeq(next *Buffer) iter.Seq[PositionedCell]
- func (b *Buffer) Get(x, y uint16) *Cell
- func (b *Buffer) IndexOf(x, y uint16) int
- func (b *Buffer) Merge(other *Buffer)
- func (b *Buffer) PosOf(index int) (x, y uint16)
- func (b *Buffer) Reset()
- func (b *Buffer) Resize(area Rect)
- func (b *Buffer) SetLine(x, y uint16, line Line, maxWidth uint16) (nextX, nextY uint16)
- func (b *Buffer) SetSpan(x, y uint16, span Span, maxWidth uint16) (nextX, nextY uint16)
- func (b *Buffer) SetString(x, y uint16, s string, style Style) (nextX, nextY uint16)
- func (b *Buffer) SetStringn(x, y uint16, s string, maxWidth uint16, style Style) (nextX, nextY uint16)
- func (b *Buffer) SetStyle(area Rect, style Style)
- func (b *Buffer) String() string
- type Cell
- func (c Cell) Equal(other Cell) bool
- func (c Cell) GetStyle() Style
- func (c Cell) GetSymbol() string
- func (c *Cell) MergeSymbol(symbol string, strategy symbols.MergeStrategy) *Cell
- func (c *Cell) Reset()
- func (c *Cell) SetBg(color Color) *Cell
- func (c *Cell) SetChar(r rune) *Cell
- func (c *Cell) SetDiffOption(o CellDiffOption) *Cell
- func (c *Cell) SetFg(color Color) *Cell
- func (c *Cell) SetSkip(skip bool) *Cell
- func (c *Cell) SetStyle(s Style) *Cell
- func (c *Cell) SetSymbol(symbol string) *Cell
- func (c Cell) Skip() bool
- func (c Cell) Width() uint16
- type CellDiffOption
- type CellDiffOptionKind
- type ClearType
- type Color
- type Constraint
- type ConstraintKind
- type Direction
- type Flex
- type Frame
- type Grapheme
- type Layout
- func (l Layout) Constraints(constraints ...Constraint) Layout
- func (l Layout) Direction(d Direction) Layout
- func (l Layout) Flex(f Flex) Layout
- func (l Layout) GetConstraints() []Constraint
- func (l Layout) GetDirection() Direction
- func (l Layout) GetFlex() Flex
- func (l Layout) GetMargin() Margin
- func (l Layout) GetSpacing() Spacing
- func (l Layout) Horizontal() Layout
- func (l Layout) HorizontalMargin(n uint16) Layout
- func (l Layout) Margin(n uint16) Layout
- func (l Layout) Spacing(s Spacing) Layout
- func (l Layout) Split(area Rect) []Rect
- func (l Layout) SplitWithSpacers(area Rect) (segments, spacers []Rect)
- func (l Layout) String() string
- func (l Layout) Vertical() Layout
- func (l Layout) VerticalMargin(n uint16) Layout
- type Line
- func (l Line) Alignment(a Alignment) Line
- func (l Line) Centered() Line
- func (l Line) GetAlignment() Alignment
- func (l Line) GetSpans() []Span
- func (l Line) GetStyle() Style
- func (l Line) Left() Line
- func (l Line) Patch(style Style) Line
- func (l Line) Render(area Rect, buf *Buffer)
- func (l Line) RenderWithFallbackAlignment(area Rect, buf *Buffer, parent Alignment)
- func (l Line) Right() Line
- func (l Line) Spans(spans ...Span) Line
- func (l Line) String() string
- func (l Line) Style(style Style) Line
- func (l Line) Width() int
- type Margin
- type Modifier
- type Offset
- type Position
- type PositionedCell
- type Rect
- func (r Rect) Area() uint32
- func (r Rect) AsPosition() Position
- func (r Rect) AsSize() Size
- func (r Rect) Bottom() uint16
- func (r Rect) Clamp(other Rect) Rect
- func (r Rect) Columns() []Rect
- func (r Rect) Contains(p Position) bool
- func (r Rect) Inner(m Margin) Rect
- func (r Rect) Intersection(other Rect) Rect
- func (r Rect) Intersects(other Rect) bool
- func (r Rect) IsEmpty() bool
- func (r Rect) Left() uint16
- func (r Rect) Offset(o Offset) Rect
- func (r Rect) Outer(m Margin) Rect
- func (r Rect) Positions() []Position
- func (r Rect) Resize(s Size) Rect
- func (r Rect) Right() uint16
- func (r Rect) Rows() []Rect
- func (r Rect) Top() uint16
- func (r Rect) Union(other Rect) Rect
- type Size
- type Spacing
- type Span
- type StatefulWidget
- type Style
- func (s Style) AddModifier(m Modifier) Style
- func (s Style) Bg(c Color) Style
- func (s Style) Fg(c Color) Style
- func (s Style) GetAddModifier() Modifier
- func (s Style) GetBg() Color
- func (s Style) GetFg() Color
- func (s Style) GetSubModifier() Modifier
- func (s Style) GetUnderlineColor() Color
- func (s Style) IsEmpty() bool
- func (s Style) Patch(other Style) Style
- func (s Style) RemoveModifier(m Modifier) Style
- func (s Style) UnderlineColor(c Color) Style
- type Terminal
- func (t *Terminal) Autoresize() error
- func (t *Terminal) Backend() Backend
- func (t *Terminal) Clear() error
- func (t *Terminal) CurrentBuffer() *Buffer
- func (t *Terminal) Draw(render func(*Frame)) error
- func (t *Terminal) FrameCount() uint64
- func (t *Terminal) GetCursorPosition() (Position, error)
- func (t *Terminal) GetFrame() *Frame
- func (t *Terminal) HideCursor() error
- func (t *Terminal) InsertBefore(height uint16, draw func(*Buffer)) error
- func (t *Terminal) Resize(area Rect) error
- func (t *Terminal) SetCursorPosition(p Position) error
- func (t *Terminal) ShowCursor() error
- func (t *Terminal) Size() (Size, error)
- func (t *Terminal) TryDraw(render func(*Frame) error) error
- func (t *Terminal) ViewportArea() Rect
- type TestBackend
- func (b *TestBackend) AppendLines(n uint16) error
- func (b *TestBackend) Buffer() *Buffer
- func (b *TestBackend) Clear() error
- func (b *TestBackend) ClearRegion(t ClearType) error
- func (b *TestBackend) CursorHidden() bool
- func (b *TestBackend) Draw(cells []PositionedCell) error
- func (b *TestBackend) Flush() error
- func (b *TestBackend) GetCursorPosition() (Position, error)
- func (b *TestBackend) HideCursor() error
- func (b *TestBackend) Resize(width, height uint16)
- func (b *TestBackend) Scrollback() []string
- func (b *TestBackend) SetCursorPosition(p Position) error
- func (b *TestBackend) ShowCursor() error
- func (b *TestBackend) Size() (Size, error)
- func (b *TestBackend) WindowSize() (WindowSize, error)
- type TestingT
- type Text
- func (t Text) Alignment(a Alignment) Text
- func (t Text) Centered() Text
- func (t Text) GetAlignment() Alignment
- func (t Text) GetLines() []Line
- func (t Text) GetStyle() Style
- func (t Text) Height() int
- func (t Text) Left() Text
- func (t Text) Lines(lines ...Line) Text
- func (t Text) Patch(style Style) Text
- func (t Text) Render(area Rect, buf *Buffer)
- func (t Text) Right() Text
- func (t Text) String() string
- func (t Text) Style(style Style) Text
- func (t Text) Width() int
- type Viewport
- type ViewportKind
- type Widget
- type WidgetFunc
- type WidthPolicy
- type WindowSize
Examples ¶
Constants ¶
This section is empty.
Variables ¶
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.
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.
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.
var PositionOrigin = Position{0, 0}
PositionOrigin is the top left corner.
var ZeroRect = Rect{}
ZeroRect is an empty rect at the origin.
Functions ¶
func AllGraphemes ¶
AllGraphemes yields only drawable clusters, without allocating a slice.
func AssertBuffer ¶
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 ¶
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 GraphemeWidth ¶
GraphemeWidth measures a single uniseg segment with its stepper-provided width. For full Indic conjunct boundaries, use SegmentGraphemes instead.
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 ¶
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 SegmentGraphemes ¶
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 ¶
StringWidth is the terminal advance under DefaultWidthPolicy, matching cells, Buffer.SetStringn, spans and widgets. Controls occupy no columns.
func TrimLeftColumns ¶
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.
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 NewBufferFilled ¶
NewBufferFilled returns a buffer covering area with every cell a copy of cell.
func NewBufferWithLines ¶
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 ¶
NewBufferWithStrings is NewBufferWithLines for unstyled text, which is how most buffer assertions are written.
func (*Buffer) 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) 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 ¶
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 ¶
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 ¶
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 ¶
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) Resize ¶
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 ¶
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 ¶
SetSpan draws a span at (x, y), in the span's own style, clipped to maxWidth.
func (*Buffer) SetString ¶
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 ¶
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 ¶
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 (Cell) Equal ¶
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 ¶
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 ¶
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) SetDiffOption ¶
func (c *Cell) SetDiffOption(o CellDiffOption) *Cell
SetDiffOption sets how the cell takes part in the frame diff.
func (*Cell) SetStyle ¶
SetStyle applies a style to the cell. Colors the style leaves unset are kept, which is what makes styles layer.
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 ¶
func (o CellDiffOption) Kind() CellDiffOptionKind
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 )
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 ParseColor ¶
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 ¶
Rgb returns a 24-bit true color. Only terminals with true color support will display it correctly.
func RgbFromU32 ¶
RgbFromU32 returns an RGB color from a 0x00RRGGBB value.
func (Color) IsSet ¶
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 ¶
Named reports whether c is one of the sixteen named ANSI colors, returning its ordinal (0..15) if so.
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 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 )
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 )
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) 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 ¶
Count returns how many frames have been drawn before this one, which is handy for driving animations.
func (*Frame) RenderWidget ¶
RenderWidget draws a widget into the given area of the frame.
func (*Frame) SetCursorPosition ¶
SetCursorPosition puts the terminal cursor at the given position after the frame is drawn. A frame that never calls this hides the cursor.
type Grapheme ¶
Grapheme is a complete drawing unit and its terminal advance. Indic conjuncts and the Tamil ksha/sri ligatures are kept together for shaping.
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) GetConstraints ¶
func (l Layout) GetConstraints() []Constraint
GetConstraints returns the layout's constraints.
func (Layout) GetDirection ¶
GetDirection returns the layout's axis.
func (Layout) GetSpacing ¶
GetSpacing returns the gap between segments.
func (Layout) Horizontal ¶
Horizontal returns a copy of l splitting into columns.
func (Layout) HorizontalMargin ¶
HorizontalMargin returns a copy of l inset by n cells on the left and right.
func (Layout) Spacing ¶
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 ¶
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 ¶
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) VerticalMargin ¶
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 ¶
LineFromString returns an unstyled single-span line.
func LineFromStyledString ¶
LineFromStyledString returns a single-span line in the given style. The style is applied to the span, matching ratatui's Line::styled.
func (Line) GetAlignment ¶
GetAlignment returns the line's alignment, which may be AlignmentNone.
func (Line) GetSpans ¶
GetSpans returns the line's spans. The slice is the line's own; do not modify it.
func (Line) Render ¶
Render draws the line on the first row of the area, honouring its own alignment.
func (Line) RenderWithFallbackAlignment ¶
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.
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) Intersects ¶
Intersects reports whether any modifier in other is set in m.
type Offset ¶
Offset is a signed displacement applied to a Rect. Positive X moves right, positive Y moves down.
type Position ¶
Position is a single point in the terminal, in cells, measured from the top left corner.
type PositionedCell ¶
PositionedCell is one cell of a diff: the cell together with where it goes.
type Rect ¶
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 ¶
NewRect returns a Rect, clamping Width and Height so the right and bottom edges stay within uint16.
func (Rect) Area ¶
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 ¶
AsPosition returns the rect's top left corner.
func (Rect) Clamp ¶
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) Contains ¶
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 ¶
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 ¶
Intersection returns the overlap of r and other, which is empty if they do not overlap.
func (Rect) Intersects ¶
Intersects reports whether r and other overlap.
func (Rect) Offset ¶
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 ¶
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) Resize ¶
Resize changes the size, keeping the position and clamping so that Right and Bottom stay within uint16.
func (Rect) Right ¶
Right is the first x coordinate to the right of the rect, clamped to uint16 max.
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.
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 ¶
NewSpan returns an unstyled span holding the given content. It is the equivalent of ratatui's Span::raw.
func NewStyledSpan ¶
NewStyledSpan returns a span holding the given content in the given style.
type StatefulWidget ¶
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 ¶
AddModifier returns a copy of s with the given modifiers added, and removed from the set of modifiers s clears.
func (Style) GetAddModifier ¶
GetAddModifier returns the modifiers this style turns on.
func (Style) GetSubModifier ¶
GetSubModifier returns the modifiers this style turns off.
func (Style) GetUnderlineColor ¶
GetUnderlineColor returns the underline color, which may be unset.
func (Style) Patch ¶
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 ¶
RemoveModifier returns a copy of s with the given modifiers cleared, and removed from the set of modifiers s adds.
func (Style) UnderlineColor ¶
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 ¶
NewTerminal returns a Terminal drawing to the whole of the given backend.
func NewTerminalWithViewport ¶
NewTerminalWithViewport returns a Terminal drawing into the given viewport.
func (*Terminal) Autoresize ¶
Autoresize resizes the terminal if it has changed size since the last frame. Fixed viewports are left alone.
func (*Terminal) CurrentBuffer ¶
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 ¶
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 ¶
FrameCount returns how many frames have been drawn.
func (*Terminal) GetCursorPosition ¶
GetCursorPosition reports where the cursor is.
func (*Terminal) GetFrame ¶
GetFrame returns a Frame for the current buffer without drawing anything.
func (*Terminal) HideCursor ¶
HideCursor hides the terminal cursor.
func (*Terminal) InsertBefore ¶
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) SetCursorPosition ¶
SetCursorPosition moves the cursor and records the position, so that an inline viewport can restore it across a resize.
func (*Terminal) ShowCursor ¶
ShowCursor shows the terminal cursor.
func (*Terminal) TryDraw ¶
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 ¶
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) 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 ¶
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 TextFromString ¶
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 ¶
TextFromStyledString is TextFromString with a style applied to the whole block.
func (Text) GetAlignment ¶
GetAlignment returns the text's alignment, which may be AlignmentNone.
func (Text) GetLines ¶
GetLines returns the text's lines. The slice is the text's own; do not modify it.
func (Text) Render ¶
Render draws the text, one line per row, honouring the text's alignment for any line that does not set its own.
type Viewport ¶
type Viewport struct {
// contains filtered or unexported fields
}
Viewport is the region of the terminal a Terminal draws into.
func FixedViewport ¶
FixedViewport uses an explicit region that never autoresizes.
func FullscreenViewport ¶
func FullscreenViewport() Viewport
FullscreenViewport uses the whole terminal.
func InlineViewport ¶
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 ¶
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 ¶
WidgetFunc adapts a plain function to the Widget interface.
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 ¶
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.
Source Files
¶
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. |