# Envision
[](https://github.com/ryanoneill/envision/actions/workflows/ci.yml)
[](https://codecov.io/gh/ryanoneill/envision)
[](https://docs.rs/envision)
[](https://crates.io/crates/envision)
[](LICENSE)
A [ratatui](https://github.com/ratatui/ratatui) framework for collaborative TUI development with headless testing support.
## Features
- **Component Library** - 74 ready-to-use UI components following TEA pattern
- **Headless Testing** - Render your TUI without a terminal using `CaptureBackend`
- **TEA Architecture** - The Elm Architecture pattern with `App`, `Runtime`, and `Command`
- **Async Runtime** - Full async support with subscriptions, timers, and async commands
- **Widget Annotations** - Attach semantic metadata to widgets for testing and accessibility
- **Test Harness** - Fluent assertions and snapshot testing for TUI applications
- **Input Simulation** - Programmatically simulate keyboard and mouse events
- **Multiple Output Formats** - Plain text, ANSI-colored, and JSON output
## Feature Flags
Envision is feature-gated so consumers can opt out of the parts they don't need. Default features enable serialization and all component groups.
| `full` | yes | All component groups + clipboard + markdown + regex (convenience alias) |
| `input-components` | yes (via `full`) | Interactive input widgets (`LineInput`, `TextArea`, `Dropdown`, `Select`, ...) |
| `data-components` | yes (via `full`) | Data-display widgets (`Table`, `DataGrid`, `Tree`, `ResourceGauge`, ...) |
| `display-components` | yes (via `full`) | Text and chart widgets (`StyledText`, `Chart`, `Sparkline`, ...) |
| `navigation-components` | yes (via `full`) | `PaneLayout`, `Router`, `TabBar`, `KeyHints` |
| `overlay-components` | yes (via `full`) | Overlay stack primitives |
| `compound-components` | yes (via `full`) | Higher-level compositions (`Diagram`, `LogViewer`, `ConversationView`) |
| `serialization` | yes | `serde::Serialize`/`Deserialize` on component state |
| `tracing` | no | Emits `tracing::warn!` diagnostics (e.g., table column clip warnings) |
| `clipboard` | yes (via `full`) | `arboard`-backed clipboard on `TextArea` |
| `markdown` | yes (via `full`) | Markdown rendering in `StyledText` |
| `regex` | yes (via `full`) | Regex search in `EventStream`, `LogViewer` |
| `test-utils` | no | `AppHarness` async test utilities (`advance_time`, `wait_for`) at the crate boundary for downstream tests |
To opt out of everything and only pull in specific groups:
```toml
[dependencies]
envision = { version = "0.17", default-features = false, features = ["data-components", "display-components"] }
```
## Quick Start
Add envision to your project:
```bash
cargo add envision
```
### Basic Capture Backend
```rust
use envision::backend::CaptureBackend;
use ratatui::Terminal;
use ratatui::widgets::Paragraph;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a headless terminal
let backend = CaptureBackend::new(80, 24);
let mut terminal = Terminal::new(backend)?;
// Render something
terminal.draw(|frame| {
frame.render_widget(Paragraph::new("Hello, Envision!"), frame.area());
})?;
// Capture the output
println!("{}", terminal.backend());
Ok(())
}
```
### TEA Architecture
```rust
use envision::prelude::*;
use ratatui::widgets::Paragraph;
struct MyApp;
#[derive(Default, Clone)]
struct State {
count: i32,
}
#[derive(Clone)]
enum Msg {
Increment,
Decrement,
}
impl App for MyApp {
type State = State;
type Message = Msg;
type Args = ();
fn init(_args: ()) -> (State, Command<Msg>) {
(State::default(), Command::none())
}
fn update(state: &mut State, msg: Msg) -> Command<Msg> {
match msg {
Msg::Increment => state.count += 1,
Msg::Decrement => state.count -= 1,
}
Command::none()
}
fn view(state: &State, frame: &mut Frame) {
let text = format!("Count: {}", state.count);
frame.render_widget(Paragraph::new(text), frame.area());
}
}
```
### Testing with AppHarness
```rust
use envision::prelude::*;
use ratatui::widgets::Paragraph;
struct MyApp;
#[derive(Default, Clone)]
struct State {
count: i32,
}
#[derive(Clone)]
enum Msg {
Increment,
Decrement,
}
impl App for MyApp {
type State = State;
type Message = Msg;
type Args = ();
fn init(_args: ()) -> (State, Command<Msg>) {
(State::default(), Command::none())
}
fn update(state: &mut State, msg: Msg) -> Command<Msg> {
match msg {
Msg::Increment => state.count += 1,
Msg::Decrement => state.count -= 1,
}
Command::none()
}
fn view(state: &State, frame: &mut Frame) {
let text = format!("Count: {}", state.count);
frame.render_widget(Paragraph::new(text), frame.area());
}
}
fn test_my_app() {
let mut harness = AppHarness::<MyApp>::new(80, 24).unwrap();
harness.dispatch(Msg::Increment);
harness.dispatch(Msg::Increment);
harness.render().unwrap();
harness.assert_contains("Count: 2");
}
test_my_app();
```
### Test Harness for Custom Rendering
```rust
use envision::prelude::*;
use ratatui::widgets::Paragraph;
let mut harness = TestHarness::new(80, 24);
harness
.render(|frame| {
frame.render_widget(Paragraph::new("Hello!"), frame.area());
})
.unwrap();
harness.assert_contains("Hello!");
```
## Examples
Run the examples to see envision in action:
```bash
# Basic capture backend usage
cargo run --example capture_backend
# TEA architecture with sync runtime
cargo run --example counter_app
# Async runtime with subscriptions
cargo run --example async_counter
# Test harness and assertions
cargo run --example test_harness
# Widget annotations
cargo run --example annotations
# Theme switching with components
cargo run --example themed_app
# Multi-component showcase with focus management
cargo run --example component_showcase
```
## Components
Envision provides a comprehensive library of 74 reusable UI components, all following the TEA (The Elm Architecture) pattern with `Component` and `Toggleable` traits.
### Input Components
| `Button` | Clickable button with keyboard activation |
| `Checkbox` | Toggleable checkbox with label |
| `Dropdown` | Searchable/filterable select with type-to-filter |
| `InputField` | Single-line text input with cursor navigation |
| `LineInput` | Single-line input with visual wrapping, history, undo/redo |
| `RadioGroup` | Single-selection radio button group |
| `Select` | Dropdown selection widget |
| `TextArea` | Multi-line text editor with scrolling |
### Navigation Components
| `Accordion` | Collapsible panel container |
| `Breadcrumb` | Navigation breadcrumb trail |
| `Menu` | Keyboard-navigable menu with shortcuts |
| `Router` | Multi-screen navigation with history |
| `StepIndicator` | Pipeline/workflow visualization with per-step styles |
| `Tabs` | Horizontal tab navigation |
| `TabBar` | Tab bar with closeable tabs and overflow |
### Data Components
| `LoadingList` | List with per-item loading and error states |
| `SelectableList` | Scrollable list with keyboard navigation |
| `Table` | Data table with sorting and selection |
| `Tree` | Hierarchical tree view with expand/collapse |
### Display Components
| `BigText` | Large block-character text rendering |
| `Calendar` | Month calendar with event markers |
| `Canvas` | General-purpose drawing surface with shape primitives |
| `CodeBlock` | Syntax-highlighted code display |
| `Collapsible` | Expandable/collapsible content panel |
| `Divider` | Horizontal or vertical separator |
| `Gauge` | Ratio and measurement display with thresholds |
| `HelpPanel` | Keyboard shortcut reference panel |
| `KeyHints` | Contextual keyboard shortcut bar |
| `MultiProgress` | Multiple concurrent progress trackers |
| `Paginator` | Page navigation indicators |
| `ProgressBar` | Progress display with ETA and rate |
| `ScrollView` | Scrollable container for arbitrary content |
| `ScrollableText` | Scrollable multi-line text display |
| `Sparkline` | Inline trend visualization |
| `Spinner` | Animated loading indicator (multiple styles) |
| `StatusBar` | Application status bar with sections |
| `StatusLog` | Timestamped status message log |
| `StyledText` | Rich text display with styled content |
| `TerminalOutput` | ANSI-capable terminal output display |
| `TitleCard` | Styled title with optional subtitle |
| `Toast` | Timed notification messages |
| `UsageDisplay` | Resource usage metrics display |
### Overlay Components
| `ConfirmDialog` | Preset confirmation dialog with Yes/No buttons |
| `Dialog` | Modal dialog overlay with custom buttons |
| `Tooltip` | Positioned tooltip with auto-dismiss |
### Compound Components
| `AlertPanel` | Alert metrics dashboard with sparklines |
| `BoxPlot` | Statistical box-and-whisker plots |
| `Chart` | Line, bar, area, and scatter charts with annotations |
| `CommandPalette` | Fuzzy-searchable command palette overlay |
| `ConversationView` | AI conversation display with role colors and markdown |
| `DataGrid` | Editable data table with cell navigation |
| `Diagram` | Graph visualization with Sugiyama and force-directed layout |
| `DiffViewer` | Side-by-side and unified diff display |
| `EventStream` | Real-time event log with levels and timestamps |
| `FileBrowser` | File system browser with pluggable backend |
| `FlameGraph` | Hierarchical flame graph visualization |
| `Form` | Multi-field form with validation |
| `Heatmap` | 2D color-mapped data visualization |
| `Histogram` | Distribution visualization with adaptive binning |
| `LogCorrelation` | Multi-stream synchronized log viewer |
| `LogViewer` | Filterable log display with search |
| `MarkdownRenderer` | Markdown text rendering (headings, bold, code, lists) |
| `MetricsDashboard` | Dashboard with charts, counters, and gauges |
| `PaneLayout` | Resizable split-pane layouts |
| `SearchableList` | Filterable list with search input |
| `SpanTree` | Hierarchical span/trace tree |
| `SplitPanel` | Resizable dual-panel layout |
| `Timeline` | Time-based event and span visualization |
| `Treemap` | Proportional area-based data visualization |
### Utility
| `FocusManager` | Keyboard focus coordination |
| `AppShell` | Consistent header/content/footer layout splits |
### Component Example
```rust
use envision::component::{Button, ButtonMessage, ButtonOutput, ButtonState, Component};
// Initialize state
let mut state = ButtonState::new("Submit");
// Handle messages
let output = Button::update(&mut state, ButtonMessage::Press);
assert_eq!(output, Some(ButtonOutput::Pressed));
```
## Architecture
Envision follows The Elm Architecture (TEA) pattern:
```text
┌─────────────────────────────────────────────────────────┐
│ Application │
│ │
│ ┌─────────┐ ┌────────┐ ┌──────────────────┐ │
│ │ State │────▶│ View │────▶│ Terminal/Frame │ │
│ └─────────┘ └────────┘ └──────────────────┘ │
│ ▲ │
│ │ │
│ ┌─────────┐ ┌────────────────────┐ │
│ │ Update │◀────│ Message/Events │ │
│ └─────────┘ └────────────────────┘ │
│ │ ▲ │
│ ▼ │ │
│ ┌─────────┐ ┌────────────────────┐ │
│ │ Command │────▶│ Effect Handler │ │
│ └─────────┘ └────────────────────┘ │
└─────────────────────────────────────────────────────────┘
```
## Modules
| `component` | 74 reusable UI components with `Component`, `Toggleable` traits |
| `backend` | `CaptureBackend` for headless rendering |
| `app` | TEA architecture: `App`, `Runtime`, `Command`, subscriptions |
| `harness` | `TestHarness` and `AppHarness` for testing |
| `annotation` | Widget annotations with `Annotate` and `AnnotationRegistry` |
| `input` | Input simulation with `EventQueue` |
| `overlay` | Modal overlay system with `Overlay` trait and `OverlayStack` |
| `theme` | Theming with `Theme` for consistent styling across components |
| `adapter` | `DualBackend` for simultaneous real + capture rendering |
## Minimum Supported Rust Version
The minimum supported Rust version is **1.85** (edition 2024).
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.