Tui-rs revival project

Related tags

Command-line ratatui
Overview

tui-rs

Build Status Crate Status Docs Status

Demo cast under Linux Termite with Inconsolata font 12pt

What is this fork?

This fork was created to continue maintenance on the original TUI project. The original maintainer had created an issue explaining how he couldn't find time to continue development, which led to us creating this fork. From here, we hope to continue developing the TUI crate.

In order to organize ourselves, we have created a temporary discord server. We have not yet determined with the community what will be our definitive communication medium.

Please make sure you read the updated contributing guidelines, especially if you are interested in working on a PR or issue opened in the previous repository.

Introduction

tui-rs is a Rust library to build rich terminal user interfaces and dashboards. It is heavily inspired by the Javascript library blessed-contrib and the Go library termui.

The library supports multiple backends:

The library is based on the principle of immediate rendering with intermediate buffers. This means that at each new frame you should build all widgets that are supposed to be part of the UI. While providing a great flexibility for rich and interactive UI, this may introduce overhead for highly dynamic content. So, the implementation try to minimize the number of ansi escapes sequences generated to draw the updated UI. In practice, given the speed of Rust the overhead rather comes from the terminal emulator than the library itself.

Moreover, the library does not provide any input handling nor any event system and you may rely on the previously cited libraries to achieve such features.

Rust version requirements

Since version 0.17.0, tui requires rustc version 1.59.0 or greater.

Documentation

The documentation can be found on docs.rs.

Demo

The demo shown in the gif can be run with all available backends.

# crossterm
cargo run --example demo --release -- --tick-rate 200
# termion
cargo run --example demo --no-default-features --features=termion --release -- --tick-rate 200

where tick-rate is the UI refresh rate in ms.

The UI code is in examples/demo/ui.rs while the application state is in examples/demo/app.rs.

If the user interface contains glyphs that are not displayed correctly by your terminal, you may want to run the demo without those symbols:

cargo run --example demo --release -- --tick-rate 200 --enhanced-graphics false

Widgets

Built in

The library comes with the following list of widgets:

Click on each item to see the source of the example. Run the examples with with cargo (e.g. to run the gauge example cargo run --example gauge), and quit by pressing q.

You can run all examples by running cargo make run-examples (require cargo-make that can be installed with cargo install cargo-make).

Third-party libraries, bootstrapping templates and widgets

  • ansi-to-tui — Convert ansi colored text to tui::text::Text
  • color-to-tui — Parse hex colors to tui::style::Color
  • rust-tui-template — A template for bootstrapping a Rust TUI application with Tui-rs & crossterm
  • simple-tui-rs — A simple example tui-rs app
  • tui-builder — Batteries-included MVC framework for Tui-rs + Crossterm apps
  • tui-clap — Use clap-rs together with Tui-rs
  • tui-log — Example of how to use logging with Tui-rs
  • tui-logger — Logger and Widget for Tui-rs
  • tui-realm — Tui-rs framework to build stateful applications with a React/Elm inspired approach
  • tui-realm-treeview — Treeview component for Tui-realm
  • tui tree widget — Tree Widget for Tui-rs
  • tui-windows — Tui-rs abstraction to handle multiple windows and their rendering
  • tui-textarea: Simple yet powerful multi-line text editor widget supporting several key shortcuts, undo/redo, text search, etc.
  • tui-rs-tree-widgets: Widget for tree data structures.
  • tui-input: TUI input library supporting multiple backends and tui-rs.

