tui

package module
v0.1.4 Latest Latest
Warning

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

Go to latest
Published: Jul 21, 2026 License: MIT Imports: 16 Imported by: 0

README

Nagi TUI for Go

日本語

Nagi TUI for Go provides a native cell-based TUI runtime, Unicode-aware semantic nodes, 21 standard widgets, supervised asynchronous work, subscriptions, and deterministic test support

Requirements

  • Go 1.25 or newer
  • Linux or macOS on x86-64 or ARM64

Installation

go get github.com/mayahiro/nagitui-go@v0.1.0

Quick start

Run the minimal stateful counter:

go run ./examples/counter

Packages

Package Responsibility
Module root tui App lifecycle, semantic nodes, layout, events, Effects, Subscriptions, and terminal loop
surface Geometry, Cells, Surface drawing, composition, diffing, and snapshots
widget 21 standard widgets built from the public TUI API
tuitest Virtual input, resize, time, effects, subscriptions, and frame inspection
github.com/mayahiro/nagi-go/text Shared Unicode 17 text primitives
github.com/mayahiro/nagi-go/vt Shared typed terminal input/output, Color, Attributes, and Style

The root package re-exports Surface geometry and VT style types for application convenience. Their canonical definitions remain in surface and vt

The Nagi semantic specifications define behavior shared with the Rust implementation

Testing applications

Package tuitest drives messages, terminal input, resize, virtual time, Effects, Subscriptions, and frame inspection without a real terminal

The shared event-driven application architecture explains how process output and timers enter Nagi without a second UI loop

Examples

Run commands from the Go repository root in a real terminal

Example Command
Counter go run ./examples/counter
Command palette go run ./examples/command-palette
Async search go run ./examples/async-search
Event-driven log viewer go run ./examples/log-viewer
Virtual scroll go run ./examples/virtual-scroll
Widget gallery go run ./examples/widget-gallery
Extended widget gallery go run ./examples/extended-widget-gallery
Dashboard go run ./examples/dashboard
Filtered list go run ./examples/filtered-list
File browser go run ./examples/file-browser
Multi-pane log viewer go run ./examples/multi-pane-log-viewer
Form validation go run ./examples/form-validation

Limitations

Terminal input and output must be connected to a terminal. Mouse reporting is disabled by default. Raw mode and screen restoration are best effort on normal return, error, and panic paths. Process abort, nested terminal sessions, suspend and resume, and /dev/tty acquisition are not supported

ScrollViewport clips and scrolls an eager child tree. Large data sets can use VirtualScrollViewport, which declares the complete cell extent and constructs only the current visible or bounded-overscan VirtualFragment

License

Source code is available under the MIT License. Generated Unicode data is distributed under the Unicode License v3

Documentation

Overview

Package tui provides the application, semantic view, layout, and runtime facade for Nagi TUI.

Index

Constants

View Source
const (
	// ColorDefault is the terminal's default color
	ColorDefault = vt.ColorDefault
	// ColorIndexed is an indexed terminal palette entry
	ColorIndexed = vt.ColorIndexed
	// ColorRGB is a 24-bit RGB color
	ColorRGB = vt.ColorRGB
)
View Source
const DefaultQueueCapacity = 4_096

DefaultQueueCapacity is the default maximum number of waiting messages

View Source
const DefaultSubscriptionCapacity = 256

DefaultSubscriptionCapacity is the default per-source subscription inbox capacity

View Source
const DefaultTaskLimit = 64

DefaultTaskLimit is the default maximum number of concurrent effect tasks

Variables

View Source
var (
	// ErrZeroQueueCapacity indicates that runtime queue capacity is zero
	ErrZeroQueueCapacity = errors.New("runtime queue capacity must be positive")
	// ErrQueueFull indicates that the bounded runtime message queue is full
	ErrQueueFull = errors.New("runtime message queue is full")
	// ErrZeroTaskLimit indicates that concurrent task limit is zero
	ErrZeroTaskLimit = errors.New("runtime task limit must be positive")
	// ErrZeroSubscriptionCapacity indicates that subscription capacity is zero
	ErrZeroSubscriptionCapacity = errors.New("runtime subscription capacity must be positive")
	// ErrNegativeFrameInterval indicates that a frame interval is negative
	ErrNegativeFrameInterval = errors.New("runtime minimum frame interval must not be negative")
)

Functions

func RunTerminal

func RunTerminal[Message any](
	app App[Message],
	options TerminalOptions,
	mapEvent func(vt.Event) EventAction[Message],
) error

RunTerminal runs an application in the process terminal until the application or mapEvent requests exit, or terminal input reaches EOF

The terminal session restores raw mode and screen state on normal, error, and panic exits.

func RunTerminalContext

func RunTerminalContext[Message any](
	ctx context.Context,
	app App[Message],
	options TerminalOptions,
	mapEvent func(vt.Event) EventAction[Message],
) error

RunTerminalContext runs an application until normal exit, terminal EOF, or context cancellation

Context cancellation returns ctx.Err(). The terminal session restores raw mode and screen state on every return path.

Types

type ANSITextOptions

type ANSITextOptions struct {
	// Paragraph contains wrapping and alignment settings for parsed spans
	Paragraph ParagraphOptions
}

ANSITextOptions controls paragraph behavior after safe ANSI SGR parsing

type App

type App[Message any] interface {
	// Init initializes application state and returns startup work
	Init() Effect[Message]
	// Update applies one message and returns follow-up work
	Update(Message) Effect[Message]
	// Subscriptions describes long-lived message sources for the current state
	Subscriptions() Subscription[Message]
	// View rebuilds the semantic view for the current state
	View(ViewContext) Node[Message]
}

App is one application whose state is updated by sequential messages

type Attributes

type Attributes = vt.Attributes

Attributes is the VT-owned Boolean terminal attribute type

type BorderKind

type BorderKind uint8

BorderKind selects a built-in one-cell panel border

