termmosaic

package module
v1.1.0 Latest Latest
Warning

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

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

README

TermMosaic

Go Reference CI gofmt golangci-lint Go

A terminal UI framework for Go: a cell-buffer renderer, a catalog of ready-to-use widgets, and a command/keymap layer that binds keys to named actions without changing a single widget signature.

Status: v1.0.0, released 2026-10-06. The renderer, input layer and the full widget catalog are built and tested — 28 packages, 1,186 tests, zero-allocation frame path. v1.0.0 is the first release that makes a stability promise: the public API is frozen at that tag, and Semantic Versioning applies from it — with one documented exception: the test harness widgets/widgettest is excluded from that promise, because it must evolve with the framework (docs/STATUS.md). Known limitations are enumerated in docs/STATUS.md and in the Known Limitations sections of CHANGELOG.md — written down, not left for users to discover.

Supported platforms: Linux and macOS. Windows is a deliberate loud-error stub — every console operation fails loudly instead of half-working — and a Windows console backend is out of scope for v1.0.0 (ADR 0001; decision recorded in docs/STATUS.md).

IME composition is out of scope for v1.0.0. EventCompose is reserved; nothing decodes it yet (ADR 0005).

See docs/STATUS.md for what is decided, proposed and open, and docs/adr/ for the reasoning behind each decision.

Why this exists

The Go TUI ecosystem has exactly one dominant framework, and it leaves a lot on the table:

  • Ink (TS/React) clears and repaints the whole screen on each update. It works until your app gets big, then input lag becomes obvious.
  • OpenTUI is a strong engineering artifact with a deliberately unfinished surface: at 13.4k stars and running in production, it ships no progressbar, gauge, sparkline, bar chart, or meter, and no list, tree, pager, or virtual scroll. Its roadmap still lists data virtualization as unfinished.
  • Terminal.Gui and friends predate the modern bar and carry decades of accumulated baggage.

TermMosaic's bet is narrow and specific: the widget catalog is the product. A framework nobody can build a real dashboard on is a toy, regardless of how elegant its renderer is.

Design pillars

  1. A complete widget catalog. Twenty-four widgets covering layout, forms, data, and visualization — the things real tools need.
  2. Data virtualization from day one. List, Table, and Tree render 100k+ rows at interactive speed. Not a future roadmap item.
  3. Honest rendering. A double-buffered cell buffer with two-tier diffing (row-level skip, then per-cell), dirty-region tracking, and a 30–60 fps frame budget. No full-screen clears in the hot path.
  4. Graceful degradation. Truecolor → 256 → 16 color. Unicode borders → ASCII. NO_COLOR respected. Mouse capture is off by default because it steals selection and scrollback from your shell. tmux DCS passthrough is a known gap — see docs/STATUS.md.
  5. Testable without a terminal. A headless memory-sink backend means the renderer and every widget are unit-testable in CI.
  6. Accessible by construction. Color is never the only signal. Visible focus. Full keyboard operation. (A reduced-motion flag is not built yet — the catalog animates nothing today, so there is nothing to gate.)
  7. Documented limits. Known limitations are written down, not discovered by users. If we have no IME support, the README says so.

Installation

Tagged and released through v1.0.0. Pin the version:

go get github.com/serkanalgur/termmosaic@v1.0.0

What's in the box

24 widgets, built and tested:

Core Block Text Paragraph Split
Forms TextInput TextArea Select Checkbox Radio Toggle Tabs Button KeyHint
Data List Table Tree Pager + the virtual/ engine
Visualization ProgressBar Gauge Meter Sparkline BarChart
Navigation & modality Menu Dialog

buffer.Buffer is not on that list and is not a Widget — it has no Bounds, Draw or Handle. It is what widgets draw into.

Commands and key bindings

