ccui-tui
Loading...

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: ContainerHandle and WidgetHandle for 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 Document methods is "root"
  • ContainerHandle and WidgetHandle are cloneable
  • Use get_container(id) / get_widget(id) to get handles by ID
  • When Document is dropped, the terminal is automatically restored