Skip to content

Tui

In order for your application to present as a terminal user interface, you need to do 2 things:

  1. Enter raw mode: This is required to get key or mouse inputs from a user
  2. Enter the alternate screen: This is required to preserve the state of the user’s current terminal contents

Define a couple of functions to init and restore the terminal state:

src/tui.rs
use ratatui::prelude::{CrosstermBackend, Terminal};
pub type Tui = Terminal<CrosstermBackend<std::io::Stdout>>;
pub fn init() -> color_eyre::Result<Tui> {
use crossterm::terminal::EnterAlternateScreen;
crossterm::terminal::enable_raw_mode()?;
crossterm::execute!(std::io::stdout(), EnterAlternateScreen)?;
let mut terminal = Terminal::new(CrosstermBackend::new(std::io::stdout()))?;
terminal.clear()?;
terminal.hide_cursor()?;
Ok(terminal)
}
pub fn restore() -> color_eyre::Result<()> {
use crossterm::terminal::LeaveAlternateScreen;
crossterm::execute!(std::io::stdout(), LeaveAlternateScreen)?;
crossterm::terminal::disable_raw_mode()?;
Ok(())
}

init returns the ratatui::terminal::Terminal struct.

After calling init, the terminal is now in the appropriate state to make your application behave as a TUI application. Just have to make sure we call tui::restore() at the end of your program.

Let’s update main.rs to the following:

src/main.rs
mod crates_io_api_helper;
mod tui;
#[tokio::main]
async fn main() -> color_eyre::Result<()> {
let mut tui = tui::init()?;
tui.draw(|frame| {
frame.render_widget(
ratatui::widgets::Paragraph::new("hello world"),
frame.size(),
)
})?;
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
tui::restore()?;
Ok(())
}

If you run this using cargo run, your terminal should enter the alternate screen, display the "hello world" Paragraph widget, sleep for 5 seconds and reset the terminal back to the normal state.

Your file structure should now look like this:

.
├── Cargo.lock
├── Cargo.toml
└── src
├── crates_io_api_helper.rs
├── main.rs
└── tui.rs

Next, we will handle errors.