keymap is a separate package, not a widget, and it sits above Widget.Handle rather than inside it — termmosaic.Widget is still four methods and has never changed.

  • One named action, reached by a key or a menu item or application code. A key that resolves to nothing falls through to the tree exactly as before.
  • ctrl+k and Ctrl+K are two chords — Shift is folded into the rune, and a kitty terminal reports them as two gestures. Modifiers are parsed case-insensitively, and Space and a literal space are one chord.
  • Resolution is focus > screen > global, with no numeric priority. A screen's own Esc cannot be stolen by a global binding; a user's override wins within its own scope.
  • 0 allocations on the dispatch path. Chord is a comparable 16-byte struct, so resolution is a map lookup — pinned by TestDispatchIsZeroAllocation, not merely intended.
  • Help is derived from the bindings, so a help row cannot drift from what the key actually does. Describe() gives one row per chord, which is what a help screen and a command palette want; DescribeGrouped() gives one row per command, which is what a one-line KeyHint wants.
  • Widgets participate optionally, via keymap.Commandable and keymap.Clickable. No catalog widget implements either yet, and there is no command palette — both are deliberate, with triggers recorded in ADR 0009.

Two examples use it, of four. examples/hello dispatches through a real keymap.Registry — six commands, twelve chords — and renders both its pinned hint line and its ? help overlay from that registry rather than from hand-written strings. examples/search is the first to put a focusable widget in a focus ring: a TextInput and a Table, with Tab/Backtab moving between them, and every context-dependent binding gated by Command.Enabled rather than by ScopeFocus — because Enabled false makes Dispatch skip the command and fall through to the tree, which is what keeps a binding from taking a key away from the widget that has focus. markets and dashboard still dispatch by their own switch.

The absence of Commandable in the catalog is therefore not blocking either of them: an application can have a fully registry-derived key contract without it. What is still missing is Registry.SetFocus, which examples/search works around by tracking focus itself and filtering its hint on km.Has — the one query an application makes when focus changes is the one it cannot make.

Per-frame cost is flat in item count — this is the claim the catalog exists to back up:

Items List Table
10,000 13,320 ns 16,801 ns
100,000 14,242 ns 17,885 ns

Ten times the data for seven percent more time, at zero allocations. Run examples/markets to see it against a real 100k-item list.

Examples

go run ./examples/hello       # a responsive bordered panel; '?' for help
go run ./examples/markets    # a live finance dashboard on real ECB data
                           # add --offline to run without a network
go run ./examples/search      # Wikipedia search and results, no API key
                            # add --offline to run on a bundled capture

examples/markets, on live ECB and CoinGecko data:

One Block per region, a Split down the middle, a Table over the virtual engine, and the chart types doing the work the catalog exists for. The selected row is drawn with SelectedStyle in both the row background and the cell text — see v0.5.1, which fixed the case where it reached only the background.

Documentation

📖 Full documentation → — guides, concepts, and a page per widget with real rendered captures at three widths.

Every screenshot on the documentation site is a real render, generated by cmd/capture through the same headless path the tests use — so a page cannot show output the code does not produce.

License

MIT

Sponsoring

This is a solo project and it costs real time. If it saves you any, GitHub Sponsors is the way.

Sponsoring does not buy priority, a roadmap seat, or a promised feature — the architecture decisions are made in the open, in docs/adr/, and that will not change.

Acknowledgements

This project studies and is informed by the work of Ratatui, Bubble Tea, Textual, and OpenTUI.

Documentation

Overview

Package termmosaic is the root of the TermMosaic TUI framework.

It holds the two narrow interfaces every other package is written against — Terminal and Sink (ADR 0001) — plus the geometry, capability, event and widget types they traffic in. Nothing here talks to a real terminal: the concrete backends live in the headless and term packages, and the core depends only on these interfaces. That is what makes every widget CI-testable with no terminal, which ADR 0001 records as a first-class deliverable rather than a stretch goal.

The import graph is a DAG with no cycles:

buffer   leaf: Cell, Colour, Attr, Buffer, geometry
layout   leaf: the pure constraint solver (ADR 0004)
termmosaic        this package: Terminal, Sink, Caps, Event, Widget
headless  headless Terminal + MemorySink
render    the hybrid renderer (ADR 0003)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Caps

