Skip to main content

taria_ratatui/
lib.rs

1//! Ratatui adapter for taria, the agent accessibility layer for terminal UIs.
2//!
3//! Embed a [`TariaLayer`] in your ratatui app and each rendered frame can also
4//! publish a semantic [`taria::Snapshot`] over the taria transport (one JSON
5//! message per line over a Unix domain socket on Linux and macOS, or a named
6//! pipe on Windows). Agent inputs come back as [`taria::AgentInput`] values
7//! your event loop handles like any other input source.
8//!
9//! [`taria::AgentInput::Text`] is the one that needs aiming rather than
10//! handling: typed text belongs wherever your app puts typing, not in your key
11//! handler, or an agent's two characters meet your bindings instead of your
12//! text field. Route it to that surface yourself, and use [`text_to_keys`] to
13//! lower it if the surface is made of key events.
14//!
15//! # Usage
16//!
17//! ```no_run
18//! use ratatui::widgets::Paragraph;
19//! use taria::{Node, Role};
20//! use taria_ratatui::{InputStatus, TariaLayer, sem};
21//!
22//! fn main() -> std::io::Result<()> {
23//!     // Never fails: if the socket (a named pipe on Windows) cannot be
24//!     // bound, the layer is inert and the app runs exactly as it would
25//!     // without taria.
26//!     let mut layer = TariaLayer::bind_or_disabled("my-app");
27//!     let mut terminal = ratatui::init();
28//!
29//!     // Each render pass: record semantics alongside drawing, then publish.
30//!     let rec = layer.frame();
31//!     terminal.draw(|frame| {
32//!         let widget = Paragraph::new("hello");
33//!         let node = Node::new("greeting", Role::Text).label("hello");
34//!         frame.render_widget(sem(&rec, widget, node), frame.area());
35//!     })?;
36//!     rec.publish();
37//!
38//!     // Drain agent input alongside terminal events. Each input is acked
39//!     // `Delivered` as it is handed over; return `Ignored` for one you
40//!     // looked at and deliberately did nothing with, and the layer sends it.
41//!     layer.drain(|_input| {
42//!         // Apply to app state exactly like a keyboard event.
43//!         InputStatus::Delivered
44//!     });
45//!
46//!     ratatui::restore();
47//!     // Only now the alternate screen is gone is printing safe.
48//!     if let Some(err) = layer.bind_error() {
49//!         eprintln!("taria disabled: {err}");
50//!     }
51//!     Ok(())
52//! }
53//! ```
54
55#![warn(missing_docs)]
56#![warn(missing_debug_implementations)]
57
58mod bound;
59mod key;
60mod layer;
61mod recorder;
62mod semantic;
63#[cfg(test)]
64mod test_util;
65mod transport;
66
67pub use bound::SnapshotTooLarge;
68pub use key::{text_to_keys, to_crossterm, to_crossterm_key};
69pub use layer::{LayerStats, TariaLayer};
70pub use recorder::FrameRecorder;
71pub use semantic::{Semantic, sem};
72
73// Re-export the protocol crate so apps can depend on `taria-ratatui` alone,
74// and the two ack types the layer's own signatures use, so acking an input
75// needs no second import path.
76pub use taria;
77pub use taria::wire::{InputId, InputStatus};