# tuikit **Repository Path**: mirrors_ClickHouse/tuikit ## Basic Information - **Project Name**: tuikit - **Description**: Tool kit for writing TUI applications in Rust. - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-05-26 - **Last Updated**: 2026-02-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README [![Crates.io](https://img.shields.io/crates/v/tuikit.svg)](https://crates.io/crates/tuikit) [![Build Status](https://github.com/lotabout/tuikit/workflows/Build%20&%20Test/badge.svg)](https://github.com/lotabout/tuikit/actions?query=workflow%3A%22Build+%26+Test%22) ## Tuikit Tuikit is a TUI library for writing terminal UI applications. Highlights: - Thread safe. - Support non-fullscreen mode as well as fullscreen mode. - Support `Alt` keys, mouse events, etc. - Buffering for efficient rendering. Tuikit is modeld after [termbox](https://github.com/nsf/termbox) which views the terminal as a table of fixed-size cells and input being a stream of structured messages. **WARNING**: The library is not stable yet, the API might change. ## Usage In your `Cargo.toml` add the following: ```toml [dependencies] tuikit = "*" ``` And if you'd like to use the latest snapshot version: ```toml [dependencies] tuikit = { git = "https://github.com/lotabout/tuikit.git" } ``` Here is an example (could also be run by `cargo run --example hello-world`): ```rust use tuikit::prelude::*; use std::cmp::{min, max}; fn main() { let term: Term<()> = Term::with_height(TermHeight::Percent(30)).unwrap(); let mut row = 1; let mut col = 0; let _ = term.print(0, 0, "press arrow key to move the text, (q) to quit"); let _ = term.present(); while let Ok(ev) = term.poll_event() { let _ = term.clear(); let _ = term.print(0, 0, "press arrow key to move the text, (q) to quit"); let (width, height) = term.term_size().unwrap(); match ev { Event::Key(Key::ESC) | Event::Key(Key::Char('q')) => break, Event::Key(Key::Up) => row = max(row-1, 1), Event::Key(Key::Down) => row = min(row+1, height-1), Event::Key(Key::Left) => col = max(col, 1)-1, Event::Key(Key::Right) => col = min(col+1, width-1), _ => {} } let attr = Attr{ fg: Color::RED, ..Attr::default() }; let _ = term.print_with_attr(row, col, "Hello World! 你好!今日は。", attr); let _ = term.set_cursor(row, col); let _ = term.present(); } } ``` ## Layout `tuikit` provides `HSplit`, `VSplit` and `Win` for managing layouts: 1. `HSplit` allow you to split area horizontally into pieces. 2. `VSplit` works just like `HSplit` but splits vertically. 3. `Win` do not split, it could have margin, padding and border. For example: ```rust use tuikit::prelude::*; struct Model(String); impl Draw for Model { fn draw(&self, canvas: &mut dyn Canvas) -> DrawResult<()> { let (width, height) = canvas.size()?; let message_width = self.0.len(); let left = (width - message_width) / 2; let top = height / 2; let _ = canvas.print(top, left, &self.0); Ok(()) } } impl Widget for Model{} fn main() { let term: Term<()> = Term::with_height(TermHeight::Percent(50)).unwrap(); let model = Model("middle!".to_string()); while let Ok(ev) = term.poll_event() { if let Event::Key(Key::Char('q')) = ev { break; } let _ = term.print(0, 0, "press 'q' to exit"); let hsplit = HSplit::default() .split( VSplit::default() .basis(Size::Percent(30)) .split(Win::new(&model).border(true).basis(Size::Percent(30))) .split(Win::new(&model).border(true).basis(Size::Percent(30))) ) .split(Win::new(&model).border(true)); let _ = term.draw(&hsplit); let _ = term.present(); } } ``` The split algorithm is simple: 1. Both `HSplit` and `VSplit` will take several `Split` where a `Split` would contains: 1. basis, the original size 2. grow, the factor to grow if there is still enough room 3. shrink, the factor to shrink if there is not enough room 2. `HSplit/VSplit` will count the total width/height(basis) of the split items 3. Judge if the current width/height is enough or not for the split items 4. shrink/grow the split items according to their grow/shrink: `factor / sum(factors)` 5. If still not enough room, the last one(s) would be set width/height 0 ## References `Tuikit` borrows ideas from lots of other projects: - [rustyline](https://github.com/kkawakam/rustyline) Readline Implementation in Rust. - How to enter the raw mode. - Part of the keycode parsing logic. - [termion](https://gitlab.redox-os.org/redox-os/termion) A bindless library for controlling terminals/TTY. - How to parse mouse events. - How to enter raw mode. - [rustbox](https://github.com/gchp/rustbox) and [termbox](https://github.com/nsf/termbox) - The idea of viewing terminal as table of fixed cells. - [termfest](https://github.com/agatan/termfest) Easy TUI library written in Rust - The buffering idea.