type Caps struct {
	// TrueColor reports support for SGR 38;2 and 48;2.
	TrueColor bool
	// Color256 reports support for the xterm-256 palette.
	Color256 bool
	// Unicode reports whether box-drawing and block glyphs render correctly,
	// as opposed to mojibake or blank cells on a misconfigured locale.
	Unicode bool
	// Mouse reports support for mouse reporting.
	Mouse bool
	// KittyKeyboard reports that this terminal MAY SUPPORT the kitty keyboard
	// protocol, which gives unambiguous key events for keys xterm cannot encode.
	//
	// "May support" is the whole of the claim, and it is deliberately NOT the same
	// as "the protocol is active". Detection is a TERM substring heuristic, so it
	// is right sometimes and wrong sometimes, and whether the protocol is actually
	// in force is established by a handshake on a running input.Source and
	// reported by Source.KittyActive(). Negotiation state lives on the Source
	// because it is a property of a session rather than of a device; see ADR 0005.
	KittyKeyboard bool
	// BracketedPaste reports support for bracketed paste, which is what makes
	// a multi-line paste one event instead of several keystrokes.
	BracketedPaste bool
}

Caps reports what a terminal supports.

Detection is a single point of truth so the truecolor->256->16 and Unicode->ASCII degradation ladders have one home, which ADR 0001 calls out as a direct benefit of owning the terminal layer. TermMosaic has no terminfo database; it sniffs a fixed, well-chosen subset, which ADR 0001 records as a deliberate accepted limitation.

func DefaultCaps

func DefaultCaps() Caps

DefaultCaps returns the capabilities of a modern, well-configured terminal. A headless Terminal starts here; a real one starts from probing and degrades.

func (Caps) ColourDepth

func (c Caps) ColourDepth() buffer.ColourDepth

ColourDepth returns the rung of the degradation ladder these capabilities select.

type Compose

type Compose struct {
	Text   string
	Cursor int
	Phase  ComposePhase
}

Compose is the payload of an EventCompose.

RESERVED, NEVER EMITTED IN v0.x. IME support is deferred by ADR 0005 and this type exists so the union can already express composition. The field set is what an implementation needs and no more: Text is the preedit string as the terminal reports it, Cursor is the byte offset of the caret within Text, and Phase says whether this is the start of a composition, an update to it, the committed text, or the end.

type ComposePhase

type ComposePhase uint8

ComposePhase is the stage of an IME composition.

const (
	// ComposeStart begins a composition.
	ComposeStart ComposePhase = iota
	// ComposeUpdate replaces the preedit string of an in-progress composition.
	ComposeUpdate
	// ComposeCommit carries the committed text and ends the composition.
	ComposeCommit
	// ComposeEnd discards a composition without committing it.
	ComposeEnd
)

Composition phases.

func (ComposePhase) String

func (p ComposePhase) String() string

String returns the composition phase's name.

type Event

type Event struct {
	// Kind discriminates the event.
	Kind EventKind
	// Key is the non-printable key for EventKey, or KeyNone for a printable
	// character.
	Key Key
	// Rune is the printable character for EventKey, or 0.
	Rune rune
	// Mod is the modifier state.
	Mod KeyMod
	// Type is press, repeat or release. Always KeyPress unless the kitty
	// keyboard protocol reported event types (ADR 0005 section 2).
	Type KeyType
	// Mouse is the payload for EventMouse.
	Mouse Mouse
	// Size is the new size for EventResize.
	Size Size
	// Text is the payload for EventPaste, the entire paste undelimited and
	// unescaped, and the committed text for EventCompose.
	Text string
	// Compose is the payload for EventCompose, and nil otherwise. This is the
	// only pointer field in Event and the one field allowed to be nil; see
	// ADR 0005 section 7 for why composition is reserved but deferred.
	Compose *Compose
	// Truncated reports that a paste payload exceeded the configured maximum
	// and was cut short. The text is still a valid prefix of what was pasted.
	Truncated bool
	// Focused reports the new state for EventFocus.
	Focused bool
}

Event is a single input event delivered to the widget tree.

One struct rather than an interface, because events cross the input path per keystroke and an interface here would mean a heap allocation for no benefit. Unused fields are zero, with one exception: Compose is nil unless Kind is EventCompose.

INVARIANT: this struct is copied by value on the hot path and must not grow without a deliberate decision. TestEventSizeIsBounded pins sizeof(Event); see ADR 0005 section 8.

func KeyEvent

func KeyEvent(r rune, mod KeyMod) Event

KeyEvent returns an EventKey for a printable rune.

func ResizeEvent

func ResizeEvent(w, h int) Event

ResizeEvent returns an EventResize for the given size.