const (
	// BorderSingle uses square single-line box drawing characters
	BorderSingle BorderKind = iota
	// BorderRounded uses rounded single-line corners
	BorderRounded
	// BorderDouble uses double-line box drawing characters
	BorderDouble
	// BorderThick uses heavy box drawing characters
	BorderThick
)

type Clock

type Clock interface {
	// Now returns the current monotonic timestamp
	Now() Timestamp
}

Clock is a monotonic time source used by runtime scheduling

type Color

type Color = vt.Color

Color is the VT-owned terminal color type

func DefaultColor

func DefaultColor() Color

DefaultColor returns the terminal default color

func IndexedColor

func IndexedColor(index uint8) Color

IndexedColor returns an indexed terminal palette color

func RGBColor

func RGBColor(red, green, blue uint8) Color

RGBColor returns a 24-bit RGB color

type ColorKind

type ColorKind = vt.ColorKind

ColorKind is the VT-owned terminal color representation kind

type DeliveryPolicy

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

DeliveryPolicy defines bounded delivery behavior for one subscription

func BatchDelivery

func BatchDelivery(maximumMessages int, maximumDelay time.Duration) DeliveryPolicy

BatchDelivery releases FIFO values after maximumMessages or maximumDelay

It panics when maximumMessages is not positive or maximumDelay is negative.

func LatestDelivery

func LatestDelivery() DeliveryPolicy

LatestDelivery retains only the newest value not yet delivered to Update

func ReliableDelivery

func ReliableDelivery() DeliveryPolicy

ReliableDelivery preserves every value in FIFO order and blocks a full Stream inbox

func (DeliveryPolicy) BatchLimits

func (p DeliveryPolicy) BatchLimits() (int, time.Duration, bool)

BatchLimits returns the count and delay for Batch delivery

func (DeliveryPolicy) IsLatest

func (p DeliveryPolicy) IsLatest() bool

IsLatest reports whether only the newest pending value is retained

func (DeliveryPolicy) IsReliable

func (p DeliveryPolicy) IsReliable() bool

IsReliable reports whether every value is delivered reliably

type DuplicateNodeIDError

type DuplicateNodeIDError struct {
	// ID is the duplicated application-defined identity
	ID NodeID
}

DuplicateNodeIDError indicates that one semantic tree reused a stable ID

func (*DuplicateNodeIDError) Error

func (e *DuplicateNodeIDError) Error() string

Error returns the duplicate identity diagnostic

type DuplicateSubscriptionKeyError

type DuplicateSubscriptionKeyError struct {
	// Key is the duplicated application-defined identity
	Key SubscriptionKey
}

DuplicateSubscriptionKeyError indicates that one declaration reused a key

func (*DuplicateSubscriptionKeyError) Error

Error returns the duplicate identity diagnostic

type Effect

type Effect[Message any] struct {
	// contains filtered or unexported fields
}

Effect is declarative follow-up work produced by App.Init or App.Update

func AfterEffect

func AfterEffect[Message any](delay time.Duration, message Message) Effect[Message]

AfterEffect emits message after delay according to the runtime clock

A negative delay is treated as zero.

func BatchEffects

func BatchEffects[Message any](effects ...Effect[Message]) Effect[Message]

BatchEffects starts child effects independently and completes when all finish

func CancelEffect

func CancelEffect[Message any](key TaskKey) Effect[Message]

CancelEffect cancels the current latest task for key

func CancelScopeEffect

func CancelScopeEffect[Message any](scope ScopeID) Effect[Message]

CancelScopeEffect cancels current tasks and timers in scope

func ExitEffect

func ExitEffect[Message any]() Effect[Message]

ExitEffect requests normal application exit after the final dirty frame is rendered

func FocusEffect

func FocusEffect[Message any](id NodeID) Effect[Message]

FocusEffect requests focus for a focusable node in the next application view

func LatestEffect

func LatestEffect[Message any](key TaskKey, task Task[Message]) Effect[Message]

LatestEffect replaces the current task for key and suppresses stale results

It panics when task is nil.

func NoneEffect

func NoneEffect[Message any]() Effect[Message]

NoneEffect returns an effect that performs no work

func RunEffect

func RunEffect[Message any](task Task[Message]) Effect[Message]

RunEffect runs one task on a supervised goroutine

It panics when task is nil.

func ScopedEffect

func ScopedEffect[Message any](scope ScopeID, effect Effect[Message]) Effect[Message]

ScopedEffect associates every task and timer in effect with a scope

func ScrollToEffect

func ScrollToEffect[Message any](id NodeID, offset ScrollOffset) Effect[Message]

ScrollToEffect requests a ScrollViewport offset in the next application view

func SequenceEffects

func SequenceEffects[Message any](effects ...Effect[Message]) Effect[Message]

SequenceEffects runs child effects in order

func (Effect[Message]) IsNone

func (e Effect[Message]) IsNone() bool

IsNone reports whether this effect performs no work

func (Effect[Message]) WithoutRedraw added in v0.1.4

func (e Effect[Message]) WithoutRedraw() Effect[Message]

WithoutRedraw declares that the Update returning this effect did not change state observed by View

Follow-up work is still scheduled and Subscriptions are still reconciled. Synchronous UI commands and an already-dirty runtime still produce a frame.

type EffectDiagnostics

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

EffectDiagnostics contains counters for supervised task behavior

func (EffectDiagnostics) Cancellations

func (d EffectDiagnostics) Cancellations() uint64

Cancellations returns the number of cooperative cancellation requests

func (EffectDiagnostics) StaleResults

func (d EffectDiagnostics) StaleResults() uint64

StaleResults returns the number of completed task results suppressed as stale

func (EffectDiagnostics) TaskPanics

func (d EffectDiagnostics) TaskPanics() uint64

TaskPanics returns the number of panics caught at the task boundary

type EventAction

type EventAction[Message any] struct {
	// contains filtered or unexported fields
}

EventAction is the application-level decision for one normalized event

func ExitAction

func ExitAction[Message any]() EventAction[Message]

ExitAction returns an action that finishes the event loop normally

func IgnoreAction

func IgnoreAction[Message any]() EventAction[Message]

