moon_tui

moon_tui high-level facade.

moon_tui.ansi

fn enter_alternate() -> string#

Returns the escape sequence that enters the alternate screen.

fn leave_alternate() -> string#

Returns the escape sequence that leaves the alternate screen.

fn hide_cursor() -> string#

Returns the escape sequence that hides the cursor.

fn show_cursor() -> string#

Returns the escape sequence that shows the cursor.

fn enable_paste() -> string#

Returns the escape sequence that enables bracketed paste.

fn disable_paste() -> string#

Returns the escape sequence that disables bracketed paste.

fn enable_focus() -> string#

Returns the escape sequence that enables focus events.

fn disable_focus() -> string#

Returns the escape sequence that disables focus events.

fn enable_mouse() -> string#

Returns the escape sequence that enables mouse events.

fn disable_mouse() -> string#

Returns the escape sequence that disables mouse events.

fn clear_screen() -> string#

Returns the escape sequence that clears the screen.

fn save_cursor() -> string#

Returns the escape sequence that saves the cursor.

fn restore_cursor() -> string#

Returns the escape sequence that restores the cursor.

fn move_to(position: Position) -> string#

Returns the escape sequence that moves the cursor.

fn style_sequence(value: Style) -> string#

Encodes a complete style from reset. Runs share styles, so this is emitted once per changed run rather than once per cell.

  • value: Style to encode from a reset.
struct Encoded#

Encoded terminal output and its final cursor position.

bytes: string

The escape sequence and text to write.

changed_cells: int

How many cells the encoding redraws.

cursor_y: int

Row the cursor ends on, for the next relative move.

fn encode(previous: Buffer, next: Buffer, before_cursor: CursorRequest, after_cursor: CursorRequest, origin: Position, force: bool) -> Encoded#

Encodes one desired frame in the portable xterm subset. Application text is already sanitized into cells; this module is the package's sole escape producer.

  • previous: What the terminal is believed to be showing.
  • next: What it should show.
  • before_cursor: Cursor state of the presented frame.
  • after_cursor: Cursor state the new frame asks for.
  • origin: Absolute cell the grid is placed at.
  • force: True to emit every cell rather than only the changes.
fn encode_view(previous: Buffer, next: Buffer, before_cursor: CursorRequest, after_cursor: CursorRequest, origin: Position, force: bool, relative: bool, last_y: int) -> Encoded#

Inline viewports use relative row movement from the presenter's own last known position, avoiding cursor-position queries and absolute row guesses.

  • previous: What the terminal is believed to be showing.
  • next: What it should show.
  • before_cursor: Cursor state of the presented frame.
  • after_cursor: Cursor state the new frame asks for.
  • origin: Absolute cell the grid is placed at.
  • force: True to emit every cell rather than only the changes.
  • relative: True to move by relative rows instead of absolute ones.
  • last_y: Row the presenter last left the cursor on.

moon_tui.buffer

struct Buffer#

Dense row-major cell grid. The backing array is reused by reset/resize.

size: Size

Grid extent in cells.

cells: [Cell]

The grid itself, row-major.

epochs: [int]

Per-cell generation stamps, so a reset costs no clearing pass.

active: [int]

Indices touched since the last reset.

diff_epochs: [int]

Per-cell stamps for the diff pass, kept apart from epochs.

state: *BufferState

The generation counters shared by every value-copy of this handle.

struct BufferState#

Scalar generations shared by every value-copy of a Buffer handle.

generation: int

Bumped by each reset, retiring every epochs stamp below it.

diff_generation: int

The same trick for the diff pass.

fn new(size: Size) -> Buffer#

Creates a new value with the supplied configuration.

  • size: Grid extent to allocate.
impl Buffer#
fn bounds(self: Buffer) -> Rect#

Returns the buffer bounds.

fn index(self: Buffer, x: int, y: int) -> int#

Returns the linear buffer index for a coordinate.

  • x: Column, counting from zero.
  • y: Row, counting from zero.
fn get(self: Buffer, x: int, y: int) -> Cell#

Returns the cell at a coordinate, or a blank cell when out of bounds.

  • x: Column, counting from zero.
  • y: Row, counting from zero.
fn reset(self: Buffer)#

Resets the value to its initial state.

fn resize(self: Buffer, size: Size) -> Buffer#

Resizes the target while preserving valid content.

  • size: New extent; content inside both extents is preserved.
fn put(self: Buffer, x: int, y: int, grapheme: string, span: int, value: Style) -> bool#

Writes a grapheme head and continuation cells when it fits.

  • x: Column of the head cell.
  • y: Row of the head cell.
  • grapheme: Text to write.
  • span: Display columns it occupies; a span that overruns the row is refused.
  • value: Style the written cells carry.
fn write_ascii(self: Buffer, x: int, y: int, text: string, start: int, end: int, value: Style)#

Writes a clipped printable-ASCII slice into one row with one bounds calculation and one shared mutation setup.

  • x: Column the slice starts at.
  • y: Row to write into.
  • text: Printable-ASCII source text.
  • start: First byte index of the slice.
  • end: One past the last byte index of the slice.
  • value: Style the written cells carry.
fn fill(self: Buffer, area: Rect, grapheme: string, value: Style)#

Fills the target area.

  • area: Region to fill, clipped to the buffer.
  • grapheme: Text written into every cell.
  • value: Style the written cells carry.
fn patch_style(self: Buffer, area: Rect, delta: StylePatch)#

Applies a style patch to the target area.

  • area: Region to restyle, clipped to the buffer.
  • delta: The partial update laid over each cell.

moon_tui.cell

struct Cell#

One dense grid cell. Wide heads have span=2; their following cell has continuation=true and span=0.

grapheme: string

The text this cell draws; empty for a blank or a continuation.

style: Style

Foreground, background, and attributes for the cell.

span: int

Display columns the grapheme occupies: 1 normally, 2 for a wide head, 0 for a continuation.

continuation: bool

Whether this cell is the second half of a wide grapheme.

fn blank() -> Cell#

Creates a blank terminal cell.

fn with_style(value: Style) -> Cell#

Creates a blank cell with the supplied style.

  • value: Style the blank cell carries.
fn head(grapheme: string, value: Style, span: int) -> Cell#

Creates the head cell for a grapheme of the supplied display span.

  • grapheme: Text the cell draws.
  • value: Style the cell carries.
  • span: Display columns it occupies; 2 makes the next cell a continuation.
fn continuation(value: Style) -> Cell#

Creates a wide-cell continuation marker.

  • value: Style the continuation cell carries, matching its head.

moon_tui.clock

struct Clock#