func SpecialKeyEvent

func SpecialKeyEvent(k Key, mod KeyMod) Event

SpecialKeyEvent returns an EventKey for a non-printable key.

type EventKind

type EventKind int

EventKind discriminates an Event.

const (
	// EventNone is the zero value and carries no event.
	EventNone EventKind = iota
	// EventKey is a key press, repeat or release.
	EventKey
	// EventResize reports a new terminal size.
	EventResize
	// EventMouse is a mouse button press, release or motion.
	EventMouse
	// EventPaste is a bracketed-paste payload, delivered whole.
	EventPaste
	// EventFocus reports gaining or losing terminal focus.
	EventFocus
	// EventCompose reports IME composition state.
	//
	// DECLARED BUT NEVER EMITTED IN v0.x. IME support is deferred by ADR 0005
	// §7; this constant exists so the union can already express composition,
	// and so a widget author writing a switch today sees the case and knows
	// composition is coming. Do not emit it and do not handle it as if it were
	// live.
	EventCompose
)

Event kinds. A zero Event has Kind EventNone, which widgets ignore.

func (EventKind) String

func (k EventKind) String() string

String returns the kind's name.

type Focusable

type Focusable interface {
	Widget
	// Focused reports whether the widget currently has focus.
	Focused() bool
	// SetFocused gives or removes focus. Implementations invalidate themselves.
	SetFocused(bool)
}

Focusable is an optional interface a Widget implements if it can take focus. The renderer uses it to maintain focus order without requiring every widget to carry a focus method.

type Key

type Key int

Key identifies a key press. Printable keys are carried as their rune in Event.Rune; Key is only set for keys that have no printable form.

The set is deliberately the xterm-encodable set, with no F13–F35. A new key must be APPENDED at the end of the iota block below: the constants are contiguous and inserting one in the middle silently renumbers every later value.

TermMosaic decodes the kitty keyboard protocol when the handshake on an input.Source succeeds — not merely when a terminal advertises the capability. Caps.KittyKeyboard is a TERM heuristic meaning "may support", and the negotiation state lives on the Source because it is a property of a running session rather than of a device. See ADR 0005 §2. Without a successful handshake some combinations are indistinguishable; that is an accepted limitation of owning the input layer.

const (
	// KeyNone means the event carries a printable rune rather than a special
	// key, so Event.Rune holds the character.
	KeyNone Key = iota
	// KeyEnter is the return key.
	KeyEnter
	// KeyTab is the tab key.
	KeyTab
	// KeyBacktab is shift-tab, reported as its own key because terminals
	// encode it that way and a widget usually wants to treat it differently
	// from tab.
	KeyBacktab
	// KeyBackspace is the backspace key. A terminal may deliver it as a
	// control character rather than as an escape sequence, depending on the
	// terminfo setting, and the input decoder reconciles that: both 0x7f and
	// 0x08 decode to KeyBackspace by default. See ADR 0005 §2, and
	// input.Config.BackspaceByte to pin one.
	KeyBackspace
	// KeyEscape is the escape key, which a bare escape is indistinguishable
	// from the start of an escape sequence.
	KeyEscape
	// KeySpace is the space bar, which terminals may deliver as a rune.
	KeySpace
	// KeyUp is the up arrow.
	KeyUp
	// KeyDown is the down arrow.
	KeyDown
	// KeyLeft is the left arrow.
	KeyLeft
	// KeyRight is the right arrow.
	KeyRight
	// KeyHome is the home key.
	KeyHome
	// KeyEnd is the end key.
	KeyEnd
	// KeyPageUp is the page-up key.
	KeyPageUp
	// KeyPageDown is the page-down key.
	KeyPageDown
	// KeyDelete is the delete key.
	KeyDelete
	// KeyInsert is the insert key.
	KeyInsert
	// KeyF1 is the F1 key.
	KeyF1
	// KeyF2 is the F2 key.
	KeyF2
	// KeyF3 is the F3 key.
	KeyF3
	// KeyF4 is the F4 key.
	KeyF4
	// KeyF5 is the F5 key.
	KeyF5
	// KeyF6 is the F6 key.
	KeyF6
	// KeyF7 is the F7 key.
	KeyF7
	// KeyF8 is the F8 key.
	KeyF8
	// KeyF9 is the F9 key.
	KeyF9
	// KeyF10 is the F10 key.
	KeyF10
	// KeyF11 is the F11 key.
	KeyF11
	// KeyF12 is the F12 key.
	KeyF12
)

