Low-level terminal primitives for MoonBit.
moonbit-community/tty provides a small foundation for programs that need to talk to a
real terminal: tty detection, raw mode, terminal size queries, output
commands, color values, and host input decoding. It is intentionally below a
full TUI framework. It does not own a screen model, layout engine, widget tree,
pane system, or scrollback buffer.
This module is early and native-target focused. Public APIs are still being shaped around small terminal programs and the examples in this repository.
The root package owns coordinated terminal handles and stateful terminal operations.
Use Tty when an operation needs a real terminal handle:
- process stdio:
Tty::stdio() - controlling terminal:
Tty::open() - custom handles:
Tty::new(input, output)withReaderandWritertraits for async files, stdio, and OS pipes - raw mode:
Tty::get_state,State::make_raw,Tty::set_state,Tty::with_raw_mode - terminal size:
Tty::window_size - cursor position report:
Tty::query_cursor_position - kitty keyboard protocol support query:
Tty::query_kitty_keyboard_support - dynamic color queries:
Tty::query_default_foreground_color,Tty::query_default_background_color, andTty::query_cursor_color - terminal events:
Tty::read_event - output commands: cursor movement/visibility, line/display/scrollback erase, scroll margins, reverse index, alternate screen, bracketed paste mode, SGR mouse tracking, focus tracking, DEC auto wrap mode, foreground/background colors, text attributes, and style reset
Raw file and stdio byte I/O should use moonbitlang/async/fs and
moonbitlang/async/stdio directly. The root package does not wrap them as
stdin, stdout, or stderr.
VT/ANSI byte construction is an internal implementation detail. Downstream callers
should use root Tty output command methods instead of importing byte-sequence
helpers directly.
User input event values.
The package contains key, paste, mouse, focus, modifier, and unknown-input values
reported through root Tty::read_event. Terminal response traffic such as
cursor position reports and kitty keyboard detection replies is consumed by root
query methods and is not part of the public input event model. Root callers
that are working with a terminal should use Tty::read_event so input, resize
notifications, and terminal request/response traffic share the same coordinated
terminal handle.
When bracketed paste mode is enabled, complete valid UTF-8 paste payloads are reported as one paste input event. When SGR mouse tracking is enabled, 1006 mouse reports are decoded as cell-coordinate mouse input events. When focus tracking is enabled, focus in and focus out reports are decoded as input events.
Semantic terminal color values.
The package represents default, ANSI basic/bright, indexed 256-color, RGB
truecolor values, and 16-bit RGB values returned by terminal color queries.
Root Tty methods turn Color values into SGR output.
Terminal dynamic color queries live on root Tty because they coordinate output
requests with input-stream responses.
Add the module and import the packages you need in moon.pkg:
import {
"moonbit-community/tty"
"moonbit-community/tty/color" @tty/color
"moonbit-community/tty/input" @tty/input
}Write terminal commands through a Tty:
async fn main {
let tty = @tty.Tty::stdio()
tty.hide_cursor()
tty.set_cursor_position(1, 1)
tty.bold()
tty.set_foreground(Basic(Green))
tty.write("hello from tty\r\n")
tty.reset_style()
tty.show_cursor()
}Run a scoped raw-mode input loop:
async fn main {
let tty = @tty.Tty::stdio()
tty.with_raw_mode(() => {
tty.write("press q to quit\r\n")
while true {
match tty.read_event() {
Input(Key(key)) =>
match key.code {
Char('q') => break
_ => ()
}
Input(Paste(_)) => ()
Input(Mouse(_)) => ()
Input(FocusIn) => ()
Input(FocusOut) => ()
Input(Unknown(_)) => ()
Resize(_) => ()
}
}
})
}Examples live in a separate workspace member under examples/.
moon run examples/raw
moon run examples/input
moon run examples/color
moon run examples/cursor
moon run examples/pager -- README.md
moon run examples/agentThe examples are manual validation tools, not framework APIs:
examples/rawchecks raw mode behavior.examples/inputprints decoded key, paste, mouse, focus, and resize events as they arrive.examples/colorprints a color specimen.examples/cursordraws with cursor movement and erase sequences.examples/pagerdemonstrates primary-screen paging with a fixed status row.examples/agentdemonstrates a Codex-like primary-screen transcript, input composer, delayed queued input, and shell command execution.
ttyowns terminal handles, platform state, raw mode, terminal size, cursor position queries, dynamic color queries, and command-style terminal operations.- internal VT helpers only build byte sequences for root
Ttymethods. inputcontains user input event values.- internal input decoding turns host input bytes into root terminal events and private terminal response events.
coloronly represents semantic color values.- Higher-level editing, layout, widgets, screen rendering, and terminal-emulator state belong outside this module unless the project plan changes.
See docs/architecture.md and docs/plan.md for the current design notes and
execution board.
Common validation commands:
moon fmt
moon test .
moon test
moon check
moon infoReview pkg.generated.mbti after moon info; it is the public API surface.