IgnoreAction returns an action that consumes an event without state changes

func MessageAction

func MessageAction[Message any](message Message) EventAction[Message]

MessageAction returns an action that adds message to the application queue

func (EventAction[Message]) Kind

func (a EventAction[Message]) Kind() EventActionKind

Kind returns the event decision variant

func (EventAction[Message]) Message

func (a EventAction[Message]) Message() (Message, bool)

Message returns the queued message for EventMessage

type EventActionKind

type EventActionKind uint8

EventActionKind identifies an application-level terminal event decision

const (
	// EventIgnore consumes an event without changing application state
	EventIgnore EventActionKind = iota
	// EventMessage adds a message to the application queue
	EventMessage
	// EventExit finishes the event loop normally
	EventExit
)

type EventDispatch

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

EventDispatch is the observable outcome of routing one normalized event

func (EventDispatch) Consumed

func (d EventDispatch) Consumed() bool

Consumed reports whether a handler consumed the event

func (EventDispatch) Messages

func (d EventDispatch) Messages() int

Messages returns the number of application messages enqueued by handlers

func (EventDispatch) RedrawRequested

func (d EventDispatch) RedrawRequested() bool

RedrawRequested reports whether routing explicitly requested a frame

type EventResult

type EventResult[Message any] struct {
	// contains filtered or unexported fields
}

EventResult is the composable result of one semantic node event handler

func ConsumeResult

func ConsumeResult[Message any]() EventResult[Message]

ConsumeResult returns a consumed result without a message

func IgnoreResult

func IgnoreResult[Message any]() EventResult[Message]

IgnoreResult returns an ignored result that continues ancestor routing

func MessageResult

func MessageResult[Message any](message Message) EventResult[Message]

MessageResult returns a consumed result that emits one application message

func (EventResult[Message]) CapturePointer

func (r EventResult[Message]) CapturePointer(id NodeID) EventResult[Message]

CapturePointer captures pointer routing for a stable Node ID

func (EventResult[Message]) Consume

func (r EventResult[Message]) Consume() EventResult[Message]

Consume stops ancestor routing after applying the result

func (EventResult[Message]) Emit

func (r EventResult[Message]) Emit(message Message) EventResult[Message]

Emit adds an application message to the result

func (EventResult[Message]) Focus

func (r EventResult[Message]) Focus(id NodeID) EventResult[Message]

Focus requests focus for a stable Node ID

func (EventResult[Message]) Redraw

func (r EventResult[Message]) Redraw() EventResult[Message]

Redraw requests a frame even without an application message

func (EventResult[Message]) ReleaseFocus

func (r EventResult[Message]) ReleaseFocus() EventResult[Message]

ReleaseFocus releases node focus

func (EventResult[Message]) ReleasePointer

func (r EventResult[Message]) ReleasePointer() EventResult[Message]

ReleasePointer releases pointer capture

type Frame

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

Frame is one coalesced rendered frame

func (Frame) Operations

func (f Frame) Operations() []vt.TerminalOp

Operations returns a copy of typed VT operations relative to the previous frame

func (Frame) Surface

func (f Frame) Surface() *surface.Surface

Surface returns an independent copy of the normalized rendered surface

func (Frame) Timestamp

func (f Frame) Timestamp() Timestamp

Timestamp returns the monotonic time at which the frame was produced

type HorizontalAlignment

type HorizontalAlignment uint8

HorizontalAlignment controls horizontal placement inside an alignment node

const (
	// AlignStart places content at the left edge
	AlignStart HorizontalAlignment = iota
	// AlignCenter centers content horizontally
	AlignCenter
	// AlignEnd places content at the right edge
	AlignEnd
)

type Insets

type Insets struct {
	// Top is the number of cells above the child
	Top uint32
	// Right is the number of cells to the child's right
	Right uint32
	// Bottom is the number of cells below the child
	Bottom uint32
	// Left is the number of cells to the child's left
	Left uint32
}

Insets contains padding widths around a node

func UniformInsets

func UniformInsets(cells uint32) Insets

UniformInsets returns equal insets on every side

type InteractionState

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

InteractionState is runtime-owned UI continuity keyed by stable Node IDs

func NewInteractionState

func NewInteractionState() *InteractionState

NewInteractionState returns empty Interaction State

func (*InteractionState) Focused

func (s *InteractionState) Focused() (NodeID, bool)

Focused returns the focused Node ID

func (*InteractionState) PointerCapture

func (s *InteractionState) PointerCapture() (NodeID, bool)

PointerCapture returns the node holding pointer capture

func (*InteractionState) ScrollOffset

func (s *InteractionState) ScrollOffset(id NodeID) ScrollOffset

ScrollOffset returns a retained scroll offset, defaulting to zero

func (*InteractionState) ScrollState

func (s *InteractionState) ScrollState(id NodeID) (ScrollState, bool)

ScrollState returns resolved ScrollViewport state for a node

func (*InteractionState) TextInput

func (s *InteractionState) TextInput(id NodeID) (TextInputState, bool)

TextInput returns retained TextInput state for a node

type Length

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

Length is a main-axis sizing rule for a child node

Its zero value is Auto.

func Auto

func Auto() Length

Auto returns a length that uses the child's measured size

func Fixed

func Fixed(cells uint32) Length

Fixed returns a length requesting an exact cell count

func Flex

func Flex(weight uint32) Length

Flex returns a length sharing remaining cells by weight

func MinMax

func MinMax(minimum, preferred, maximum uint32) Length

MinMax returns a preferred length constrained by minimum and maximum

func Percent

func Percent(percent uint32) Length

Percent returns a parent percentage rounded down and capped at 100

func (Length) Bounds

func (l Length) Bounds() (minimum, preferred, maximum uint32, ok bool)

Bounds returns the minimum, preferred, and maximum values for a MinMax length

func (Length) Kind

func (l Length) Kind() LengthKind

Kind returns the length representation

func (Length) Value

func (l Length) Value() (uint32, bool)

Value returns the cell count, weight, or percentage for Fixed, Flex, and Percent lengths

