# tastty
A batteries-included toolkit for terminal parsing, session management,
and automation for the Rust language.
- **Parsing**: VT parsing into a live screen buffer, with input
encoders and host replies.
- **Sessions**: run a program in a managed PTY, answering host queries, with
input handling. Embeddable in a [ratatui] app as a widget.
- **Automation**: spawn, send input, wait on conditions, snapshot, assert on screen state.
[![tastty-core][core-badge]][core-crates]
[![tastty][tastty-badge]][tastty-crates]
[![tastty-driver][driver-badge]][driver-crates]
[![ratatui support][ratatui-badge]][ratatui-rs]
[![Matrix][matrix-badge]][matrix-url]
[![MIT licensed][mit-badge]][mit-url]
## Example
Embed a live terminal in a [ratatui] app by spawning a program and
rendering it as a widget:
```sh
cargo add tastty
```
```rust,no_run
use std::time::Duration;
use crossterm::event::{self, Event, KeyCode, KeyModifiers};
use tastty::widget::PseudoTerminal;
use tastty::{Builder, Terminal, TerminalSize};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut tui = ratatui::init();
let size = tui.size()?;
let term = Terminal::spawn(
Builder::command("bash").size(TerminalSize { rows: size.height, cols: size.width }),
)?;
while !term.is_finished() {
if term.take_redraw() {
tui.draw(|f| term.with_screen(|s| f.render_widget(PseudoTerminal::new(s), f.area())))?;
}
// Forward keystrokes to the child; Ctrl+Q quits.
if event::poll(Duration::from_millis(16))? {
if let Event::Key(key) = event::read()? {
if key.code == KeyCode::Char('q') && key.modifiers.contains(KeyModifiers::CONTROL) {
break;
}
let _ = term.send_key(key);
}
}
}
ratatui::restore();
Ok(())
}
```
Drive an interactive program headless and assert on its screen:
```sh
cargo add tastty-driver
```
```rust,no_run
use std::time::Duration;
use tastty_driver::{Builder, InputSegment, Session, WaitCondition};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let session = Session::spawn(Builder::command("bash"))?;
session.send_input(&[InputSegment::Text("echo hello\n".into())])?;
let outcome = session.wait(
WaitCondition::regex("hello"),
Duration::from_secs(5),
)?;
println!("{}", outcome.snapshot.text());
Ok(())
}
```
Check out the per-crate `examples/` directories, for more information, or run an example:
```sh
cargo run -p tastty --example bordered
```
## Crates
- [`tastty-core`][core-docs]: VT parser, screen buffer, and input
encoders.
- [`tastty`][tastty-docs]: managed PTY sessions, with optional [ratatui]
widget support via [tui-term].
- [`tastty-driver`][driver-docs]: the automation layer for driving and
testing terminal programs.
## Contributing
We welcome contributions from the community!
Check out the [Contributing Guidelines](./docs/CONTRIBUTING.md) on how to get started.
## Status
> [!NOTE]
> This project is still in active development and should be considered a work in progress.
> We value feedback on the API and usability greatly.
## License
`tastty` is available under the MIT license. See [LICENSE](LICENSE) for
more information.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in `tastty` by you shall be licensed as MIT,
without any additional terms or conditions.
[core-badge]: https://img.shields.io/crates/v/tastty-core?style=flat-square&label=tastty-core
[core-crates]: https://crates.io/crates/tastty-core
[core-docs]: https://docs.rs/tastty-core
[tastty-badge]: https://img.shields.io/crates/v/tastty?style=flat-square&label=tastty
[tastty-crates]: https://crates.io/crates/tastty
[tastty-docs]: https://docs.rs/tastty
[driver-badge]: https://img.shields.io/crates/v/tastty-driver?style=flat-square&label=tastty-driver
[driver-crates]: https://crates.io/crates/tastty-driver
[driver-docs]: https://docs.rs/tastty-driver
[ratatui-badge]: https://img.shields.io/badge/ratatui-widget-000?style=flat-square&logo=ratatui
[ratatui-rs]: https://ratatui.rs
[matrix-badge]: https://img.shields.io/badge/matrix-%23tastty-0dbd8b?style=flat-square&logo=matrix&logoColor=white
[matrix-url]: https://matrix.to/#/%23tastty:matrix.org
[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square
[mit-url]: LICENSE
[ratatui]: https://crates.io/crates/ratatui
[tui-term]: https://crates.io/crates/tui-term