Non-printable keys.

func (Key) String

func (k Key) String() string

String returns the key's name, for diagnostics and key-hint rendering.

type KeyMod

type KeyMod uint8

KeyMod is a bitmask of modifier keys held during an event.

const (
	// ModShift is the Shift key.
	ModShift KeyMod = 1 << iota
	// ModAlt is the Alt key, labelled Option on macOS.
	ModAlt
	// ModCtrl is the Control key.
	ModCtrl
	// ModSuper is the Super or Command key.
	ModSuper
)

Modifier keys.

func (KeyMod) Has

func (m KeyMod) Has(other KeyMod) bool

Has reports whether every bit in other is set in m.

func (KeyMod) String

func (m KeyMod) String() string

String returns the modifiers in a stable, conventional order.

type KeyType

type KeyType uint8

KeyType is what happened to a key.

Without the kitty keyboard protocol every event is KeyPress and autorepeat is indistinguishable from a second press; that is an accepted limitation of the xterm encoding, not a bug.

const (
	// KeyPress is a key going down. It is the zero value, so a synthesized
	// EventKey is a press unless something says otherwise.
	KeyPress KeyType = iota
	// KeyRepeat is an autorepeat, distinguishable from a second press only
	// under the kitty keyboard protocol.
	KeyRepeat
	// KeyRelease is a key coming up.
	KeyRelease
)

Key event types.

func (KeyType) String

func (t KeyType) String() string

String returns the key event type's name.

type Minimizable

type Minimizable interface {
	Widget
	// MinSize returns the widget's smallest meaningful size in cells. It must be
	// pure, must not depend on the current Bounds, and must be safe to call before
	// the widget has ever been drawn.
	MinSize() Size
}

Minimizable is an optional interface a Widget implements if it has a smallest size at which it can render something meaningful.

This is the existing Focusable pattern exactly: optional, so that adding it costs no widget anything, and discoverable by a type assertion. A widget that does not implement it is fully supported — there is no framework default minimum and no framework reaction (ADR 0007 §4).

MinSize is the size of the WHOLE widget INCLUDING its own chrome — a bordered Table with MinSize{20, 5} needs 20x5 cells, not a 20x5 content area. Pinning this here is deliberate: three authors would otherwise each decide whether their border counts, and every caller's arithmetic would then be wrong for some subset of the catalog.

The framework does nothing with a MinSize. What to do when the available space is below it is the application's decision, because only the application knows whether losing a table is acceptable (ADR 0007, rejected alternative: a framework-owned "too small" screen).

type Mouse

type Mouse struct {
	X, Y   int
	Button MouseButton
	Action MouseAction
	// Mod is the modifier state at the time of the event.
	Mod KeyMod
}

Mouse is the payload of an EventMouse.

type MouseAction

type MouseAction int

MouseAction is what happened to the button.

const (
	// MousePress is a button going down.
	MousePress MouseAction = iota
	// MouseRelease is a button coming up.
	MouseRelease
	// MouseDrag is motion with a button held.
	MouseDrag
	// MouseMove is motion with no button held.
	MouseMove
)

Mouse actions.

type MouseButton

type MouseButton int

MouseButton identifies a mouse button.

const (
	// MouseNone means no button, for motion events.
	MouseNone MouseButton = iota
	// MouseLeft is the primary button.
	MouseLeft
	// MouseMiddle is the middle button.
	MouseMiddle
	// MouseRight is the secondary button.
	MouseRight
	// MouseWheelUp is a wheel-up notch.
	MouseWheelUp
	// MouseWheelDown is a wheel-down notch.
	MouseWheelDown
)

Mouse buttons.

type Rect

type Rect = buffer.Rect

Rect is an axis-aligned rectangle in cell coordinates. Aliased from buffer so that a layout result can be handed to a widget's Bounds() without conversion.

type Sink

type Sink interface {
	// Write appends bytes to the sink. A short write with a nil error is
	// treated as an error by the renderer.
	Write(p []byte) (int, error)
	// Flush pushes buffered bytes to the underlying device.
	Flush() error
}

