A Rust library for building rich, stateful terminal user interfaces and dashboards.
rustom follows the immediate mode widget architecture common to modern Rust TUI libraries: widgets are cheap, disposable values that consume themselves when rendered into an in memory Buffer, the Terminal diffs the current buffer against the previous frame, and only the cells that actually changed get written to the real terminal. Rendering is backend agnostic through a Backend trait, with a crossterm implementation included.
Buffer/Cell: the in memory grid every widget renders into.Layout: split a screen area into rows or columns usingLength,Percentage,Ratio,Min,Max, andFillconstraints.Style,Color,Modifier: foreground and background colors plus text attributes like bold, italic, and underline.Span,Line,Text: composable styled text.- Widgets:
Block,Paragraph(with word wrap and scrolling),List(with selection and auto scroll),Table(with a header row and per column widths),Gauge,LineGauge,Tabs,Sparkline,BarChart, andScrollbar. Terminal: double buffered, diff based rendering with acrosstermbackend andinit/restorehelpers for raw mode and the alternate screen.
[dependencies]
rustom = "0.1.0"use std::io;
use rustom::layout::{Constraint, Direction, Layout};
use rustom::style::{Color, Style};
use rustom::widgets::{Block, Paragraph};
fn run() -> io::Result<()> {
let mut terminal = rustom::init()?;
terminal.draw(|frame| {
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Length(3), Constraint::Fill(1)])
.split(frame.area());
frame.render_widget(Block::bordered().title("rustom"), chunks[0]);
let body = Paragraph::new("Hello from rustom.")
.style(Style::new().fg(Color::Cyan))
.block(Block::bordered());
frame.render_widget(body, chunks[1]);
})?;
rustom::restore()?;
Ok(())
}Run the full demo, which wires up tabs, a list with a scrollbar, a table, a paragraph, a sparkline, a bar chart, a gauge, and a line gauge in a single event loop:
cargo run --example demoPress q to quit, j / k or the arrow keys to move the list selection, and Tab to switch tabs.
- Widgets implement
Widget::render(self, area, buf), consuming themselves. Build a fresh widget from your application state every frame rather than mutating one in place. - Widgets that need to remember something across frames (a selected list index, a scroll offset) implement
StatefulWidgetinstead, and take a&mut Statethat you own and store alongside the rest of your application state. Layout::splituses a two pass greedy solver: fixed size constraints (Length,Percentage,Ratio,Max) claim their space first, then leftover space is divided amongMinandFillsegments in proportion to their weights.Chart(axes and line/scatter datasets) andCanvas(arbitrary line drawing) are not implemented yet. Everything else in the widget list above is.
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.