type LengthKind

type LengthKind uint8

LengthKind identifies a main-axis sizing rule

const (
	// LengthAuto uses the child's measured size
	LengthAuto LengthKind = iota
	// LengthFixed requests an exact cell count
	LengthFixed
	// LengthFlex shares cells left after non-flexible requests
	LengthFlex
	// LengthPercent requests a percentage of the parent
	LengthPercent
	// LengthMinMax requests a preferred size constrained by minimum and maximum
	LengthMinMax
)

type Node

type Node[Message any] struct {
	// contains filtered or unexported fields
}

Node is a semantic view node rebuilt by an application for each frame

func ANSIText

func ANSIText[Message any](input string, options ANSITextOptions) Node[Message]

ANSIText parses SGR styling and discards every non-display control sequence

CSI commands other than SGR, OSC, DCS, SOS, PM, APC, raw escape sequences, and non-line-breaking control characters never reach terminal output.

func Align

func Align[Message any](child Node[Message], horizontal HorizontalAlignment, vertical VerticalAlignment) Node[Message]

Align places a child within the rectangle assigned to the node

func Border

func Border[Message any](child Node[Message], style vt.Style) Node[Message]

Border wraps a child in a single-cell Unicode border

func Clip

func Clip[Message any](child Node[Message]) Node[Message]

Clip limits a child's drawing to the assigned rectangle

func Column

func Column[Message any](children ...Node[Message]) Node[Message]

Column returns a vertical container

The returned node retains the supplied variadic slice. Callers must not mutate that slice after construction.

func Gap

func Gap[Message any](cells uint32) Node[Message]

Gap returns spacing interpreted along the main axis of its immediate Row or Column

Outside a Row or Column, a Gap has zero measured size.

func Modal[Message any](id NodeID, child Node[Message]) Node[Message]

Modal marks a subtree as the active modal routing and focus scope

func Padding

func Padding[Message any](child Node[Message], insets Insets) Node[Message]

Padding wraps a child in fixed padding

func Panel

func Panel[Message any](child Node[Message], title string) Node[Message]

Panel returns a titled single-border container with one-cell inner padding

func PanelWithOptions

func PanelWithOptions[Message any](child Node[Message], title string, options PanelOptions) Node[Message]

PanelWithOptions returns a titled container with configured border, padding, and styles

func Paragraph

func Paragraph[Message any](spans []TextSpan, options ParagraphOptions) Node[Message]

Paragraph returns inline styled text using the supplied wrapping and alignment

func RichText

func RichText[Message any](spans ...TextSpan) Node[Message]

RichText returns inline styled text with grapheme-safe hard wrapping

func Row

func Row[Message any](children ...Node[Message]) Node[Message]

Row returns a horizontal container

The returned node retains the supplied variadic slice. Callers must not mutate that slice after construction.

func ScrollViewport

func ScrollViewport[Message any](id NodeID, child Node[Message]) Node[Message]

ScrollViewport returns a clipped viewport with runtime-owned cell offset

The supplied child tree is eager. Use VirtualScrollViewport when content construction must be bounded by the visible region.

func ScrollViewportWithOptions

func ScrollViewportWithOptions[Message any](
	id NodeID,
	child Node[Message],
	options ScrollViewportOptions[Message],
) Node[Message]

ScrollViewportWithOptions returns a clipped viewport with configured behavior

The supplied child tree is eager. Use VirtualScrollViewportWithOptions when content construction must be bounded by the visible region.

func Spacer

func Spacer[Message any](width, height uint32) Node[Message]

Spacer returns an invisible node with a fixed measured size

func Stack

func Stack[Message any](children ...Node[Message]) Node[Message]

Stack returns a front-to-back overlay container

The returned node retains the supplied variadic slice. Callers must not mutate that slice after construction.

func StyledText

func StyledText[Message any](content string, style vt.Style) Node[Message]

StyledText returns a styled text node

func StyledTextInput

func StyledTextInput[Message any](
	id NodeID,
	value, placeholder string,
	style, placeholderStyle vt.Style,
	onChange func(string) Message,
) Node[Message]

StyledTextInput returns a styled one-line input with placeholder text

func SurfaceNode

func SurfaceNode[Message any](source *surface.Surface) Node[Message]

SurfaceNode captures an independent snapshot of a public Surface as a node

A nil source produces an empty node. Surface cells remain typed and cannot introduce raw terminal escape sequences.

func Text

func Text[Message any](content string) Node[Message]

Text returns a default-style text node

func TextInput

func TextInput[Message any](id NodeID, value string, onChange func(string) Message) Node[Message]

TextInput returns a one-line grapheme-aware input with retained cursor state

func VirtualScrollViewport added in v0.1.1

func VirtualScrollViewport[Message any](
	id NodeID,
	contentSize Size,
	builder func(VirtualViewport) VirtualFragment[Message],
) Node[Message]

VirtualScrollViewport returns a viewport that constructs only a visible content fragment

contentSize declares the complete scrollable cell extent without constructing it. The builder is cached for one resolved visible range during the semantic frame and may return bounded overscan before that range. A nil builder produces empty fragments.

func VirtualScrollViewportWithOptions added in v0.1.1

func VirtualScrollViewportWithOptions[Message any](
	id NodeID,
	contentSize Size,
	options ScrollViewportOptions[Message],
	builder func(VirtualViewport) VirtualFragment[Message],
) Node[Message]

VirtualScrollViewportWithOptions returns a virtual viewport with configured scrolling behavior

Only the cached fragment participates in measurement, rendering, focus, hit testing, and event routing. Fragment Node IDs therefore represent visible or overscanned content and must remain stable across requests.

func (Node[Message]) Focusable

func (n Node[Message]) Focusable(id NodeID) Node[Message]

Focusable makes the node focusable under a stable identity

func (Node[Message]) OnEvent

func (n Node[Message]) OnEvent(id NodeID, handler func(vt.Event) EventResult[Message]) Node[Message]

OnEvent attaches an event handler under a stable identity

func (Node[Message]) TabStop