Runtime clock seam. Production uses host monotonic time and real sleeping; tests inject a reference-backed fake with no wall-clock delay.

now_ms: fn() -> int

Reads monotonic milliseconds.

sleep_ms: fn(int) -> void

Waits the requested milliseconds.

struct FakeClock#

Deterministic clock handle for runtime tests.

clock: Clock

The seam to hand to code under test.

state: *FakeClockState

The time and sleep log the seam reads and writes.

struct FakeClockState#

Shared mutable time and sleep counters for a fake clock.

now: int

Current fake time in milliseconds.

sleeps: [int]

Every sleep the code under test asked for, in order.

fn system() -> Clock#

Returns the system implementation.

fn fake(start_ms: int) -> FakeClock#

Creates a deterministic fake implementation.

  • start_ms: Time the fake clock starts at.
impl FakeClock#
fn sleep_count(self: FakeClock) -> int#

Returns the number of fake-clock sleeps.

fn advance(self: FakeClock, ms: int)#

Advances the fake clock by the requested milliseconds.

  • ms: Milliseconds to move the fake clock forward.

moon_tui.decoder

struct Decoder#

Bounded incremental VT decoder. The constructor returns one managed stream; copied pointers share it while separate decoders remain independent.

pending: string

Bytes held back because they do not yet form a complete sequence.

paste: string

Bracketed-paste text accumulated so far.

in_paste: bool

Whether a bracketed paste is currently open.

escape_deadline: int

Monotonic time a lone Escape resolves at.

max_pending: int

Byte ceiling on pending before it is dropped.

max_paste: int

Byte ceiling on one paste.

escape_timeout_ms: int

How long a lone Escape waits for a continuation.

fn new(max_pending: int, max_paste: int, escape_timeout_ms: int) -> *Decoder#

Creates a new value with the supplied configuration.

  • max_pending: Byte ceiling on held-back input.
  • max_paste: Byte ceiling on one paste.
  • escape_timeout_ms: How long a lone Escape waits for a continuation.
use moon_tui.decoder
use moon_tui.event.{Event, KeyCode}

fn main() {
  let escape = std.strings.from_code(27)
  let input = decoder.new(max_pending: 4096, max_paste: 1024, escape_timeout_ms: 25)
  for event in input.push(escape + "[A", 0) {
    match event {
      Event.Key(key) => match key.code {
        KeyCode.Up => println("up"),
        _ => {},
      },
      _ => {},
    }
  }
  println(input.flush_deadlines(25))
}
impl Decoder#
fn push(self: *Decoder, chunk: string, now_ms: int) -> [Event]#

Pushes a byte chunk and returns all complete typed events. A trailing Escape remains pending until another byte arrives or its deadline fires.

  • chunk: Bytes just read from the terminal.
  • now_ms: Current monotonic time, which arms the Escape deadline.
fn flush_deadlines(self: *Decoder, now_ms: int) -> [Event]#

Resolves a pending bare Escape once its injected monotonic deadline is due. It never sleeps and is deterministic under a fake clock.

  • now_ms: Current monotonic time; a due Escape resolves to a key event.

moon_tui.diff

struct Run#

One adjacent row segment whose desired cells share a style.

y: int

Row the run sits on.

start: int

First column of the run.

end: int

One past the last column of the run.

style: Style

Style every cell in the run shares.

fn runs(previous: Buffer, next: Buffer, force: bool) -> [Run]#

Finds changed, style-coalesced row runs. Continuation cells remain in the run extent so a wide-to-narrow replacement clears both physical columns.

  • previous: What the terminal is believed to be showing.
  • next: What it should show.
  • force: True to emit every cell rather than only the changes.

moon_tui.driver

struct Capabilities#

Terminal feature flags supported by a backend.

vt: bool

Whether the terminal understands VT escape sequences at all.

true_color: bool

Whether 24-bit colour is supported.

mouse_sgr: bool

Whether SGR-encoded mouse reporting is supported.

bracketed_paste: bool

Whether bracketed paste is supported.

focus_reporting: bool

Whether focus in/out events are reported.

fn baseline_capabilities() -> Capabilities#

Returns the conservative terminal capabilities.

enum ReadResult#

Enumerates the supported ReadResult cases.

Data(string)

Bytes that were available.

WouldBlock

Nothing was available; try again later.

Eof

The input stream ended.

Failure(string)

The read failed, with the reason.

struct Driver#

Injected terminal backend. Closures capture reference-backed driver state; there is no package-global handle or saved-mode storage.

is_terminal: fn() -> bool

Whether the backend is attached to a real terminal.

open: fn() -> bool

Enters raw mode and claims the terminal; false on failure.

close: fn() -> void

Restores the modes open changed.

size: fn() -> Size

Reads the current terminal extent.

read: fn() -> ReadResult

Takes whatever input is available without blocking.

write_all: fn(string) -> bool

Writes one whole transaction; false means the write failed.

flush: fn() -> bool

Pushes buffered output out; false means the flush failed.

capabilities: Capabilities

What this backend reports it can do.

struct FakeState#

Shared mutable queues and counters for a fake terminal driver.

opened: bool

Whether open has been called and not yet closed.

close_calls: int

How many times close was called.

write_calls: int

How many times write_all was called.

flush_calls: int

How many times flush was called.

terminal: bool

What is_terminal answers.

fail_open: bool

Whether the next open should fail.

fail_flush: bool

Whether the next flush should fail.

fail_after_bytes: int

Byte budget after which the next write fails; negative disables it.

size: Size

What size answers.

reads: [ReadResult]

Queued read results, taken in order.

writes: [string]

Everything written so far, in order.

struct FakeDriver#

Deterministic in-memory terminal backend for tests.

driver: Driver

The seam to hand to code under test.

state: *FakeState

The queues and counters the seam reads and writes.

fn fake(size: Size) -> FakeDriver#

Creates a deterministic fake implementation.

  • size: Extent the fake terminal reports.
use moon_tui.driver
use moon_tui.geometry
use moon_tui.style
use moon_tui.terminal

fn main() {
  let backend = driver.fake(geometry.size(20, 4))
  let term = terminal.open_with(terminal.options(), backend.driver).unwrap()
  let frame = term.begin_frame()
  frame.root().write_text(0, 0, "moon", style.plain())
  term.present()
  println(backend.output())
  backend.push_read(driver.ReadResult.Data("q"))
  println(term.poll(0).unwrap())
  term.close()
  println(backend.close_count())
}
impl FakeDriver#
fn is_open(self: FakeDriver) -> bool#

Reports whether the fake terminal backend remains open.

