Terminal interaction for applications that own their loop.
Unicode editing · Terminal-native presentation · Rust and C
MIT License ·
Documentation ·
Rust example ·
C example
REPLAI is an embeddable terminal interaction library for line-oriented command interfaces. It handles the editable draft and the terminal around it: Unicode cursor movement, history navigation, multiline paste, completion requests, redraw, and restoration when an interaction ends.
Your application supplies the prompt, decides what the input means, and keeps control of execution. An interpreter, database shell, debugger or developer tool can use the same interaction machinery with its own language and policies.
Pre-release · Linux terminal backend qualified. The Rust API and C ABI 1 are experimental. Use an exact revision; no stable API/ABI or published crate release is promised. See project status for demonstrated scope and current limits.
A prompt is easy to print. Keeping a partially edited Unicode draft intact through history recall, pasted newlines, a terminal resize or an arriving notice requires coordinated editing state, display geometry and terminal ownership. REPLAI brings those mechanisms together behind a host-driven interface.
| During an interaction | REPLAI's responsibility | The host's decision |
|---|---|---|
| Editing a draft | Bounded UTF-8 text; grapheme movement and deletion | Input meaning and validation |
| Recalling input | History navigation; return to the original draft and cursor | Admission, retention and persistence |
| Pasting multiple lines | Bracketed framing; normalized newlines; one draft until Enter | What the submitted text executes |
| Requesting completion | Typed request; validated replacement and redraw | Candidate discovery and selection |
| Receiving external output | Write a safe text line; restore the draft and cursor | Content and scheduling |
| Submitting, interrupting or reaching EOF | Distinct outcomes; close and restore captured terminal state | Execute, cancel, retry or exit |
The library supplies a line-oriented editing surface with an accented prompt,
compact continuation lines and generic text roles. It uses the terminal's
default background and scrollback, with no alternate screen. NO_COLOR and
TERM=dumb disable styling; Unicode cells and multiline redraw are handled by
the same renderer for Rust and C.
Interaction contracts define the behavior and failure rules. Presentation defines the visual grammar, exact reference comparisons and terminal/emulator limits.
The Read–Eval–Print Loop reads an expression, evaluates it in an environment, prints a result, then returns to the next input. REPLAI provides the editable terminal input and its lifecycle. Parsing, evaluation and semantic result formatting belong to the host.
flowchart LR
edit["REPLAI<br/>Prompt · edit · submit"] --> read["Host<br/>Read / parse"]
read --> evaluate["Host<br/>Evaluate / execute"]
evaluate --> print["Host<br/>Format and print"]
print -->|Open next interaction| edit
This separation follows the evaluator-driver structure taught in SICP §4.1.4 and the application/editor boundary illustrated by GNU Readline's programming interface. These are architectural references, not API-compatibility claims.
The REPL guide develops the classical cycle with a worked example, the host/library sequence and primary references, including McCarthy's 1960 paper on symbolic evaluation. Architecture maps that boundary to REPLAI's safe Rust implementation and separate C binding.
From a checkout, on Linux with stable Rust and an interactive ANSI/VT-compatible terminal:
cargo run --locked --example demodemo> hello
echo: hello
demo> 界
... café
echo: 界
café
demo>
The second interaction illustrates a bracketed multiline paste, submitted once.
Try wor followed by Tab for host-selected completion, or type a draft and use
Up then Down to return to it. To see output arrive while you are editing:
cargo run --locked --example demo -- --noticeA notice appears after two seconds; the unfinished draft and cursor survive. Ctrl-C interrupts editing. Ctrl-D exits on an empty draft, and otherwise deletes the next grapheme. The example owns these loop decisions and history admission.
An Interaction owns a platform-neutral editing/interaction engine. Its current
Linux system façade acquires a terminal only while editing. See the
architecture for protocol/system separation and the
distinction between portable core tests and interactive platform qualification.
The host polls events and decides when to open the next interaction. For example,
this program reads one submitted input, keeping interruption and EOF distinct:
use replai::{Editor, Event, Interaction, Prompt, Role};
use std::time::Duration;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut input = Interaction::new(Editor::new(65_536, 100));
input.open(&std::io::stdin(), &std::io::stdout(), Prompt::new("demo")?)?;
loop {
match input.poll(Duration::from_millis(100))? {
Some(Event::Submitted(text)) => {
println!("received: {text}"); // The terminal is already restored.
break;
}
Some(Event::Interrupted) => break,
Some(Event::EndOfInput) => break,
Some(Event::CompletionRequested) => {} // This host declines completion.
Some(Event::Rejected(error)) => {
input.external_output(Role::Warning, &error.to_string())?;
}
None => {}
}
}
Ok(())
}The complete Rust example adds completion, explicit history
admission and reopen behavior. Generate method documentation with
cargo doc --no-deps. Hosts keep their application loop; no callback framework
or asynchronous runtime is required.
The separate replai-c binding consumes the public Rust API. It exposes ABI 1
through opaque handles, typed integer events and caller-owned UTF-8 buffers.
Both language interfaces use one editor and renderer.
Build the producer artifacts and stage them into an absent or empty prefix:
cargo build --locked --release -p replai-c
python3 tools/stage_c.py --prefix /tmp/replai-installThe installation provides replai.h, libreplai_c.a, libreplai_c.so and the
replai pkg-config package. A C consumer needs only those installed artifacts
and its native toolchain; it does not need Cargo or access to Rust source.
The C guide gives exact static/shared link commands, the create → open → poll → close/reopen → destroy lifecycle, and ownership/error rules. The C example demonstrates the complete host loop.
Qualification exercises both the safe Rust implementation and independently compiled C processes. It observes submitted UTF-8 bytes, terminal cells and cursor position, exact termios restoration, descriptor ownership, C/Rust ABI layout, staged library resolution and memory-checker results. Real Linux PTYs are part of both paths. CI keeps documentation, Rust and native-consumer gates visible separately.
| Continue with… | For… |
|---|---|
| Documentation map | The authoritative document for each question |
| REPL guide | Classical foundations and the host interaction sequence |
| Architecture | Modules, dependencies and safe/unsafe ownership |
| Development | Reproducible checks and evidence requirements |
| Contributing | Proposing focused changes |
| Project status · Changelog | Current limits, next work and consumer-visible changes |
MIT.