func (n Node[Message]) TabStop(enabled bool) Node[Message]

TabStop controls Tab traversal participation without changing the stable ID

func (Node[Message]) WithFocusedStyle

func (n Node[Message]) WithFocusedStyle(style vt.Style) Node[Message]

WithFocusedStyle merges style over this node's clipped rectangle while it owns focus. It does not change measurement, layout, hit testing, or routing. The node must also have a stable identity, normally through Focusable or OnEvent.

func (Node[Message]) WithID

func (n Node[Message]) WithID(id NodeID) Node[Message]

WithID attaches a stable semantic identity without changing focus behavior

func (Node[Message]) WithLength

func (n Node[Message]) WithLength(length Length) Node[Message]

WithLength sets the node's main-axis sizing rule in a row or column

type NodeID

type NodeID string

NodeID is an application-defined stable identity for an interactive or stateful node

func NewNodeID

func NewNodeID(value string) NodeID

NewNodeID returns an identifier from an application-defined stable key

func (NodeID) String

func (id NodeID) String() string

String returns the application-defined key

type OptionalColor

type OptionalColor = vt.OptionalColor

OptionalColor is the VT-owned optional terminal color type

func SomeColor

func SomeColor(color Color) OptionalColor

SomeColor returns an optional color containing color

type PanelOptions

type PanelOptions struct {
	// Border selects the border character set
	Border BorderKind
	// Padding is applied inside the one-cell border
	Padding Insets
	// Style controls panel colors and attributes
	Style PanelStyle
}

PanelOptions controls panel border, padding, and styles

func DefaultPanelOptions

func DefaultPanelOptions() PanelOptions

DefaultPanelOptions returns a single border with one-cell inner padding

type PanelStyle

type PanelStyle struct {
	// Border styles the border cells
	Border vt.Style
	// Title styles the optional title
	Title vt.Style
	// Background fills the complete panel rectangle before child rendering
	Background vt.Style
}

PanelStyle contains the visual styles used by a Panel node

type ParagraphOptions

type ParagraphOptions struct {
	// Wrap controls automatic line boundaries
	Wrap WrapMode
	// Alignment places each rendered line within the paragraph rectangle
	Alignment HorizontalAlignment
}

ParagraphOptions controls paragraph wrapping and horizontal alignment

The zero value uses word wrapping and start alignment.

func DefaultParagraphOptions

func DefaultParagraphOptions() ParagraphOptions

DefaultParagraphOptions returns word wrapping with start alignment

type Point

type Point = surface.Point

Point is the Surface-owned terminal cell coordinate type

type Rect

type Rect = surface.Rect

Rect is the Surface-owned half-open terminal cell rectangle type

type Runtime

type Runtime[Message any] struct {
	// contains filtered or unexported fields
}

Runtime is a single-goroutine application runtime with a bounded FIFO queue

func NewRuntime

func NewRuntime[Message any](app App[Message], size Size) (*Runtime[Message], error)

NewRuntime returns a runtime using a production monotonic clock

func NewRuntimeWithClock

func NewRuntimeWithClock[Message any](app App[Message], config RuntimeConfig, clock Clock) (*Runtime[Message], error)

NewRuntimeWithClock returns a runtime using explicit settings and clock

func (*Runtime[Message]) ActiveSubscriptions

func (r *Runtime[Message]) ActiveSubscriptions() int

ActiveSubscriptions returns the number of currently declared sources

func (*Runtime[Message]) ActiveTasks

func (r *Runtime[Message]) ActiveTasks() int

ActiveTasks returns supervised tasks that have not fully finished

func (*Runtime[Message]) App

func (r *Runtime[Message]) App() App[Message]

App returns the application instance owned by the runtime

func (*Runtime[Message]) ClearFocus

func (r *Runtime[Message]) ClearFocus()

ClearFocus releases node focus and schedules a frame when focus existed

func (*Runtime[Message]) Close

func (r *Runtime[Message]) Close()

Close cooperatively cancels active effect tasks and timers

func (*Runtime[Message]) DispatchEvent

func (r *Runtime[Message]) DispatchEvent(event vt.Event) (EventDispatch, error)

DispatchEvent routes one normalized event through focus, hit testing, and ancestors

func (*Runtime[Message]) EffectDiagnostics

func (r *Runtime[Message]) EffectDiagnostics() EffectDiagnostics

EffectDiagnostics returns cancellation, stale-result, and panic counters

func (*Runtime[Message]) Enqueue

func (r *Runtime[Message]) Enqueue(message Message) error

Enqueue adds one message to the FIFO queue

func (*Runtime[Message]) ExitRequested

func (r *Runtime[Message]) ExitRequested() bool

ExitRequested reports whether the application requested normal exit

func (*Runtime[Message]) Interaction

func (r *Runtime[Message]) Interaction() *InteractionState

Interaction returns runtime-owned UI continuity

func (*Runtime[Message]) PendingEffectMessages

func (r *Runtime[Message]) PendingEffectMessages() int

PendingEffectMessages returns completed effect messages waiting for capacity

func (*Runtime[Message]) PendingSubscriptionMessages

func (r *Runtime[Message]) PendingSubscriptionMessages() int

PendingSubscriptionMessages returns values waiting before the application queue

func (*Runtime[Message]) PendingTasks

func (r *Runtime[Message]) PendingTasks() int

PendingTasks returns supervised tasks waiting for a worker slot

func (*Runtime[Message]) PollEffects

func (r *Runtime[Message]) PollEffects() int

PollEffects moves due timers and completed tasks into the bounded queue

func (*Runtime[Message]) PollSubscriptions

func (r *Runtime[Message]) PollSubscriptions() int

PollSubscriptions moves ready subscription values into the bounded queue

func (*Runtime[Message]) ProcessPending

func (r *Runtime[Message]) ProcessPending() (int, error)

ProcessPending applies every queued message in FIFO order without rendering between messages

func (*Runtime[Message]) ProcessPendingWith

func (r *Runtime[Message]) ProcessPendingWith(observe func(Message)) (int, error)