fn close_count(self: FakeDriver) -> int#

Returns how many times the fake driver was closed.

fn set_terminal(self: FakeDriver, enabled: bool)#

Records whether terminal mode is enabled.

  • enabled: What is_terminal should answer.
fn fail_next_write_after(self: FakeDriver, bytes: int)#

Makes the fake driver fail its next write after a byte limit.

  • bytes: Byte budget the next write fails past.
fn push_read(self: FakeDriver, result: ReadResult)#

Queues a read result in the fake driver.

  • result: Read result to queue behind the ones already there.
fn output(self: FakeDriver) -> string#

Returns output captured by the fake driver.

moon_tui.driver_posix

fn system_driver() -> Driver#

Returns the platform terminal driver.

moon_tui.driver_win

fn system_driver() -> Driver#

Returns the platform terminal driver.

moon_tui.event

const SHIFT#

Modifier mask bit for Shift.

const ALT#

Modifier mask bit for Alt.

const CTRL#

Modifier mask bit for Control.

const SUPER#

Modifier mask bit for Super/Command.

enum KeyCode#

Enumerates the supported KeyCode cases.

Char(string)

A printable grapheme the terminal delivered.

Enter

The return key.

Escape

The escape key.

Backspace

The backspace key.

Tab

The tab key.

Up

The up arrow.

Down

The down arrow.

Left

The left arrow.

Right

The right arrow.

Home

The home key.

End

The end key.

PageUp

The page-up key.

PageDown

The page-down key.

Insert

The insert key.

Delete

The forward-delete key.

Function(int)

A function key, by its number.

struct Key#

Decoded key code and modifier mask.

code: KeyCode

Which key was pressed.

modifiers: int

Modifier bits held at the time, OR-ed together.

enum MouseKind#

Enumerates the supported MouseKind cases.

Down

A button was pressed.

Up

A button was released.

Move

The pointer moved.

ScrollUp

The wheel turned up.

ScrollDown

The wheel turned down.

struct Mouse#

Decoded mouse action, button, modifiers, and cell position.

kind: MouseKind

What the mouse did.

button: int

Button index for a press or release; 0 otherwise.

x: int

Column of the pointer, counting from zero.

y: int

Row of the pointer, counting from zero.

modifiers: int

Modifier bits held at the time, OR-ed together.

enum Event#

Enumerates the supported Event cases.

Key(Key)

A key press, with its modifiers.

Mouse(Mouse)

A mouse action, with its position.

Paste(string)

Bracketed-paste text, delivered whole.

Focus(bool)

The terminal window gained (true) or lost (false) focus.

Resize(Size)

The terminal was resized to this extent.

Unknown(string)

A sequence the decoder did not recognise, kept verbatim.

fn key(code: KeyCode, modifiers: int) -> Event#

Creates a keyboard event.

  • code: Which key was pressed.
  • modifiers: Modifier bits held at the time.

moon_tui.focus

struct FocusRing#

Optional app-owned focus order. Rendering reads the current id but never mutates it; applications call next/previous/focus from their update step.

ids: [string]

The focus order, as the application declared it.

index: int

Position of the focused id within ids.

fn new(ids: [string]) -> *FocusRing#

Creates a new value with the supplied configuration.

  • ids: Widget identifiers in focus order.
use moon_tui.focus

fn main() {
  let ring = focus.new(["search", "results", "footer"])
  println(ring.current())
  println(ring.next())
  println(ring.previous())
  println(ring.focus("footer"))
  println(ring.contains("search"))
}
impl FocusRing#
fn current(self: *FocusRing) -> string#

Returns the currently focused identifier.

fn contains(self: *FocusRing, id: string) -> bool#

Reports whether the requested value is present.

  • id: Identifier to look for.
fn focus(self: *FocusRing, id: string) -> bool#

Moves focus to the requested identifier when present.

  • id: Identifier to move focus to; an unknown one leaves focus alone.
fn next(self: *FocusRing) -> string#

Moves to and returns the next item.

fn previous(self: *FocusRing) -> string#

Moves to and returns the previous item.

moon_tui.frame

enum CursorShape#

Enumerates the supported CursorShape cases.

Block

A full-cell block.

Underline

A line under the cell.

Bar

A vertical bar at the left of the cell.

struct CursorRequest#

Requested cursor visibility, position, and shape for a frame.

visible: bool

Whether the cursor is shown this frame.

position: Position

Where the cursor sits, in screen cells.

shape: CursorShape

How the terminal draws it.

struct Frame#

A frame is a complete desired grid plus declarative cursor state.

buffer: Buffer

The dense grid this frame draws into.

area: Rect

The whole drawable region of the frame.

cursor: *CursorRequest

Cursor request for the frame, owned by the screen.

width_policy: WidthPolicy

How grapheme display widths are measured.

struct Window#

A translating, clipped view over the frame's shared dense buffer.

buffer: Buffer

The frame's grid, shared with every other window over it.

origin: Position

Where this window's (0, 0) sits in the frame.

clip: Rect

Region of the frame writes are confined to.

area: Rect

The window's own extent, in its local coordinates.

cursor: *CursorRequest

Cursor request for the frame, owned by the screen.

width_policy: WidthPolicy

How grapheme display widths are measured.

fn new(buffer: Buffer, policy: WidthPolicy) -> Frame#

Creates a new value with the supplied configuration.

  • buffer: The dense grid to draw into.
  • policy: How grapheme display widths are measured.
fn with_cursor(buffer: Buffer, cursor: *CursorRequest, policy: WidthPolicy) -> Frame#

Constructs a Frame over cursor storage owned by Screen.

  • buffer: The dense grid to draw into.
  • cursor: Cursor storage owned by the screen.
  • policy: How grapheme display widths are measured.
impl Frame#
fn window(self: Frame, area: Rect) -> Window#

Returns a window clipped to the requested frame area.

  • area: Region of the frame the window covers, clipped to it.
fn root(self: Frame) -> Window#

Returns a window spanning the complete frame.

fn set_cursor(self: Frame, visible: bool, position: Position, shape: CursorShape)#

Requests cursor visibility, position, and shape for this frame.

  • visible: Whether the cursor is shown.
  • position: Where it sits.
  • shape: How the terminal draws it.
impl Window#
fn window(self: Window, area: Rect) -> Window#

Returns a child window clipped to the requested local area.

  • area: Region in this window's coordinates the child covers.
fn fill(self: Window, grapheme: string, value: Style)#

Fills the target area.

  • grapheme: Text written into every cell.
  • value: Style the written cells carry.
fn patch_style(self: Window, area: Rect, delta: StylePatch)#