Apps using tui

  • adsb_deku/radar — Rust ADS-B decoder + TUI radar application
  • bandwhich — Terminal utility for displaying current network utilization by process, connection and remote IP/hostname
  • battleship.rs — A terminal battleship game in Rust
  • bottom — Yet another cross-platform graphical process/system monitor
  • conclusive — Command line client for Plausible Analytics
  • cotp — Trustworthy, encrypted, command-line TOTP/HOTP authenticator app with import functionality
  • cube timer — A tui-based Rubik's cube timer written in Rust
  • desed — Debugger for Sed: demystify and debug your sed scripts, from comfort of your terminal
  • diskonaut — Terminal disk space navigator
  • exhaust — Exhaust all your possibilities.. for the next coming exam
  • game-of-life-rs — Conway's Game of Life implemented in Rust and visualized with Tui-rs
  • gitui — Blazing fast terminal-ui for Git written in Rust
  • gpg-tui — Manage your GnuPG keys with ease!
  • gping — Ping, but with a graph
  • joshuto — Ranger-like terminal file manager written in Rust
  • kDash — A simple and fast dashboard for Kubernetes
  • kmon — Linux Kernel Manager and Activity Monitor
  • kubectl-watch — A kubectl plugin to provide a pretty delta change view of being watched kubernetes resources
  • minesweep — Sweep some mines for fun, and probably not for profit
  • oha — HTTP load generator, inspired by rakyll/hey with tui animation
  • oxker — a simple tui to view & control docker containers
  • poketex — A simple pokedex based on TUI
  • rrtop — Redis monitoring (top like) app
  • rust-sadari-cli — Sadari game based on terminal
  • rusty-krab-manager — Time-management TUI in Rust
  • spotify-tui — Spotify for the terminal written in Rust
  • taskwarrior-tui — A terminal user interface for Taskwarrior
  • termchat — Terminal chat through the LAN with video streaming and file transfer
  • termscp — A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/S3
  • tick-rs — Realtime ticker data in your terminal
  • tsuchita — Client-server notification center for dbus desktop notifications
  • tuinance — Display financial data on the terminal
  • vector — A lightweight, ultra-fast tool for building observability pipelines
  • xplr — A hackable, minimal, fast TUI file explorer
  • ytop — A TUI system monitor written in Rust (no longer maintained)
  • zenith — Sort of like top or htop but with zoom-able charts, CPU, GPU, network, and disk usage

Alternatives

You might want to checkout Cursive for an alternative solution to build text user interfaces in Rust.

License

MIT