ProcessPendingWith applies queued messages and observes each immediately before Update

func (*Runtime[Message]) QueuedMessages

func (r *Runtime[Message]) QueuedMessages() int

QueuedMessages returns the number of waiting messages

func (*Runtime[Message]) RenderIfDirty

func (r *Runtime[Message]) RenderIfDirty() (*Frame, error)

RenderIfDirty renders one frame when requested or state changed

func (*Runtime[Message]) RequestFocus

func (r *Runtime[Message]) RequestFocus(id NodeID) (bool, error)

RequestFocus requests focus for an ID in the current semantic tree

func (*Runtime[Message]) RequestFrame

func (r *Runtime[Message]) RequestFrame()

RequestFrame schedules a frame even when application state has not changed

func (*Runtime[Message]) Resize

func (r *Runtime[Message]) Resize(size Size)

Resize changes terminal size and schedules a frame when it differs

func (*Runtime[Message]) RunningSubscriptionStreams

func (r *Runtime[Message]) RunningSubscriptionStreams() int

RunningSubscriptionStreams returns Stream producers that have not returned

func (*Runtime[Message]) RunningTasks

func (r *Runtime[Message]) RunningTasks() int

RunningTasks returns supervised tasks occupying worker slots

func (*Runtime[Message]) SetScrollOffset

func (r *Runtime[Message]) SetScrollOffset(id NodeID, offset ScrollOffset) bool

SetScrollOffset requests an offset that is clamped during layout

func (*Runtime[Message]) SetTextCursor

func (r *Runtime[Message]) SetTextCursor(id NodeID, cursor int) bool

SetTextCursor sets a UTF-8 byte cursor normalized to a grapheme boundary

func (*Runtime[Message]) Size

func (r *Runtime[Message]) Size() Size

Size returns the current terminal cell size

func (*Runtime[Message]) Step

func (r *Runtime[Message]) Step() (*Frame, error)

Step processes all queued messages and produces at most one frame

func (*Runtime[Message]) SubscriptionActive

func (r *Runtime[Message]) SubscriptionActive(key SubscriptionKey) bool

SubscriptionActive reports whether key is currently declared

func (*Runtime[Message]) SubscriptionDiagnostics

func (r *Runtime[Message]) SubscriptionDiagnostics() SubscriptionDiagnostics

SubscriptionDiagnostics returns lifecycle and backpressure counters

func (*Runtime[Message]) SubscriptionGeneration

func (r *Runtime[Message]) SubscriptionGeneration(key SubscriptionKey) uint64

SubscriptionGeneration returns the latest started generation for key

func (*Runtime[Message]) TaskGeneration

func (r *Runtime[Message]) TaskGeneration(key TaskKey) uint64

TaskGeneration returns the latest generation started for one task key

func (*Runtime[Message]) TimeUntilEffectDeadline

func (r *Runtime[Message]) TimeUntilEffectDeadline() (time.Duration, bool)

TimeUntilEffectDeadline returns time until the next clock-driven deadline

func (*Runtime[Message]) TimeUntilFrameDeadline

func (r *Runtime[Message]) TimeUntilFrameDeadline() (time.Duration, bool)

TimeUntilFrameDeadline returns time until a pending rate-limited frame

func (*Runtime[Message]) TimeUntilSubscriptionDeadline

func (r *Runtime[Message]) TimeUntilSubscriptionDeadline() (time.Duration, bool)

TimeUntilSubscriptionDeadline returns time until the next subscription deadline

type RuntimeConfig

type RuntimeConfig struct {
	// Size is the initial terminal cell size
	Size Size
	// QueueCapacity is the maximum number of waiting messages
	QueueCapacity int
	// TaskLimit is the maximum number of effect tasks executing concurrently
	TaskLimit int
	// SubscriptionCapacity is the maximum pending values retained per source
	SubscriptionCapacity int
	// MinimumFrameInterval limits non-urgent rendering; zero disables the limit
	MinimumFrameInterval time.Duration
}

RuntimeConfig contains runtime construction settings

func NewRuntimeConfig

func NewRuntimeConfig(size Size) RuntimeConfig

NewRuntimeConfig returns settings with the default bounded queue capacity

type ScopeID

type ScopeID string

ScopeID is a stable key grouping tasks for explicit cancellation

func NewScopeID

func NewScopeID(value string) ScopeID

NewScopeID returns a scope ID from an application-defined stable value

func (ScopeID) String

func (s ScopeID) String() string

String returns the application-defined key

type ScrollAxis

type ScrollAxis uint8

ScrollAxis selects the axes controlled by a ScrollViewport

const (
	// ScrollAxisBoth enables horizontal and vertical scrolling
	ScrollAxisBoth ScrollAxis = iota
	// ScrollAxisVertical enables vertical scrolling only
	ScrollAxisVertical
	// ScrollAxisHorizontal enables horizontal scrolling only
	ScrollAxisHorizontal
)

type ScrollOffset

type ScrollOffset struct {
	// X is the horizontal content offset
	X uint32
	// Y is the vertical content offset
	Y uint32
}

ScrollOffset is a two-dimensional ScrollViewport offset in cells

type ScrollState

type ScrollState struct {
	// Offset is the current cell offset after clamping
	Offset ScrollOffset
	// Maximum is the greatest valid offset for the current content and viewport
	Maximum ScrollOffset
	// AtStart reports whether every enabled axis is at its beginning
	AtStart bool
	// AtEnd reports whether every enabled axis is at its end
	AtEnd bool
}

ScrollState contains a resolved ScrollViewport position and boundaries

type ScrollViewportOptions

type ScrollViewportOptions[Message any] struct {
	// Axis selects the axes controlled by user and programmatic scrolling
	Axis ScrollAxis
	// StickToEnd follows content growth while the viewport remains at its end
	StickToEnd bool
	// EnsureFocusedVisible scrolls a focused descendant into view
	EnsureFocusedVisible bool
	// OnScroll optionally maps user scroll state changes to application messages
	OnScroll func(ScrollState) Message
}

ScrollViewportOptions controls ScrollViewport behavior