Applies a style patch to the target area.

  • area: Region to restyle, in local coordinates.
  • delta: The partial update laid over each cell.
fn put(self: Window, x: int, y: int, grapheme: string, span: int, value: Style) -> bool#

Writes the supplied value.

  • x: Local column of the head cell.
  • y: Local row of the head cell.
  • grapheme: Text to write.
  • span: Display columns it occupies.
  • value: Style the written cells carry.
fn write_text(self: Window, x: int, y: int, text: string, value: Style) -> Position#

Writes sanitized grapheme clusters. Newline and tab are interpreted by the grid; all other C0/C1 controls have already become U+FFFD.

  • x: Local column to start at.
  • y: Local row to write into.
  • text: Text to segment and write.
  • value: Style the written cells carry.
fn write_clusters(self: Window, x: int, y: int, clusters: [Cluster], count: int, value: Style) -> Position#

Writes a prefix of an already-segmented cluster array. Widgets use this to measure, align, and paint Unicode text without segmenting it twice.

  • x: Local column to start at.
  • y: Local row to write into.
  • clusters: Already-segmented clusters.
  • count: How many of them to write.
  • value: Style the written cells carry.
fn set_cursor(self: Window, visible: bool, position: Position, shape: CursorShape)#

Requests a cursor at a position relative to this window.

  • visible: Whether the cursor is shown.
  • position: Where it sits, in this window's coordinates.
  • shape: How the terminal draws it.

moon_tui.geometry

struct Position#

A zero-based terminal cell position.

x: int

Column, counting from zero at the left edge.

y: int

Row, counting from zero at the top edge.

struct Size#

A terminal cell extent. Constructors clamp negative dimensions to zero.

width: int

Columns spanned; never negative.

height: int

Rows spanned; never negative.

struct Rect#

A half-open terminal-cell rectangle.

x: int

Column of the left edge.

y: int

Row of the top edge.

width: int

Columns spanned; the right edge is exclusive.

height: int

Rows spanned; the bottom edge is exclusive.

enum Direction#

Enumerates the supported Direction cases.

Horizontal

Lay out along the row, left to right.

Vertical

Lay out down the column, top to bottom.

fn position(x: int, y: int) -> Position#

Creates a terminal-cell position.

  • x: Column, counting from zero.
  • y: Row, counting from zero.
fn size(width: int, height: int) -> Size#

Creates a terminal-cell extent with non-negative dimensions.

  • width: Columns spanned; negative is clamped to zero.
  • height: Rows spanned; negative is clamped to zero.
fn rect(x: int, y: int, width: int, height: int) -> Rect#

Creates a clamped terminal-cell rectangle.

  • x: Column of the left edge.
  • y: Row of the top edge.
  • width: Columns spanned; negative is clamped to zero.
  • height: Rows spanned; negative is clamped to zero.
use moon_tui.geometry
use moon_tui.layout
use moon_tui.layout.{Constraint}

fn main() {
  let screen = geometry.rect(0, 0, 80, 24)
  let rows = layout.split(
    screen,
    geometry.Direction.Vertical,
    [Constraint.Length(3), Constraint.Weight(1), Constraint.Length(1)],
  )
  println(rows.map(|row| row.height))
  println(screen.inset(1).contains(geometry.position(2, 2)))
  println(screen.intersect(geometry.rect(70, 20, 20, 10)))
  println(screen.translate(1, 1).right())
}
impl Rect#
fn right(self: Rect) -> int#

Returns the rectangle's exclusive right edge.

fn bottom(self: Rect) -> int#

Returns the rectangle's exclusive bottom edge.

fn is_empty(self: Rect) -> bool#

Reports whether empty.

fn contains(self: Rect, p: Position) -> bool#

Reports whether the half-open rectangle contains a position.

  • p: Position to test against the half-open bounds.
fn intersect(self: Rect, other: Rect) -> Rect#

Returns the overlap of two rectangles.

  • other: Rectangle to overlap with; no overlap yields an empty rectangle.
fn inset(self: Rect, margin: int) -> Rect#

Returns the rectangle inset by a non-negative margin.

  • margin: Cells to pull in on every side; negative is treated as zero.
fn translate(self: Rect, dx: int, dy: int) -> Rect#

Returns the rectangle translated by the supplied offset.

  • dx: Columns to shift by.
  • dy: Rows to shift by.

moon_tui.layout

enum Constraint#

Enumerates the supported Constraint cases.

Length(int)

Exactly this many cells, assigned before anything else.

Percent(int)

This percentage of the original usable span.

Weight(int)

This share of whatever remains after lengths and percentages.

fn split(area: Rect, direction: Direction, constraints: [Constraint], spacing: int, margin: int) -> [Rect]#

Deterministic one-axis integer layout. Fixed lengths are assigned first, percentages use the original usable span, and weights divide the remainder.

  • area: Region to divide.
  • direction: Axis to divide along.
  • constraints: One constraint per resulting region, in order.
  • spacing: Cells left between adjacent regions.
  • margin: Cells trimmed from every side before dividing.

moon_tui.runtime

enum RuntimeEvent<Msg>#

Enumerates the supported RuntimeEvent cases.

Terminal(Event)

Input from the terminal.

Message(Msg)

An application message, from an effect or a timer.

Refresh

A repaint request with no new information.

enum Command<Msg>#

Enumerates the supported Command cases.

Effect(fn() -> Future<Msg>)

Run this asynchronously and deliver its message when it settles.

After(int, Msg)

Deliver this message once the delay in milliseconds has passed.

struct Update<Model, Msg>#

Model transition, redraw decision, and follow-up commands.

model: Model

The model the next cycle sees.

commands: [Command<Msg>]

Follow-up work the runtime should start.

redraw: bool

Whether the view should be repainted this cycle.

quit: bool

Whether the loop should stop after this cycle.

struct Program<Model, Msg>#

Application model, update callback, and view callback.

use moon_tui.frame.{Frame}
use moon_tui.runtime
use moon_tui.runtime.{Program, RuntimeEvent, Update}
use moon_tui.style
use moon_tui.terminal
use moon_tui.tui

enum Msg { Tick, Quit }
struct Model { count: int }

fn init() -> Update<Model, Msg> {
  runtime.with_commands(
    runtime.redraw(Model { count: 0 }),
    [runtime.after(1000, Msg.Tick)],
  )
}

fn update(model: Model, event: RuntimeEvent<Msg>) -> Update<Model, Msg> {
  match event {
    RuntimeEvent.Message(Msg.Tick) => runtime.with_commands(
      runtime.redraw(Model { count: model.count + 1 }),
      [runtime.after(1000, Msg.Tick)],
    ),
    RuntimeEvent.Message(Msg.Quit) => runtime.quit(model),
    _ => runtime.unchanged(model),
  }
}

