ccui-tui
Rust
Still ongoing project
Quick Start
use ccui::{Ui, Text, Style, Container};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut doc = Ui::run()?;
// Add widgets
doc.add_widget("title", Text::new("Hello"))?;
// Add container with children
let row = doc.add_container("row", Style::new().row())?;
row.add_widget("left", Text::new("Left"))?;
row.add_widget("right", Text::new("Right"))?;
// Handle events (this blocks and prevents program from exiting)
while let Some(event) = doc.event_receiver().recv().await {
if let ccui::Event::Key(key) = event {
if key.code == crossterm::event::KeyCode::Char('q') {
break;
}
}
}
Ok(())
}
Design Philosophy
Since terminal drawing is a frame-by-frame operation, loop rendering is required. But this will block the program, so this framework sets it into an asynchronous thread. Besides, we are committed to making it DOM-like experience.
ID-driven + Async
- All UI elements are identified by string IDs
- Operations are synchronous sends to an async render loop
- Handles (
ContainerHandle,WidgetHandle) are lightweight and cloneable - Event-driven: block on
event_receiver()to stay alive and handle input
Core Concepts
- ID-driven: All elements identified by string IDs
- Handles:
ContainerHandleandWidgetHandlefor chaining operations - Async: All operations are synchronous sends to async render loop
Notes
- Blocking required:
Ui::run()returns immediately. You must block (e.g., event loop) to prevent program from exiting - Default parent for
Documentmethods is"root" ContainerHandleandWidgetHandleare cloneable- Use
get_container(id)/get_widget(id)to get handles by ID - When
Documentis dropped, the terminal is automatically restored