Show HN: Tuie - A rich, performant TUI library for rust

vim-god1 pts0 comments

GitHub - jake-stewart/tuie: A rich, performant TUI library for Rust. · GitHub

/" data-turbo-transient="true" />

Skip to content

Search or jump to...

Search code, repositories, users, issues, pull requests...

-->

Search

Clear

Search syntax tips

Provide feedback

--><br>We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Cancel

Submit feedback

Saved searches

Use saved searches to filter your results more quickly

-->

Name

Query

To see all available qualifiers, see our documentation.

Cancel

Create saved search

Sign in

/;ref_cta:Sign up;ref_loc:header logged out"}"<br>Sign up

Appearance settings

Resetting focus

You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.

Dismiss alert

{{ message }}

jake-stewart

tuie

Public

Notifications<br>You must be signed in to change notification settings

Fork

Star<br>10

main

BranchesTags

Go to file

CodeOpen more actions menu

Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit

History<br>3 Commits<br>3 Commits

chord_macro

chord_macro

src

src

.gitignore

.gitignore

Cargo.toml

Cargo.toml

LICENSE

LICENSE

readme.md

readme.md

View all files

Repository files navigation

tuie

A rich, performant TUI library for Rust.

demo.mp4

Features

Layout: Flexbox, grids, splits, and virtualized lists, all with min, max, and preferred-size constraints.

Images: Kitty with sixel and half-block fallbacks, all working over SSH and tmux passthrough.

Input: Iterator-based extensible text input with vi, emacs, modern, and custom bindings.

Harmonious: Generated 256-color palette, consistent with user's base16 theme, zero config.

Chords: Construct and match on human readable inputs: chord!(Ctrl + Arrow(Up | Down))

Async: Timers and async callbacks with support for any async runtime.

Performance: Per subtree/widget/cell dirty tracking, batched queries, shared memory graphics, packed structs.

GUI: Optionally run as a GUI with box-drawing, smooth scrolling.

Getting started

Install:

cargo add tuie --features=harmonious

Write your main:

std::io::Result {<br>let root = Pane::new()<br>.border(Border::SINGLE)<br>.child(Text::new().content("hello world"));<br>tuie::start_tui(root)<br>}">use tuie::prelude::*;<br>use std::process::ExitCode;

fn main() -> std::io::ResultExitCode> {<br>let root = Pane::new()<br>.border(Border::SINGLE)<br>.child(Text::new().content("hello world"));<br>tuie::start_tui(root)

Run:

cargo run

Constructing widgets

Chain builders to create a simple widget tree:

Box {<br>Pane::new()<br>.border(Border::SINGLE)<br>.child(Text::new().content(format!("hello {name}")))<br>}">fn greeting(name: String) -> BoxPane> {<br>Pane::new()<br>.border(Border::SINGLE)<br>.child(Text::new().content(format!("hello {name}")))

Or compose widgets together for something more complicated:

text_id: WidgetId,

impl Greeting {<br>fn new(name: &str) -> Box {<br>let mut text_id = WidgetId::EMPTY;<br>let root = Pane::new().border(Border::SINGLE).child(<br>Text::new().content(format!("hello {name}")).id(&mut text_id)<br>);<br>Box::new(Self { root, text_id })

fn set_name(&mut self, name: &str) {<br>if let Some(text) = self.root.get_widget_mut(self.text_id) {<br>text.set_content(format!("hello {name}"));

impl DelegateWidget for Greeting {<br>tuie::delegate_widget!(root);

fn override_on_input(&mut self, queue: &mut InputQueue) -> InputResult {<br>// you can override or react to your root widget's events and methods<br>// using after_* and override_*.<br>return self.root.on_input(queue);<br>}">struct Greeting {<br>root: BoxPane>,<br>text_id: WidgetIdText>,

impl Greeting {<br>fn new(name: &str) -> BoxSelf> {<br>let mut text_id = WidgetId::EMPTY;<br>let root = Pane::new().border(Border::SINGLE).child(<br>Text::new().content(format!("hello {name}")).id(&mut text_id)<br>);<br>Box::new(Self { root, text_id })

fn set_name(&mut self, name: &str) {<br>if let Some(text) = self.root.get_widget_mut(self.text_id) {<br>text.set_content(format!("hello {name}"));

impl DelegateWidget for Greeting {<br>tuie::delegate_widget!(root);

fn override_on_input(&mut self, queue: &mut InputQueue) -> InputResult {<br>// you can override or react to your root widget's events and methods<br>// using after_* and override_*.<br>return self.root.on_input(queue);

You can also impl Widget yourself, which is how all of the default widgets are implemented.

Examples

tuie-demo: discoverable, interactive reference covering most widgets and features.

fz: fuzzy finder built on tuie, a real-world example of a non-trivial application.

Feature flags

harmonious — enables Lab-space palette generation from the terminal's base16 colors.

images — enables the Image widget and ImageConfig/ImageProtocol/ImageSource types; pulls in the image crate.

gui — enables start_gui and the gui module; pulls in winit, wgpu, pollster, fontdb, and freetype-rs (plus objc2 on macOS). Implies...

root tuie name border self text

Related Articles