fn view(model: Model, frame: Frame) {
  frame.root().write_text(0, 0, "ticks: ${model.count}", style.plain())
}

async fn main() {
  let program = Program { init: init, update: update, view: view }
  let _final = (await tui.run(program, runtime.options(), terminal.options())).unwrap()
}
init: fn() -> Update<Model, Msg>

Builds the first model and its opening commands.

update: fn(Model, RuntimeEvent<Msg>) -> Update<Model, Msg>

Folds one event into the model.

view: fn(Model, Frame) -> void

Paints the model into the frame.

struct RuntimeOptions#

Terminal-runtime timing and input configuration.

max_fps: int

Upper bound on repaints per second.

max_events_per_cycle: int

How many events one cycle may fold in before repainting.

completion_queue_capacity: int

How many effect results may queue up.

idle_sleep_ms: int

How long to sleep when there is nothing to do.

fn options() -> RuntimeOptions#

Returns the default options.

fn redraw<Model, Msg>(model: Model) -> Update<Model, Msg>#

Returns an update that requests a redraw.

  • model: The model the next cycle sees.
fn unchanged<Model, Msg>(model: Model) -> Update<Model, Msg>#

Returns an update that leaves the model without a redraw.

  • model: The model the next cycle sees.
fn quit<Model, Msg>(model: Model) -> Update<Model, Msg>#

Returns an update that requests runtime shutdown.

  • model: The model returned to the caller of the loop.
fn with_commands<Model, Msg>(update: Update<Model, Msg>, commands: [Command<Msg>]) -> Update<Model, Msg>#

Returns a model update with follow-up commands.

  • update: The transition to attach work to.
  • commands: Follow-up work the runtime should start.
fn effect<Msg>(run: fn() -> Future<Msg>) -> Command<Msg>#

Creates a command backed by an asynchronous effect.

  • run: Called once; the message it resolves to is delivered to update.
fn after<Msg>(delay_ms: int, message: Msg) -> Command<Msg>#

Creates a command that emits a message after a delay.

  • delay_ms: How long to wait before delivering.
  • message: What to deliver.
enum EffectOutcome<Msg>#

Enumerates the supported EffectOutcome cases.

Success(int, Msg)

The effect with this id produced this message.

Failure(int, string)

The effect with this id failed, with the reason.

struct EffectTask#

Runtime bookkeeping for one asynchronous effect.

id: int

Identifier the completion is reported under.

future: Future<void>

The running effect.

struct Timer<Msg>#

Delayed message scheduled for a monotonic deadline.

deadline: int

Monotonic time the message is due at.

sequence: int

Tie-breaker so timers due at the same instant keep their order.

message: Msg

What is delivered when it fires.

async fn run_with<Model, Msg>(program: Program<Model, Msg>, terminal: Terminal, clock: Clock, config: RuntimeOptions) -> Result<Model, Error>async#

Runs the serial model/update/view loop over an already-open Terminal. The same low-level begin_frame/present path is used by custom-loop callers.

  • program: The init, update, and view callbacks to drive.
  • terminal: An already-open session to draw on.
  • clock: Time source, so tests can drive the loop without waiting.
  • config: Frame rate, event batching, and idle behaviour.

moon_tui.screen

struct PresentStats#

Byte and cell counts from one terminal presentation.

success: bool

Whether both the write and the flush succeeded.

bytes: int

How many bytes the transaction wrote.

changed_cells: int

How many cells the diff decided to redraw.

full_refresh: bool

Whether every cell was redrawn rather than just the changes.

struct Screen#

Reusable previous/next grids. One managed state object lets a Terminal and its copied Frames observe the same buffers without singleton arrays.

state: *ScreenState

The buffers and cursor tracking shared by every copy of this handle.

width_policy: WidthPolicy

How grapheme display widths are measured.

struct ScreenState#

Shared mutable backing state for a terminal screen.

previous: Buffer

What the terminal is believed to be showing.

next: Buffer

What the frame under construction wants it to show.

previous_cursor: CursorRequest

Cursor placement of the last presented frame.

next_cursor: *CursorRequest

Cursor placement the frame under construction asked for.

force_full: bool

Whether the next presentation redraws every cell.

origin: Position

Absolute cell the drawing is placed at.

relative: bool

Whether placement is inline rather than full-screen.

cursor_y: int

Row the terminal cursor is believed to sit on.

fn new(size: Size, policy: WidthPolicy) -> Screen#

Creates a screen with blank current and previous buffers.

  • size: Grid extent for both buffers.
  • policy: How grapheme display widths are measured.
impl Screen#
fn size(self: Screen) -> Size#

Returns the current size.

fn cursor_row(self: Screen) -> int#

Returns the current terminal cursor row.

fn reset_cursor_row(self: Screen)#

Resets tracked cursor placement.

fn previous_buffer(self: Screen) -> Buffer#

Returns the last presented buffer.

fn set_origin(self: Screen, origin: Position)#

Sets the absolute origin used for terminal cursor placement.

  • origin: Absolute cell the drawing is placed at.
fn set_relative(self: Screen, enabled: bool)#

Selects relative inline presentation instead of full-screen placement.

  • enabled: True for inline placement, false for full-screen.
fn begin_frame(self: Screen) -> Frame#

Starts drawing a new frame.

fn refresh(self: Screen)#

Forces the next presentation to redraw all cells.

fn resize(self: Screen, size: Size)#

Resizes the target while preserving valid content.

  • size: New extent; content inside both extents is preserved.
fn present(self: Screen, write_all: fn(string) -> bool, flush: fn() -> bool) -> PresentStats#

Builds and writes one transaction. The logical previous frame advances only after both the single write_all call and flush report success.

  • write_all: Called once with the whole transaction; false means the write failed.
  • flush: Called after the write; false means the flush failed.

moon_tui.style

enum Color#

Portable terminal colors. Indexed uses the xterm 0..255 palette.

Default

The terminal's own foreground or background.

Indexed(int)

A slot in the xterm 0..255 palette.

Rgb(int, int, int)

A direct color, as red, green, and blue in 0..255.

const BOLD#

Style attribute mask bit for bold text.

const DIM#

Style attribute mask bit for dim text.

const ITALIC#

Style attribute mask bit for italic text.

const UNDERLINE#

Style attribute mask bit for underlined text.

const REVERSE#

Style attribute mask bit for reversed colors.

const HIDDEN#