Sink consumes the bytes the diff produces.

The renderer writes here and knows nothing else about its output. Two implementations exist in v1: the real terminal's writer, and a MemorySink that records frames for tests (ADR 0001).

type Size

type Size = buffer.Size

Size is a terminal width and height in cells. Aliased from buffer for the same reason as Rect.

type Terminal

type Terminal interface {
	// Size returns the terminal's current size in cells.
	Size() (w, h int)
	// EnterRawMode disables line buffering and echo. It is not idempotent:
	// implementations must track their own state and make a second call a
	// no-op, because an unbalanced LeaveRawMode leaves the user's shell broken.
	EnterRawMode() error
	// LeaveRawMode restores the terminal's mode on entry.
	LeaveRawMode() error
	// EnterAltScreen switches to the alternate screen buffer.
	EnterAltScreen() error
	// LeaveAltScreen switches back to the main screen buffer.
	LeaveAltScreen() error
	// Capabilities reports what the terminal supports, which selects both the
	// colour-degradation rung and the box-drawing character set.
	Capabilities() Caps
	// Read reads input bytes. It returns io.EOF when the terminal is closed.
	Read(p []byte) (int, error)
	// ResizeEvents yields a value whenever the terminal is resized. The channel
	// is closed when the terminal is.
	ResizeEvents() <-chan Size
	// Close releases the terminal. It must leave raw mode and the alternate
	// screen even if the caller forgot to.
	Close() error
}

Terminal controls the physical terminal.

Implementations are the real x/sys-backed terminal and a headless fake for CI. Nothing in the core depends on which: the renderer depends only on Sink, and widget tests depend only on Terminal plus Sink (ADR 0001).

type Widget

type Widget interface {
	// Bounds returns the widget's rectangle in screen cells. It must be safe to
	// call before the widget has ever been drawn.
	Bounds() Rect
	// Draw writes the widget's cells into buf, which is clipped to Bounds.
	// It is called every frame for every widget and is expected to be cheap
	// and idempotent: writing the same state twice must produce the same cells.
	Draw(buf *buffer.Buffer)
	// Invalidate marks Bounds dirty. It must be safe to call from any
	// goroutine (ADR 0003), which the buffer's dirty accumulator provides.
	Invalidate()
	// Handle offers the event to the widget and reports whether it consumed it.
	// Events reach a widget only after the application's keymap has declined
	// them (ADR 0009), so a binding in a keymap shadows a switch in this
	// widget. A widget's own key handling is therefore the fallback, not the
	// primary path, and a key that matters to both should be a command.
	Handle(Event) bool
}

Widget is a retained node in the UI tree, exactly as ADR 0003 specifies it.

The four-method surface is the whole contract, and its smallness is the point: there is no reconciler, no virtual tree, no incremental-draw interface, and no message algebra. ADR 0003 argues each of those away explicitly — most importantly that requiring widget authors to implement correct incremental invalidation is a discipline Go cannot enforce, and that silent invalidation bugs are the worst class of bug a TUI can have.

The trade, recorded in ADR 0003 and accepted: Draw runs for every widget every frame, cheap today (~81 µs for 12,000 cells) with no lever to pull if it ever stops being cheap. The dirty-rectangle accumulator is the hook an incremental API would attach to, when that day comes.

Directories