func DefaultScrollViewportOptions

func DefaultScrollViewportOptions[Message any]() ScrollViewportOptions[Message]

DefaultScrollViewportOptions returns two-dimensional scrolling without automatic following or focus tracking

type Size

type Size = surface.Size

Size is the Surface-owned non-negative terminal cell size type

type Style

type Style = vt.Style

Style is the VT-owned terminal style type

type Subscription

type Subscription[Message any] struct {
	// contains filtered or unexported fields
}

Subscription is a declarative set of long-lived application message sources

func BatchSubscriptions

func BatchSubscriptions[Message any](subscriptions ...Subscription[Message]) Subscription[Message]

BatchSubscriptions combines declarations while preserving declaration order

func EverySubscription

func EverySubscription[Message any](
	key SubscriptionKey,
	interval time.Duration,
	policy DeliveryPolicy,
	factory func() Message,
) Subscription[Message]

EverySubscription returns a runtime-clock interval source

The first value is produced after one full interval. It panics when interval is not positive or factory is nil.

func NoneSubscription

func NoneSubscription[Message any]() Subscription[Message]

NoneSubscription returns an empty subscription set

func StreamSubscription

func StreamSubscription[Message any](
	key SubscriptionKey,
	policy DeliveryPolicy,
	stream SubscriptionStream[Message],
) Subscription[Message]

StreamSubscription returns a cooperatively cancellable long-lived source

It panics when stream is nil.

func (Subscription[Message]) IsNone

func (s Subscription[Message]) IsNone() bool

IsNone reports whether this declaration contains no sources

func (Subscription[Message]) String

func (s Subscription[Message]) String() string

String returns a diagnostic description of the subscription shape

type SubscriptionDiagnostics

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

SubscriptionDiagnostics contains lifecycle, backpressure, and failure counters

func (SubscriptionDiagnostics) BatchFlushes

func (d SubscriptionDiagnostics) BatchFlushes() uint64

BatchFlushes returns count- or time-triggered Batch releases

func (SubscriptionDiagnostics) BlockedSends

func (d SubscriptionDiagnostics) BlockedSends() uint64

BlockedSends returns Stream sends that encountered a full inbox

func (SubscriptionDiagnostics) DiscardedMessages

func (d SubscriptionDiagnostics) DiscardedMessages() uint64

DiscardedMessages returns values discarded when a generation stopped

func (SubscriptionDiagnostics) LatestReplacements

func (d SubscriptionDiagnostics) LatestReplacements() uint64

LatestReplacements returns pending Latest values replaced before delivery

func (SubscriptionDiagnostics) ProducerPanics

func (d SubscriptionDiagnostics) ProducerPanics() uint64

ProducerPanics returns producer or Every factory panics isolated by the supervisor

func (SubscriptionDiagnostics) Starts

func (d SubscriptionDiagnostics) Starts() uint64

Starts returns the number of started subscription generations

func (SubscriptionDiagnostics) Stops

func (d SubscriptionDiagnostics) Stops() uint64

Stops returns the number of stopped subscription generations

type SubscriptionKey

type SubscriptionKey string

SubscriptionKey is a stable identity for one long-lived source

func NewSubscriptionKey

func NewSubscriptionKey(value string) SubscriptionKey

NewSubscriptionKey returns a key from an application-defined stable value

func (SubscriptionKey) String

func (k SubscriptionKey) String() string

String returns the application-defined key

type SubscriptionSink

type SubscriptionSink[Message any] struct {
	// contains filtered or unexported fields
}

SubscriptionSink is a cancellation-aware sender owned by one Stream producer

func (SubscriptionSink[Message]) Closed

func (s SubscriptionSink[Message]) Closed() bool

Closed reports whether the runtime stopped this subscription generation

func (SubscriptionSink[Message]) Done

func (s SubscriptionSink[Message]) Done() <-chan struct{}

Done is closed when the runtime stops this subscription generation

func (SubscriptionSink[Message]) Send

func (s SubscriptionSink[Message]) Send(message Message) bool

Send submits a value according to the source delivery policy

Reliable and Batch delivery can block while the bounded inbox is full. It returns false after the runtime stops this subscription generation.

type SubscriptionStream

type SubscriptionStream[Message any] func(context.Context, SubscriptionSink[Message])

SubscriptionStream is one cooperatively cancellable long-lived producer

type SystemClock

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

SystemClock is a production monotonic clock based on time.Time

func NewSystemClock

func NewSystemClock() SystemClock

NewSystemClock returns a production clock with a new origin

func (SystemClock) Now

func (c SystemClock) Now() Timestamp

Now returns elapsed monotonic time from the clock origin

type Task

type Task[Message any] func(context.Context) Message

Task is one goroutine task producing an application message

type TaskKey

type TaskKey string

TaskKey is a stable key for replacement and cancellation of one latest task

func NewTaskKey

func NewTaskKey(value string) TaskKey

NewTaskKey returns a task key from an application-defined stable value

func (TaskKey) String

func (k TaskKey) String() string

String returns the application-defined key

type TerminalOptions

type TerminalOptions struct {
	// Capabilities contains optional output encoder capabilities
	Capabilities vt.Capabilities
	// MouseTracking enables SGR mouse reports when non-nil
	//
	// It is disabled by default so terminal text selection remains available.
	MouseTracking *vt.MouseTracking
	// FocusFirst focuses the first focusable node before the initial frame
	FocusFirst bool
	// EscapeTimeout disambiguates a lone ESC from an escape sequence
	EscapeTimeout time.Duration
	// QueueCapacity is the maximum number of waiting application messages
	QueueCapacity int
	// TaskLimit is the maximum number of effect tasks executing concurrently
	TaskLimit int
	// SubscriptionCapacity is the maximum pending values retained per source
	SubscriptionCapacity int
	// MinimumFrameInterval limits non-urgent rendering; the default is 120 FPS
	// and zero disables the limit
	MinimumFrameInterval time.Duration
}

TerminalOptions contains settings for RunTerminal

func DefaultTerminalOptions