Style attribute mask bit for hidden text.

const STRIKE#

Style attribute mask bit for struck-through text.

struct Style#

A complete cell style.

fg: Color

Foreground color.

bg: Color

Background color.

attrs: int

Attribute bits such as bold or underline, OR-ed together.

struct StylePatch#

A composable style delta. Missing colors leave the destination unchanged.

fg: Optional<Color>

Foreground to set; absence leaves the destination alone.

bg: Optional<Color>

Background to set; absence leaves the destination alone.

add_attrs: int

Attribute bits to turn on.

remove_attrs: int

Attribute bits to turn off; applied after add_attrs.

fn plain() -> Style#

Returns the default unstyled value.

fn styled(fg: Color, bg: Color, attrs: int) -> Style#

Creates a style from foreground, background, and attributes.

  • fg: Foreground color.
  • bg: Background color.
  • attrs: Attribute bits, OR-ed together.
use moon_tui.style
use moon_tui.style.Color

fn main() {
  let base = style.styled(Color.Indexed(14), Color.Default, style.BOLD)
  let changed = base.apply(
    style.patch(none, some(Color.Rgb(20, 30, 40)), style.UNDERLINE, style.BOLD),
  )
  println(changed)
  println(style.plain())
}
fn patch(fg: Optional<Color>, bg: Optional<Color>, add_attrs: int, remove_attrs: int) -> StylePatch#

Creates a partial style update.

  • fg: Foreground to set; absence leaves it alone.
  • bg: Background to set; absence leaves it alone.
  • add_attrs: Attribute bits to turn on.
  • remove_attrs: Attribute bits to turn off.
impl Style#
fn apply(self: Style, delta: StylePatch) -> Style#

Applies the patch and returns the resulting value.

  • delta: The partial update to lay over this style.

moon_tui.terminal

struct TerminalOptions#

Terminal backend, viewport, width, and polling configuration.

viewport: Viewport

Whether to take the alternate screen or reserve inline rows.

mouse: bool

Whether to enable mouse reporting.

paste: bool

Whether to enable bracketed paste.

focus: bool

Whether to enable focus reporting.

width_policy: WidthPolicy

How grapheme display widths are measured.

fn options() -> TerminalOptions#

Returns the default options.

struct TerminalState#

Shared mutable state for an open terminal session.

closed: bool

Whether cleanup has already run.

inline: bool

Whether the session draws inline rather than on the alternate screen.

clear_inline: bool

Whether the reserved inline rows are cleared on close.

last_size: Size

Extent last observed, so a resize can be detected.

struct Terminal#

Open terminal session with drawing and input operations.

driver: Driver

The backend the session reads and writes through.

screen: Screen

The previous/next grids the session presents from.

decoder: *Decoder

The incremental VT decoder input is fed to.

options: TerminalOptions

The configuration the session was opened with.

state: *TerminalState

Session bookkeeping shared by every copy of this handle.

fn open(config: TerminalOptions) -> Result<Terminal, Error>#

Opens a terminal using the default platform backend.

  • config: Viewport, input modes, and width policy for the session.
use moon_tui.event.{Event, KeyCode}
use moon_tui.style
use moon_tui.terminal

fn main() {
  let term = terminal.open(terminal.options()).unwrap()
  defer term.close()
  let frame = term.begin_frame()
  frame.root().write_text(0, 0, "press Escape", style.plain())
  println(term.present().success)
  for event in term.poll(std.time.monotonic_ms()).unwrap() {
    match event {
      Event.Key(key) => match key.code { KeyCode.Escape => return, _ => {} },
      _ => {},
    }
  }
  term.refresh()
}
fn open_with(options: TerminalOptions, backend: Driver) -> Result<Terminal, Error>#

Opens a terminal with an explicit backend.

  • options: Viewport, input modes, and width policy for the session.
  • backend: Driver to read and write through, in place of the platform one.
impl Terminal#
fn begin_frame(self: Terminal) -> Frame#

Starts drawing a new frame.

fn present(self: Terminal) -> PresentStats#

Writes the pending terminal frame and returns statistics.

fn refresh(self: Terminal)#

Forces the next presentation to redraw all cells.

fn poll(self: Terminal, now_ms: int) -> Result<[Event], Error>#

Polls the terminal for decoded input events.

  • now_ms: Current monotonic time, which resolves a pending bare Escape.
fn close(self: Terminal)#

Idempotent reverse-order cleanup. Mode restoration is attempted even if output cleanup fails, because the platform driver owns raw-mode state.

moon_tui.tui

async fn run<Model, Msg>(program: Program<Model, Msg>, runtime_options: runtime.RuntimeOptions, terminal_options: terminal.TerminalOptions) -> Result<Model, Error>async#

Runs the configured application loop.

  • program: The init, update, and view callbacks to drive.
  • runtime_options: Frame rate, event batching, and idle behaviour.
  • terminal_options: Viewport, input modes, and width policy.
async fn run_with<Model, Msg>(program: Program<Model, Msg>, terminal: Terminal, injected_clock: clock.Clock, runtime_options: runtime.RuntimeOptions) -> Result<Model, Error>async#

Runs the application loop with explicit dependencies.

  • program: The init, update, and view callbacks to drive.
  • terminal: An already-open session to draw on.
  • injected_clock: Time source, so tests can drive the loop without waiting.
  • runtime_options: Frame rate, event batching, and idle behaviour.

moon_tui.unicode_data

const UNICODE_VERSION#

Unicode data version used by the generated width tables.

const UNICODE_SOURCE_SHA256#

SHA-256 of the source Unicode data used to generate these tables.

const EXTEND_RANGES: [int]#

Sorted Unicode code-point ranges for extend.

const SPACING_MARK_RANGES: [int]#

Sorted Unicode code-point ranges for spacing mark.

const PREPEND_RANGES: [int]#

Sorted Unicode code-point ranges for prepend.

const WIDE_RANGES: [int]#

Sorted Unicode code-point ranges for wide.

const AMBIGUOUS_RANGES: [int]#

Sorted Unicode code-point ranges for ambiguous.

const EMOJI_PRESENTATION_RANGES: [int]#

Sorted Unicode code-point ranges for emoji presentation.

const EXTENDED_PICTOGRAPHIC_RANGES: [int]#

Sorted Unicode code-point ranges for extended pictographic.

moon_tui.viewport

enum Viewport#

Enumerates the supported Viewport cases.

Alternate

Take the whole alternate screen.

Inline(int, bool)

Reserve this many rows on the primary screen, clearing them on exit when the flag is set.

struct Geometry#

Screen origin and drawable size selected for a viewport.