Path Synopsis
Package buffer implements TermMosaic's cell buffer: the padding-free 16-byte Cell, the packed Colour type, the Attr bitmask, and the row-major Buffer that widgets draw into.
Package buffer implements TermMosaic's cell buffer: the padding-free 16-byte Cell, the packed Colour type, the Attr bitmask, and the row-major Buffer that widgets draw into.
cmd
capture command
Command capture renders every widget in the TermMosaic catalog and writes the plain-text and HTML captures the documentation site displays.
Command capture renders every widget in the TermMosaic catalog and writes the plain-text and HTML captures the documentation site displays.
examples
dashboard command
Command dashboard is TermMosaic's showcase: one screen that composes nine widgets from the catalog and moves data through all of them.
Command dashboard is TermMosaic's showcase: one screen that composes nine widgets from the catalog and moves data through all of them.
hello command
Command hello is TermMosaic's runnable example: it clears the screen, draws a bordered block that fills the terminal, shows a live frame counter and the negotiated colour depth, and exits on q.
Command hello is TermMosaic's runnable example: it clears the screen, draws a bordered block that fills the terminal, shows a live frame counter and the negotiated colour depth, and exits on q.
markets command
search command
Package geometry holds TermMosaic's coordinate types: the rectangle and the size, in cell coordinates.
Package geometry holds TermMosaic's coordinate types: the rectangle and the size, in cell coordinates.
Package headless provides a terminal that touches no real device and a sink that exposes the resulting cell buffer.
Package headless provides a terminal that touches no real device and a sink that exposes the resulting cell buffer.
Package input decodes a terminal's byte stream into termmosaic.Event values.
Package input decodes a terminal's byte stream into termmosaic.Event values.
internal
ansi
Package ansi encodes the fixed subset of ANSI/VT sequences TermMosaic emits.
Package ansi encodes the fixed subset of ANSI/VT sequences TermMosaic emits.
diff
Package diff implements TermMosaic's two-tier cell diff: a per-row skip on top of a per-cell pass.
Package diff implements TermMosaic's two-tier cell diff: a per-row skip on top of a per-cell pass.
docsgen
Package docsgen renders every widget in the catalog and writes the captures the documentation site displays.
Package docsgen renders every widget in the catalog and writes the captures the documentation site displays.
Package keymap is TermMosaic's command layer: a named action an application can invoke, and a mapping from a decoded Event to it.
Package keymap is TermMosaic's command layer: a named action an application can invoke, and a mapping from a decoded Event to it.
Package layout implements TermMosaic's constraint-based layout solver.
Package layout implements TermMosaic's constraint-based layout solver.
Package render implements TermMosaic's hybrid renderer.
Package render implements TermMosaic's hybrid renderer.
Package term implements the real terminal backend: a termmosaic.Terminal driving a tty and a termmosaic.Sink writing to it.
Package term implements the real terminal backend: a termmosaic.Terminal driving a tty and a termmosaic.Sink writing to it.
Package virtual is the scroll engine for data widgets: it renders a window of rows out of a much larger collection, in constant time per frame regardless of how large the collection is.
Package virtual is the scroll engine for data widgets: it renders a window of rows out of a much larger collection, in constant time per frame regardless of how large the collection is.
widgets
basic
Package basic provides the two text widgets: Text, which writes styled spans on one line, and Paragraph, which wraps them.
Package basic provides the two text widgets: Text, which writes styled spans on one line, and Paragraph, which wraps them.
block
Package block provides Block, the catalog's only owner of borders and titles.
Package block provides Block, the catalog's only owner of borders and titles.
data
Package data provides the catalog's scrolling data widgets: List, Table, Tree and Pager.
Package data provides the catalog's scrolling data widgets: List, Table, Tree and Pager.
dialog
Package dialog provides Dialog: the catalog's modal — a box with a title, a body, and either a row of buttons or a list of choices.
Package dialog provides Dialog: the catalog's modal — a box with a title, a body, and either a row of buttons or a list of choices.
form
Package form provides the input widgets: TextInput, TextArea, Select, Checkbox, Radio, Toggle, Tabs, Button and KeyHint.
Package form provides the input widgets: TextInput, TextArea, Select, Checkbox, Radio, Toggle, Tabs, Button and KeyHint.
menu
Package menu provides Menu, a keyboard-driven menu with nested submenus to arbitrary depth.
Package menu provides Menu, a keyboard-driven menu with nested submenus to arbitrary depth.
split
Package split provides Split, the pane composer: it solves one layout and hands each pane a rectangle.
Package split provides Split, the pane composer: it solves one layout and hands each pane a rectangle.
viz
Package viz provides the catalog's measurement and display widgets: ProgressBar, Gauge, Meter, Sparkline and BarChart.
Package viz provides the catalog's measurement and display widgets: ProgressBar, Gauge, Meter, Sparkline and BarChart.
widgettest
Package widgettest renders widgets through the whole stack in a test, with no terminal involved.
Package widgettest renders widgets through the whole stack in a test, with no terminal involved.

Jump to

Keyboard shortcuts

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