func DefaultTerminalOptions() TerminalOptions

DefaultTerminalOptions returns event-driven settings with bounded queues and non-urgent rendering limited to 120 FPS

type TextInputState

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

TextInputState is Interaction State retained for one TextInput node

func (TextInputState) Cursor

func (s TextInputState) Cursor() int

Cursor returns the UTF-8 byte cursor at a grapheme boundary

type TextSpan

type TextSpan struct {
	// Text is UTF-8 content rendered with Style
	Text string
	// Style applies to every grapheme in Text
	Style vt.Style
}

TextSpan is one styled run of paragraph text

func NewTextSpan

func NewTextSpan(text string, style vt.Style) TextSpan

NewTextSpan returns one styled text run

type TimedInputDecoder

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

TimedInputDecoder is a VT input decoder whose ambiguous lone-ESC timeout uses an injected clock

func NewTimedInputDecoder

func NewTimedInputDecoder(clock Clock, escapeTimeout time.Duration) *TimedInputDecoder

NewTimedInputDecoder returns a timed decoder

It panics when clock is nil. A negative escape timeout is treated as zero.

func (*TimedInputDecoder) Feed

func (d *TimedInputDecoder) Feed(input []byte) []vt.Event

Feed consumes one arbitrary input byte chunk

func (*TimedInputDecoder) Flush

func (d *TimedInputDecoder) Flush() []vt.Event

Flush resolves all currently incomplete input immediately

func (*TimedInputDecoder) HasPending

func (d *TimedInputDecoder) HasPending() bool

HasPending reports whether incomplete input is buffered

func (*TimedInputDecoder) Poll

func (d *TimedInputDecoder) Poll() []vt.Event

Poll resolves a lone ESC when its deadline has elapsed

func (*TimedInputDecoder) TimeUntilDeadline

func (d *TimedInputDecoder) TimeUntilDeadline() (time.Duration, bool)

TimeUntilDeadline returns time until a lone-ESC deadline

type Timestamp

type Timestamp uint64

Timestamp is a monotonic runtime time measured in nanoseconds from a clock origin

func (Timestamp) Add

func (t Timestamp) Add(duration time.Duration) Timestamp

Add returns a timestamp advanced by duration, saturating at the maximum

A nonpositive duration leaves the timestamp unchanged.

func (Timestamp) Nanoseconds

func (t Timestamp) Nanoseconds() uint64

Nanoseconds returns nanoseconds since the clock origin

type VerticalAlignment

type VerticalAlignment uint8

VerticalAlignment controls vertical placement inside an alignment node

const (
	// AlignTop places content at the top edge
	AlignTop VerticalAlignment = iota
	// AlignMiddle centers content vertically
	AlignMiddle
	// AlignBottom places content at the bottom edge
	AlignBottom
)

type ViewContext

type ViewContext struct {
	// Size is the current terminal size in cells
	Size Size
}

ViewContext contains environment information available while rebuilding a semantic view

type VirtualClock

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

VirtualClock is a manually advanced monotonic clock for deterministic tests

func NewVirtualClock

func NewVirtualClock() *VirtualClock

NewVirtualClock returns a virtual clock at timestamp zero

func (*VirtualClock) Advance

func (c *VirtualClock) Advance(duration time.Duration) Timestamp

Advance moves the clock forward and returns its new timestamp

A nonpositive duration leaves the clock unchanged.

func (*VirtualClock) Now

func (c *VirtualClock) Now() Timestamp

Now returns the current virtual timestamp

type VirtualFragment added in v0.1.1

type VirtualFragment[Message any] struct {
	// Origin is the fragment origin in content coordinates
	Origin ScrollOffset
	// Node is the semantic subtree beginning at Origin
	Node Node[Message]
}

VirtualFragment is one lazily constructed visible or overscanned fragment

func NewVirtualFragment added in v0.1.1

func NewVirtualFragment[Message any](origin ScrollOffset, node Node[Message]) VirtualFragment[Message]

NewVirtualFragment returns a fragment beginning at origin

type VirtualViewport added in v0.1.1

type VirtualViewport struct {
	// Offset is the first visible cell in content coordinates
	Offset ScrollOffset
	// Size is the visible viewport size in cells
	Size Size
	// ContentSize is the complete resolved content extent in cells
	ContentSize Size
}

VirtualViewport is the visible content range requested by a virtual ScrollViewport

type WrapMode

type WrapMode uint8

WrapMode controls automatic paragraph line wrapping

const (
	// WrapWord prefers ASCII-space boundaries and hard-wraps oversized words
	WrapWord WrapMode = iota
	// WrapHard wraps at the last complete grapheme that fits
	WrapHard
	// WrapNone preserves only explicit CR, LF, and CRLF line boundaries
	WrapNone
)

Directories

Path Synopsis
examples
async-search command
command-palette command
counter command
Command counter is a minimal stateful Nagi TUI application
Command counter is a minimal stateful Nagi TUI application
dashboard command
file-browser command
filtered-list command
form-validation command
log-viewer command
virtual-scroll command
Command virtual-scroll renders a million-row virtual viewport
Command virtual-scroll renders a million-row virtual viewport
widget-gallery command
internal
conformance
Package conformance contains private helpers for shared fixture tests
Package conformance contains private helpers for shared fixture tests
ttyunix
Package ttyunix contains private Linux and macOS terminal-session integration for Nagi TUI.
Package ttyunix contains private Linux and macOS terminal-session integration for Nagi TUI.
Package surface provides cell surface composition and diff primitives for Nagi TUI.
Package surface provides cell surface composition and diff primitives for Nagi TUI.
Package tuitest provides virtual terminal and deterministic application test support for Nagi TUI.
Package tuitest provides virtual terminal and deterministic application test support for Nagi TUI.
Package widget provides standard widgets composed exclusively from the public Nagi TUI semantic Node, style, identity, layout, and event APIs
Package widget provides standard widgets composed exclusively from the public Nagi TUI semantic Node, style, identity, layout, and event APIs

Jump to

Keyboard shortcuts

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