size: Size

Drawable extent selected for the viewport.

inline: bool

Whether drawing happens inline on the primary screen.

clear_on_exit: bool

Whether the reserved rows are cleared when the viewport ends.

fn geometry_for(mode: Viewport, terminal_size: Size) -> Geometry#

Computes viewport geometry for the terminal size.

  • mode: Which viewport to compute for.
  • terminal_size: Extent the terminal reported.
fn reserve_inline(height: int) -> string#

Reserves fixed-height primary-screen rows without a cursor-position query.

  • height: Rows to reserve on the primary screen.
fn clear_inline(height: int) -> string#

Returns escape sequences that clear an inline viewport.

  • height: Rows the inline viewport occupies.
fn return_to_anchor(current_y: int) -> string#

Returns the escape sequence that moves to the inline anchor.

  • current_y: Row the cursor currently sits on.
fn finish_inline(height: int, clear: bool, current_y: int) -> string#

Finishes inline rendering and optionally clears its rows.

  • height: Rows the inline viewport occupies.
  • clear: Whether to clear those rows on the way out.
  • current_y: Row the cursor currently sits on.

moon_tui.widget

enum Alignment#

Shared alignment and text helpers used by the pure widget modules.

Left

Flush with the left edge.

Center

Centred, with an odd remainder on the right.

Right

Flush with the right edge.

fn clamp(value: int, low: int, high: int) -> int#

Clamps a value to the inclusive bounds.

  • value: Value to constrain.
  • low: Lowest value allowed.
  • high: Highest value allowed.
fn repeat(text: string, count: int) -> string#

Repeats the value the requested number of times.

  • text: Text to repeat.
  • count: How many copies to emit.
fn fit_text(text: string, max_width: int, policy: WidthPolicy) -> string#

Clips on grapheme boundaries and never emits a partial wide cluster.

  • text: Text to clip.
  • max_width: Columns the result must fit in.
  • policy: How grapheme display widths are measured.
fn wrap_text(text: string, max_width: int, policy: WidthPolicy) -> [string]#

Deterministic grapheme wrapping. Newlines are honored; long logical lines wrap at cell boundaries without splitting a cluster.

  • text: Text to wrap; newlines are honoured.
  • max_width: Columns each line must fit in.
  • policy: How grapheme display widths are measured.
fn write_line(window: Window, y: int, text: string, value: Style, alignment: Alignment)#

Writes a styled, width-aware line into a window.

  • window: Window to draw into.
  • y: Local row to write.
  • text: Text to draw, clipped to the window width.
  • value: Style the written cells carry.
  • alignment: How the text sits within the row.

moon_tui.widget_block

const BORDER_TOP#

Border mask bit for the top edge.

const BORDER_RIGHT#

Border mask bit for the right edge.

const BORDER_BOTTOM#

Border mask bit for the bottom edge.

const BORDER_LEFT#

Border mask bit for the left edge.

const BORDER_ALL#

Border mask containing every edge.

struct Block#

Border, title, and style configuration for a block widget.

title: string

Text drawn on the top border; empty draws none.

borders: int

Which edges are drawn, as OR-ed edge bits.

style: Style

Style the interior is filled with.

border_style: Style

Style the border glyphs carry.

title_style: Style

Style the title carries.

fn block(title: string) -> Block#

Creates a bordered block widget.

  • title: Text drawn on the top border.
use moon_tui.buffer
use moon_tui.frame
use moon_tui.geometry
use moon_tui.geometry.{Direction}
use moon_tui.layout
use moon_tui.layout.{Constraint}
use moon_tui.widget.{Alignment}
use moon_tui.widget_block
use moon_tui.widget_gauge
use moon_tui.widget_list
use moon_tui.widget_paragraph
use moon_tui.widget_separator
use moon_tui.widget_table
use moon_tui.widget_tabs

fn main() {
  let grid = buffer.new(geometry.size(60, 16))
  let root = frame.new(grid).root()
  let inner = widget_block.render(
    widget_block.block("Build"),
    root.window(geometry.rect(0, 0, 60, 16)),
  )
  let rows = layout.split(
    inner,
    Direction.Vertical,
    [Constraint.Length(2), Constraint.Weight(1), Constraint.Length(1)],
  )
  widget_paragraph.render(
    widget_paragraph.paragraph("moon build dashboard"),
    root.window(rows[0]),
  )
  let columns = [
    widget_table.column("Stage", Constraint.Weight(2)),
    widget_table.column("State", Constraint.Weight(1), Alignment.Right),
  ]
  widget_table.render(
    widget_table.table(columns, [["compile", "done"], ["test", "green"]]),
    widget_table.state(),
    root.window(rows[1]),
  )
  widget_gauge.render(widget_gauge.gauge(0.75, "75%"), root.window(rows[2]))
  let list_state = widget_list.state()
  list_state.select(1, 2)
  list_state.scroll_into_view(2, 2)
  println(widget_list.list([widget_list.item("one"), widget_list.item("two")]))
  println(widget_tabs.tabs(["Build", "Logs"], 0))
  println(widget_separator.separator(Direction.Horizontal))
}
fn render(value: Block, window: Window) -> Rect#

Paints the block and returns its local content rectangle.

  • value: The block to paint.
  • window: Window to draw into.

moon_tui.widget_gauge

struct Gauge#

Ratio, label, and style configuration for a gauge widget.

ratio: float

How full the bar is, from 0.0 to 1.0.

label: string

Text drawn over the bar; empty draws none.

filled_style: Style

Style the filled portion carries.

empty_style: Style

Style the empty portion carries.

filled: string

Glyph the filled portion is drawn with.

empty: string

Glyph the empty portion is drawn with.

fn gauge(ratio: float, label: string) -> Gauge#

Creates a gauge widget.

  • ratio: How full the bar is, from 0.0 to 1.0.
  • label: Text drawn over the bar.
fn render(value: Gauge, window: Window)#

Renders the value into its target.

  • value: The gauge to paint.
  • window: Window to draw into.

moon_tui.widget_list

struct ListItem#

Text and style for one list row.

text: string

The row text.

style: Style

Style the row carries when it is not selected.

struct ListState#

Mutable selection and scroll state for a list.

selected: int

Index of the selected item.

offset: int

Index of the first visible item.

struct List#

Items and presentation configuration for a list widget.

items: [ListItem]

Rows to draw, in order.

style: Style

Style unselected rows carry.

selected_style: Style

Style the selected row carries.

marker: string

Text drawn ahead of the selected row.

fn item(text: string, value: Style) -> ListItem#

Creates a list item.

  • text: The row text.
  • value: Style the row carries.