Comments
  • fix(widget)!: List should not ignore empty string items

    fix(widget)!: List should not ignore empty string items

    Upstream: #688

    Description

    Fixes issue #680. Handles the case where a list item is created with an empty string, which is not split by the lines iterator.

    Testing guidelines

    New test can be ran with cargo test

    Checklist

    • [x] I have read the contributing guidelines.
    • [x] I have added relevant tests.
    • [x] I have documented all new additions.
    bug 
    opened by orhun 6
  • Open the discussions tab

    Open the discussions tab

    First of all, thank you for making this project revive. I'm suggesting to enable the discussions on this repository. Indeed, people may want to ask questions, share news of this project, and perhaps announce that the original owner came back. Well, it will be a great opportunity to exchange about this project.

    enhancement 
    opened by antoninhrlt 4
  • Bump crossterm to 0.26 with CI fix

    Bump crossterm to 0.26 with CI fix

    Upstream: #689

    Description

    Testing guidelines

    I checked all examples by cargo run --example {example-name} and confirmed they work on iTerm2 on my Mac machine.

    Checklist

    • [x] I have read the contributing guidelines.
    • [x] I have added relevant tests. (Since this PR just upgrading existing dependency, no tests need to be added)
    • [x] I have documented all new additions.

    Description

    crossterm v0.26.0 was released recently. And some people are starting to use the latest version. Since this crate requires crossterm 0.25, both 0.25 and 0.26 are mixed in user's project when the user depends on crossterm directly. I actually saw an issue around this in my tui-textarea project: https://github.com/rhysd/tui-textarea/issues/9

    The best way to solve the issue is to follow the latest crossterm version by tui crate. I checked the release note and tui crate. Breaking changes seem not relevant to tui crate.

    This is a breaking change due to MSRV bump from 1.56 to 1.58. crossterm 0.26 is using inline format arguments feature and it requires 1.58.

    Build 
    opened by orhun 4
  • Significantly improve `Layout` performance

    Significantly improve `Layout` performance

    Upstream: #585

    Main changes

    I found that the current implementation of Layout was very heavy on allocations and clones, especially considering you're expected to use it plus the split() function every frame. So, I made some changes to allow Layout to work more on the stack.

    This is what I changed Layout to

    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
    pub struct Layout<'a> {
        direction: Direction,
        margin: Margin,
        constraints: &'a [Constraint],
        /// Whether the last chunk of the computed layout should be expanded to fill the available
        /// space.
        expand_to_fill: bool,
    }
    

    This replaces the constraints field with a reference to a slice, instead of a Vec<Constraint>. Considering that most implementations using Layout use static arrays anyway, this seemed like a no brainer, until I tried to use the LAYOUT_CAHCE. It is impossible to store this new Layout inside of the LAYOUT_CACHE because that would require that you borrow the given Layout for 'static. My solution to the problem was only storing the hash of the Layout into the cache as opposed to moving the entire Layout.

    macro_rules! hash_layout {
        ($self:expr, $area:expr) => {{
            let mut to_hash = ahash::AHasher::default();
            $area.hash(&mut to_hash);
            $self.margin.hash(&mut to_hash);
            $self.expand_to_fill.hash(&mut to_hash);
            $self.direction.hash(&mut to_hash);
            $self.constraints.iter().copied().for_each(|f| match f {
                Constraint::Max(max) => to_hash.write_u16(max),
                Constraint::Min(min) => to_hash.write_u16(min),
                Constraint::Ratio(left, right) => {
                    to_hash.write_u32(left);
                    to_hash.write_u32(right);
                }
                Constraint::Length(length) => to_hash.write_u16(length),
                Constraint::Percentage(percentage) => to_hash.write_u16(percentage),
            });
            to_hash.finish()
        }};
    }
    
    #[derive(Clone, Copy)]
    #[repr(transparent)]
    struct CustomHash(u64);
    
    impl Default for CustomHash {
        #[inline]
        fn default() -> Self {
            Self(0)
        }
    }
    
    impl std::hash::Hasher for CustomHash {
        #[inline]
        fn finish(&self) -> u64 {
            self.0
        }
    
        #[inline]
        fn write(&mut self, _: &[u8]) {
            panic!("unsupported operation");
        }
    
        #[inline]
        fn write_u64(&mut self, i: u64) {
            self.0 = i;
        }
    }
    
    thread_local! {
        static LAYOUT_CACHE: RefCell<HashMap<u64, Vec<Rect>, BuildHasherDefault<CustomHash>>> = RefCell::new(HashMap::default());
    }
    
    pub fn split(&self, area: Rect) -> Vec<Rect> {
        // TODO: Maybe use a fixed size cache ?
        LAYOUT_CACHE.with(|c| {
            c.borrow_mut()
                .entry(hash_layout!(self, area))
                .or_insert_with(|| split(area, self))
                .clone()
        })
    }
    

    This is the code I used for storing the layout. Here is a breakdown

    • First I create a hasher using ahash, It's not critical that ahash be the hashing algorithm (the default hasher works as well). However, considering how often the split() function will be run, I think it's worth the sacrifice of one extra dependency.
    • After creating the hasher, I feed it the area parameter, and then each field of the Layout one by one. cargo +nightly bench insisted that this was faster than simply running self.hash(&mut to_hash);
    • After computing the hash of area + self, I use the final value as the final key into the LAYOUT_CAHCE.
    • Because LAYOUT_CACHE uses CustomHash as it's RandomState, the hash computed by ahash is simply passed through and no further hashing is done. There's no point in hashing a hash.
    • Finally, the resulting Vec<Rect> is either grabbed from the LAYOUT_CACHE or computed, and then cloned to bypass the reference created by the HashMap

    Benchmarks

    I did some benchmarks to see just how much my changes effected performance. This was my benchmark

    #[bench]
    fn bench_vertical_split_by_height(b: &mut test::Bencher) {
        let target = Rect {
            x: 2,
            y: 2,
            width: 10,
            height: 10,
        };
    
        let layout = Layout::default()
            .direction(Direction::Vertical)
            .constraints(
                [
                    Constraint::Percentage(10),
                    Constraint::Max(5),
                    Constraint::Min(1),
                ]
                .as_ref(),
            );
    
        b.iter(|| layout.split(target));
    }
    

    When I benchmarked the original implementation and mine, these were my results. (top one is my implementation).

    test layout::tests::bench_vertical_split_by_height ... bench:          89 ns/iter (+/- 5)
    test layout::tests::bench_vertical_split_by_height ... bench:         243 ns/iter (+/- 2)
    

    My implementation seems to be ~3x faster than the original implementation.

    Swapping out ahash with the default hasher (std::collections::hash_map::DefaultHasher::default()) gave me this result

    test layout::tests::bench_vertical_split_by_height ... bench:         148 ns/iter (+/- 10)
    

    Smaller changes

    I noticed that most of the methods inside of this module (layout) were very simple and small, so I made them const and #[inline]ed them.

    Pre-requisites

    All of my changes passed the unit tests and ran the examples.

    Thanks for considering my PR, - StratusFearMe21

    enhancement 
    opened by orhun 4
  • Question about the fork

    Question about the fork

    Hello all, I've been following https://github.com/fdehau/tui-rs/issues/654 with interest!

    I maintain an RSS/Atom reader called Russ that is built on tui-rs (please feel free to add it to the list of projects using tui-rs, as I am extremely pleased with and grateful for tui-rs).

    My question is this: given the fork, with regard to bug reports/feature requests/PRs, should I file those here, or upstream? Is the plan to merge the work in this fork upstream, or have this fork eventually replace upstream? Thank you to everyone actively working to keep tui-rs going, it's such a lovely project.

    question 
    opened by ckampfe 2
  • fix(ci): fix deprecation warnings on CI

    fix(ci): fix deprecation warnings on CI

    Description

    Currently CI reports 3 kinds of deprecation warnings:

    • Node.js 12 actions are deprecated. Please update the following actions to use Node.js 16: hecrj/setup-rust-action@967aec96c6a27a0ce15c1dac3aaba332d60565e2, actions/cache@v2.
    • The set-output command is deprecated and will be disabled soon. Please upgrade to using Environment Files.
    • The save-state command is deprecated and will be disabled soon. Please upgrade to using Environment Files.

    This PR fixes all the warnings.

    Testing guidelines

    I checked all warnings are no longer reported on my forked repository: https://github.com/rhysd/tui-rs-revival/actions/runs/4191656530

    Checklist

    • [x] I have read the contributing guidelines.
    • [x] I have added relevant tests.
    • [x] I have documented all new additions.
    opened by rhysd 1
  • docs(readme): add poketex to 'apps using tui' in README

    docs(readme): add poketex to 'apps using tui' in README

    Description

    Add poketex to 'apps using tui' in README.

    Testing guidelines

    Checklist

    • [x] I have read the contributing guidelines.
    • [x] I have added relevant tests.
    • [x] I have documented all new additions.
    opened by ckaznable 0
  • fix(doc): add 3rd party libraries accidentally removed at #21

    fix(doc): add 3rd party libraries accidentally removed at #21

    Description

    Links to some 3rd party libraries including my tui-textarea crate were accidentally removed at #21. This PR fixes them.

    Testing guidelines

    Nothing to test since this is a small document change.

    Checklist

    • [x] I have read the contributing guidelines.
    • [x] I have added relevant tests.
    • [x] I have documented all new additions.
    opened by rhysd 0
  • feat(ci): add MacOS to CI

    feat(ci): add MacOS to CI

    Description

    This PR adds macOS to CI as one of major platforms which should be supported by tui crate. The CI workflow was also parametrized to reduce duplicate steps for each OS.

    Testing guidelines

    I confirmed all jobs passed in my forked repository: https://github.com/rhysd/tui-rs-revival/actions/runs/4200844754

    Checklist

    • [x] I have read the contributing guidelines.
    • [x] I have added relevant tests.
    • [x] I have documented all new additions.
    opened by rhysd 0
  • chore(ci): re-enable clippy on CI

    chore(ci): re-enable clippy on CI

    Description

    Fixes #53. This PR re-enables clippy on CI, which was disabled at #51.

    Testing guidelines

    I confirmed all checks passed in my forked repository: https://github.com/rhysd/tui-rs-revival/actions/runs/4193808784/jobs/7271163234

    Checklist

    • [x] I have read the contributing guidelines.
    • [x] I have added relevant tests.
    • [x] I have documented all new additions.
    opened by rhysd 0
  • chore: update `rust-version` to 1.59 in Cargo.toml

    chore: update `rust-version` to 1.59 in Cargo.toml

    Description

    #51 bumped MSRV, but rust-version field of Cargo.toml is still 1.56.1.

    Testing guidelines

    Since this only changes the field in Cargo.toml, I checked only cargo clippy

    Checklist

    • [x] I have read the contributing guidelines.
    • [x] I have added relevant tests.
    • [x] I have documented all new additions.
    opened by rhysd 0
  • unicode-width and emojis

    unicode-width and emojis

    I'm not a user of helix or tui. But I found this helix issue and thought I'd mention it here: https://github.com/helix-editor/helix/issues/6012

    Helix uses a fork of a subset of tui. Notably the core of Buffer is basically the same (AFAIK).

    I'm pretty sure that this bug is shared by everything using the tui-style Buffer. AFAIK, the reason is that unicode-width doesn't (or can't?) report the column width for emojis. See readme and issues: https://github.com/unicode-rs/unicode-width

    I won't have anything to contribute here, or any personal interest, really. Perhaps you should get into contact with the helix team for this, as this effects both.

    bug 
    opened by markus-bauer 0
  • better safe shared layout cache

    better safe shared layout cache

    Description

    https://github.com/tui-rs-revival/tui-rs-revival/pull/22#issuecomment-1427143924 introduced the idea to return &'static [Rect] on Layout::split using unsafe, but we can use a safe abstraction here instead with Rc.

    Testing guidelines

    Using the benchmark introduced in #22, I get these results (master/this respectively)

    test layout::tests::bench_vertical_split_by_height ... bench: 129 ns/iter (+/- 6)
    test layout::tests::bench_vertical_split_by_height ... bench: 100 ns/iter (+/- 3)
    

    Checklist

    • [X] I have read the contributing guidelines.
    • [X] I have added relevant tests.
    • [ ] I have documented all new additions.
    opened by conradludgate 0
  • Switch to `main` branch

    Switch to `main` branch

    Problem

    The word master has been deprecated in favor of main branch, but this repo defaults to master branch.

    Solution

    Switch to main branch.

    Note: the prs should auto update to main branch, but might take some time to update.

    enhancement 
    opened by sayanarijit 0
  • Adopt conventional commits

    Adopt conventional commits

    Problem

    Right now there isn't a specific convention for commits and adopting conventional commits would be nice.

    Solution

    Utilize a tool for checking the PRs for conventional commits. Such as action-semantic-pull-request or cocogitto.

    Alternatives

    None.

    Additional context

    • https://marcodenisi.dev/en/blog/why-you-should-use-conventional-commits/
    enhancement 
    opened by orhun 1
  • docs: add some lines of documentation to clear doubts

    docs: add some lines of documentation to clear doubts

    Upstream: #677

    Description

    It is a PR just to resolve issue #352

    Add a few lines to explain how to define the coordinates

    Testing guidelines

    Just test it using VS Code

    Checklist

    • [X] I have read the contributing guidelines.
    • [X] I have added relevant tests.
    • [X] I have documented all new additions.
    documentation 
    opened by orhun 4
Firefox used to have this feature a while back (from Firefox 11 to 46) and it is so good, that I feel it needs revival.

3D WebPage Inspector By: Seanpm2001, Et; Al. Top README.md Read this article in a different language Sorted by: A-Z Sorting options unavailable ( af A

Sean P. Myrick V19.1.7.2 3 Nov 10, 2022
A template for bootstrapping a Rust TUI application with tui-rs & crossterm

rust-tui-template A template for bootstrapping a Rust TUI application with tui-rs & crossterm. tui-rs The library is based on the principle of immedia

Orhun Parmaksız 72 Dec 31, 2022
SKYULL is a command-line interface (CLI) in development that creates REST API project structure templates with the aim of making it easy and fast to start a new project.

SKYULL is a command-line interface (CLI) in development that creates REST API project structure templates with the aim of making it easy and fast to start a new project. With just a few primary configurations, such as project name, you can get started quickly.

Gabriel Michaliszen 4 May 9, 2023
A hackable, minimal, fast TUI file explorer, stealing ideas from nnn and fzf.

xplr A hackable, minimal, fast TUI file explorer, stealing ideas from nnn and fzf. [Quickstart] [Features] [Plugins] [Documentation] [Upgrade Guide] [

Arijit Basu 2.6k Jan 1, 2023
Rust TUI client for steamcmd

Steam TUI About Just a simple TUI client for steamcmd. Allows for the graphical launching, updating, and downloading of steam games through a simple t

Dylan Madisetti 599 Jan 9, 2023
Another TUI based system monitor, this time in Rust!

Another TUI based system monitor, this time in Rust!

Caleb Bassi 2.1k Jan 3, 2023
A user-friendly TUI client for Matrix written in Rust!

Konoha A user-friendly TUI client for Matrix written in Rust! Notice: The client is currently not usable and is only hosted on GitHub for version cont

L3af 9 Jan 5, 2022
TUI image viewer

Picterm TUI image viewer install $ cargo install picterm or $ git clone https://github.com/ksk001100/picterm $ cd picterm $ cargo install --path . usa

Keisuke Toyota 41 Dec 31, 2022
A cli prepared with TUI that facilitates your operations.

⚠️ For linux only ⚠️ Helper CLI A cli prepared with TUI that facilitates your operations. Click me to learn more about the theme system. If you just w

Yiğit 4 Feb 1, 2022
A tui to test regexes on the rust regex crate

regex-tui Structure src/ ├── app.rs -> holds the states and renders the widgets ├── event.rs -> handles the terminal events (key press, mouse cl

null 1 Oct 21, 2021
Parse hex colors to tui::style::Color

Color -> Tui Parse hex colors to tui rgb colors #c3f111 -> Color::Rgb(195,241,17) Note that the indexed colors are NOT HEX #142 -> Color::Indexed(142)

Uttarayan Mondal 1 Nov 8, 2021
TUI input library supporting multiple backends

tui-input WARNING: Most of the functionality is only human tested. A TUI input library supporting multiple backends. This crate can be used with tui-r

Arijit Basu 36 Dec 19, 2022
2048 in `tui`, just for fun

TUI 2048 - Have a relax at anytime - ?? ^_^ How to run repo clone this repo, git clone https://github.com/WanderHuang/game-2048-tui.git cd game-2048-t

wander 43 Dec 16, 2022
Tiny color conversion library for TUI application builders

Definition of ANSI, RGB and HSL color types and all the conversions between them. There are many other color conversion crates. This one may be useful

Canop 8 Dec 15, 2022
FastSSH is a TUI that allows you to quickly connect to your services by navigating through your SSH config.

Connect quickly to your services ?? FastSSH is a TUI that allows you to quickly connect to your services by navigating through your SSH config. Instal

Julien 85 Dec 14, 2022
Lemurs - A lightweight TUI display/login manager written in Rust 🐒

Lemurs ?? A TUI Display/Login Manager written in Rust WIP: Whilst the project is working and installable, there are still a lot of bugs and limitation

Gijs Burghoorn 136 Jan 1, 2023
Playground for 2D EKF-SLAM as TUI in Rust

SLAMme.RS Playground for 2D EKF-SLAM as TUI in Rust Installation $ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # install RUST $ su

Thore Goll 1 Jan 14, 2022
TimeKnight is a neat little TUI-based timer app I use in conjunction with a task tracker

TimeKnight is a neat little TUI-based timer app I use in conjunction with a task tracker. It's kind of a secret sauce for productivity (particularly if you have ADHD or have a ridiculously overactive brain).

Monomadic 1 Feb 8, 2022
Rust TUI library - Clipping region is a set of min/max x/y values applied to the existing region

TinyBit Clipping region is a set of min/max x/y values applied to the existing region A TUI lib This is not yet production ready T O D O TODO: bugs: T

Togglebit 13 May 3, 2022