Skip to main content

core.term — Terminal / TUI framework

Verum's TUI framework is a seven-layer stack. Each layer is self-contained: use raw mode for a shell, the rendering engine for a scripted output, or the full application framework for an interactive app.

What makes it production-grade

AreaVerum core.term
AsyncFirst-class: Command.Async(Future) lands directly in the runtime via core.async. Subscriptions run as detached tasks.
CancellationEvery spawned task observes a CancellationToken; cleanup on Quit is automatic.
UnicodeGrapheme-cluster cursor & width (UAX #29 + UTS #51 approximation) — ZWJ emoji, skin tones, flags all render correctly.
LayoutCSS Flexbox Level 1 (flex-grow/shrink/basis) and CSS Grid Level 1, not just Constraint.
StyleCIELAB-perceptual adaptive color downscaling; TrueColor → 256 → 16 without perceptible drift.
GraphicsKitty, Sixel, iTerm2, and Braille fallback — auto-detected from TermCapabilities.
Diff renderDouble-buffered, row-level fast-path skip, cursor-motion minimisation, synchronized output (Mode 2026).
Mouse / paste / focusSGR extended mouse, bracketed paste (Mode 2004), focus events (Mode 1004).
ClipboardOSC 52 read & write, built into raw.clipboard.
AccessibilityOSC 133 semantic zones (Prompt / CommandInput / CommandOutput / CommandEnd / Live regions).

Quick start

mount core.term.prelude.*;

type Model is {
counter: Int,
};

type Msg is Increment | Decrement;

implement Model for Model {
type Msg = Msg;

fn update(&mut self, msg: Msg) -> Command<Msg> {
match msg {
Increment => { self.counter = self.counter + 1; Command.none() }
Decrement => { self.counter = self.counter - 1; Command.none() }
}
}

fn view(&self, frame: &mut Frame) {
let title = f"Counter: {self.counter} — press ↑/↓ / q to quit";
let block = Block.new().title(title).borders(Borders.ALL);
frame.render(block, frame.size());
}

fn handle_event(&self, event: Event) -> Maybe<Msg> {
match event {
Event.Key(ke) => match ke.code {
KeyCode.Up => Some(Increment),
KeyCode.Down => Some(Decrement),
_ => None,
},
_ => None,
}
}
}

fn main() -> IoResult<()> {
run(Model { counter: 0 })
}

Reading map