fn state(selected: int, offset: int) -> *ListState#

Creates mutable widget state.

  • selected: Index of the selected item.
  • offset: Index of the first visible item.
fn list(items: [ListItem]) -> List#

Creates a list widget.

  • items: Rows to draw, in order.
impl ListState#
fn selected_index(self: *ListState) -> int#

Returns the selected item index.

fn scroll_offset(self: *ListState) -> int#

Returns the first visible item index.

fn select(self: *ListState, index: int, count: int)#

Moves the selection to a clamped index.

  • index: Index to move to, clamped into range.
  • count: How many items the list holds.
fn scroll_into_view(self: *ListState, height: int, count: int)#

Adjusts the offset so the selection is visible.

  • height: How many rows are visible.
  • count: How many items the list holds.
fn render(value: List, state: *ListState, window: Window)#

Rendering only observes ListState; selection/scroll changes belong in update.

  • value: The list to paint.
  • state: Selection and scroll position, read but not changed.
  • window: Window to draw into.

moon_tui.widget_paragraph

struct Paragraph#

Text, wrapping, alignment, and style for a paragraph widget.

text: string

The text to draw; newlines are honoured.

style: Style

Style the text carries.

alignment: Alignment

How each line sits within the window.

wrap: bool

Whether long lines wrap instead of being clipped.

fn paragraph(text: string) -> Paragraph#

Creates a paragraph widget.

  • text: The text to draw.
fn render(value: Paragraph, window: Window)#

Renders the value into its target.

  • value: The paragraph to paint.
  • window: Window to draw into.

moon_tui.widget_separator

struct Separator#

Direction and style for a separator widget.

direction: Direction

Whether the rule runs across or down.

style: Style

Style the rule carries.

glyph: string

Text the rule is drawn with.

fn separator(direction: Direction) -> Separator#

Creates a separator widget.

  • direction: Whether the rule runs across or down.
fn render(value: Separator, window: Window)#

Renders the value into its target.

  • value: The separator to paint.
  • window: Window to draw into.

moon_tui.widget_table

struct Column#

Columns are the table's schema: headers, layout constraints, and alignment drive rendering without hardcoded field positions.

header: string

Text drawn in the header row.

constraint: Constraint

How much width the column takes.

alignment: Alignment

How cells sit within the column.

struct TableState#

Mutable selection and scroll state for a table.

selected: int

Index of the selected row.

offset: int

Index of the first visible row.

struct Table#

Column, row, and style configuration for a table widget.

columns: [Column]

The schema: header, width, and alignment per column.

rows: [[string]]

Row data, each a list of cell texts.

style: Style

Style unselected rows carry.

header_style: Style

Style the header row carries.

selected_style: Style

Style the selected row carries.

spacing: int

Cells left between adjacent columns.

show_header: bool

Whether the header row is drawn at all.

fn column(header: string, constraint: Constraint, alignment: Alignment) -> Column#

Creates a table column definition.

  • header: Text drawn in the header row.
  • constraint: How much width the column takes.
  • alignment: How cells sit within the column.
fn state(selected: int, offset: int) -> *TableState#

Creates mutable widget state.

  • selected: Index of the selected row.
  • offset: Index of the first visible row.
fn table(columns: [Column], rows: [[string]]) -> Table#

Creates a table widget.

  • columns: The schema, in display order.
  • rows: Row data, each a list of cell texts.
impl TableState#
fn selected_index(self: *TableState) -> int#

Returns the selected item index.

fn scroll_offset(self: *TableState) -> int#

Returns the first visible item index.

fn select(self: *TableState, index: int, count: int)#

Moves the selection to a clamped index.

  • index: Index to move to, clamped into range.
  • count: How many rows the table holds.
fn scroll_into_view(self: *TableState, height: int, count: int)#

Adjusts the offset so the selection is visible.

  • height: How many rows are visible.
  • count: How many rows the table holds.
fn render(value: Table, state: *TableState, window: Window)#

Rendering only observes TableState. A row with fewer cells is padded; extra cells are ignored according to the column schema.

  • value: The table to paint.
  • state: Selection and scroll position, read but not changed.
  • window: Window to draw into.

moon_tui.widget_tabs

struct Tabs#

Titles, selection, and styles for a tab bar.

titles: [string]

Tab labels, in display order.

selected: int

Index of the active tab.

style: Style

Style inactive tabs carry.

selected_style: Style

Style the active tab carries.

divider: string

Text drawn between adjacent tabs.

fn tabs(titles: [string], selected: int) -> Tabs#

Creates a tabs widget.

  • titles: Tab labels, in display order.
  • selected: Index of the active tab.
fn render(value: Tabs, window: Window)#

Renders the value into its target.

  • value: The tab bar to paint.
  • window: Window to draw into.

moon_tui.width

struct WidthPolicy#

Terminal-width policy. Ambiguous characters default to one column.

ambiguous_wide: bool

Whether East Asian ambiguous characters take two columns.

emoji_wide: bool

Whether emoji presentation takes two columns.

tab_width: int

Columns a tab advances to the next stop.

struct Cluster#

One grapheme cluster and its displayed terminal-cell width.

text: string

The grapheme cluster itself.

width: int

Columns it occupies under the policy that measured it.

newline: bool

Whether the cluster is a line break.

tab: bool

Whether the cluster is a tab.

fn default_policy() -> WidthPolicy#

Returns the default terminal width policy.

use moon_tui.width

fn main() {
  println(width.text_width("moon"))
  println(width.text_width("็•Œ"))
  println(width.clusters("๐Ÿ‘ฉโ€๐Ÿ’ป")[0].width)
  println(width.is_printable_ascii("plain"))
  let mut policy = width.default_policy()
  policy.ambiguous_wide = true
  policy.tab_width = 8
  println(width.text_width("ยท", policy))
}
fn is_printable_ascii(text: string) -> bool#

True when every byte is a printable one-column ASCII character. Keeping this common terminal-text path allocation-free avoids paying the Unicode segmentation cost for labels, borders, counters, and status lines.

  • text: Text to classify.
fn clusters(text: string, policy: WidthPolicy) -> [Cluster]#

Incremental-friendly extended-grapheme segmentation over one byte string. Invalid UTF-8 bytes become independent U+FFFD clusters.

  • text: Text to segment; invalid UTF-8 becomes U+FFFD clusters.
  • policy: How grapheme display widths are measured.
fn text_width(text: string, policy: WidthPolicy) -> int#

Returns the displayed terminal-cell width of text.

  • text: Text to measure.
  • policy: How grapheme display widths are measured.