mirror of
https://github.com/ratatui/ratatui.git
synced 2025-09-28 05:21:23 +00:00
feat: add ratatui::run() method (#1707)
This introduces a new `ratatui::run()` method which runs a closure with a terminal initialized with reasonable defaults for most applications. This calls `ratatui::init()` before running the closure and `ratatui::restore()` after the closure completes, and returns the result of the closure. A minimal hello world example using the new `ratatui::run()` method: ```rust fn main() -> Result<(), Box<dyn std::error::Error>> { ratatui::run(|terminal| { loop { terminal.draw(|frame| frame.render_widget("Hello World!", frame.area()))?; if crossterm::event::read()?.is_key_press() { break Ok(()); } } }) } ``` Of course, this also works both with apps that use free methods and structs: ```rust fn run(terminal: &mut DefaultTerminal) -> Result<(), AppError> { ... } ratatui::run(run)?; ``` ```rust struct App { ... } impl App { fn new() -> Self { ... } fn run(mut self, terminal: &mut DefaultTerminal) -> Result<(), AppError> { ... } } ratatui::run(|terminal| App::new().run(terminal))?; ```
This commit is contained in:
parent
b6fbfcdd1c
commit
7bc78bca1b
@ -21,10 +21,7 @@ use ratatui::widgets::{Widget, WidgetRef};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = App::default().run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
ratatui::run(|terminal| App::default().run(terminal))
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@ -36,15 +33,15 @@ struct App {
|
||||
}
|
||||
|
||||
impl App {
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
fn run(mut self, terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
while !self.should_quit {
|
||||
self.draw(&mut terminal)?;
|
||||
self.render(terminal)?;
|
||||
self.handle_events()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw(&mut self, tui: &mut DefaultTerminal) -> Result<()> {
|
||||
fn render(&mut self, tui: &mut DefaultTerminal) -> Result<()> {
|
||||
tui.draw(|frame| frame.render_widget(self, frame.area()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -22,21 +22,18 @@ use time::{Date, Month, OffsetDateTime};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
ratatui::run(run)
|
||||
}
|
||||
|
||||
/// Run the application.
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
fn run(terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
let mut selected_date = OffsetDateTime::now_local()?.date();
|
||||
let mut calendar_style = StyledCalendar::Default;
|
||||
loop {
|
||||
terminal.draw(|frame| render(frame, calendar_style, selected_date))?;
|
||||
if let Some(key) = event::read()?.as_key_press_event() {
|
||||
match key.code {
|
||||
KeyCode::Char('q') | KeyCode::Esc => return Ok(()),
|
||||
KeyCode::Char('q') => break Ok(()),
|
||||
KeyCode::Char('s') => calendar_style = calendar_style.next(),
|
||||
KeyCode::Char('n') | KeyCode::Tab => selected_date = next_month(selected_date),
|
||||
KeyCode::Char('p') | KeyCode::BackTab => selected_date = prev_month(selected_date),
|
||||
|
@ -21,10 +21,7 @@ use ratatui::{DefaultTerminal, Frame};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = App::new().run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
ratatui::run(|terminal| App::new().run(terminal))
|
||||
}
|
||||
|
||||
struct App {
|
||||
@ -78,7 +75,7 @@ impl App {
|
||||
}
|
||||
}
|
||||
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
fn run(mut self, terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
let tick_rate = Duration::from_millis(250);
|
||||
let mut last_tick = Instant::now();
|
||||
loop {
|
||||
|
@ -11,40 +11,35 @@
|
||||
use color_eyre::Result;
|
||||
use crossterm::event;
|
||||
use itertools::Itertools;
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Alignment, Constraint, Layout, Rect};
|
||||
use ratatui::style::{Color, Style, Stylize};
|
||||
use ratatui::text::Line;
|
||||
use ratatui::widgets::{Block, Borders, Paragraph};
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
}
|
||||
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
return Ok(());
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn render(frame: &mut Frame) {
|
||||
let layout = Layout::vertical([
|
||||
let [named, indexed_colors, indexed_greys] = Layout::vertical([
|
||||
Constraint::Length(30),
|
||||
Constraint::Length(17),
|
||||
Constraint::Length(2),
|
||||
])
|
||||
.split(frame.area());
|
||||
.areas(frame.area());
|
||||
|
||||
render_named_colors(frame, layout[0]);
|
||||
render_indexed_colors(frame, layout[1]);
|
||||
render_indexed_grayscale(frame, layout[2]);
|
||||
render_named_colors(frame, named);
|
||||
render_indexed_colors(frame, indexed_colors);
|
||||
render_indexed_grayscale(frame, indexed_greys);
|
||||
}
|
||||
|
||||
const NAMED_COLORS: [Color; 16] = [
|
||||
|
@ -31,10 +31,7 @@ use ratatui::widgets::Widget;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = App::default().run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
ratatui::run(|terminal| App::default().run(terminal))
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@ -91,7 +88,7 @@ impl App {
|
||||
/// Run the app
|
||||
///
|
||||
/// This is the main event loop for the app.
|
||||
pub fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
pub fn run(mut self, terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
while self.is_running() {
|
||||
terminal.draw(|frame| frame.render_widget(&mut self, frame.area()))?;
|
||||
self.handle_events()?;
|
||||
|
@ -24,10 +24,7 @@ use strum::{Display, EnumIter, FromRepr};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = App::default().run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
ratatui::run(|terminal| App::default().run(terminal))
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@ -82,7 +79,7 @@ struct SpacerBlock;
|
||||
|
||||
// App behaviour
|
||||
impl App {
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
fn run(mut self, terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
self.insert_test_defaults();
|
||||
|
||||
while self.is_running() {
|
||||
|
@ -36,10 +36,7 @@ const FILL_COLOR: Color = tailwind::SLATE.c950;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = App::default().run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
ratatui::run(|terminal| App::default().run(terminal))
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
@ -72,7 +69,7 @@ enum AppState {
|
||||
}
|
||||
|
||||
impl App {
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
fn run(mut self, terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
self.update_max_scroll_offset();
|
||||
while self.is_running() {
|
||||
terminal.draw(|frame| frame.render_widget(self, frame.area()))?;
|
||||
|
@ -51,7 +51,7 @@ where
|
||||
{
|
||||
let mut last_tick = Instant::now();
|
||||
loop {
|
||||
terminal.draw(|frame| ui::draw(frame, &mut app))?;
|
||||
terminal.draw(|frame| ui::render(frame, &mut app))?;
|
||||
|
||||
let timeout = tick_rate.saturating_sub(last_tick.elapsed());
|
||||
if !event::poll(timeout)? {
|
||||
|
@ -42,7 +42,7 @@ where
|
||||
{
|
||||
let events = events(tick_rate);
|
||||
loop {
|
||||
terminal.draw(|frame| ui::draw(frame, &mut app))?;
|
||||
terminal.draw(|frame| ui::render(frame, &mut app))?;
|
||||
|
||||
match events.recv()? {
|
||||
Event::Input(key) => match key {
|
||||
|
@ -36,7 +36,7 @@ fn run_app(
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let mut last_tick = Instant::now();
|
||||
loop {
|
||||
terminal.draw(|frame| ui::draw(frame, &mut app))?;
|
||||
terminal.draw(|frame| ui::render(frame, &mut app))?;
|
||||
|
||||
let timeout = tick_rate.saturating_sub(last_tick.elapsed());
|
||||
if let Some(input) = terminal
|
||||
|
@ -10,7 +10,7 @@ use ratatui::{Frame, symbols};
|
||||
|
||||
use crate::app::App;
|
||||
|
||||
pub fn draw(frame: &mut Frame, app: &mut App) {
|
||||
pub fn render(frame: &mut Frame, app: &mut App) {
|
||||
let chunks = Layout::vertical([Constraint::Length(3), Constraint::Min(0)]).split(frame.area());
|
||||
let tabs = app
|
||||
.tabs
|
||||
|
@ -27,10 +27,7 @@ use strum::{Display, EnumIter, FromRepr, IntoEnumIterator};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = App::default().run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
ratatui::run(|terminal| App::default().run(terminal))
|
||||
}
|
||||
|
||||
const EXAMPLE_DATA: &[(&str, &[Constraint])] = &[
|
||||
@ -160,7 +157,7 @@ enum SelectedTab {
|
||||
}
|
||||
|
||||
impl App {
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
fn run(mut self, terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
// increase the layout cache to account for the number of layout events. This ensures that
|
||||
// layout is not generally reprocessed on every frame (which would lead to possible janky
|
||||
// results when there are more than one possible solution to the requested layout). This
|
||||
|
@ -43,14 +43,11 @@ enum AppState {
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = App::default().run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
ratatui::run(|terminal| App::default().run(terminal))
|
||||
}
|
||||
|
||||
impl App {
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
fn run(mut self, terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
while self.state != AppState::Quitting {
|
||||
terminal.draw(|frame| frame.render_widget(&self, frame.area()))?;
|
||||
self.handle_events()?;
|
||||
|
@ -21,17 +21,14 @@ use ratatui::{DefaultTerminal, Frame};
|
||||
/// and exits when the user presses 'q'.
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?; // augment errors / panics with easy to read messages
|
||||
let terminal = ratatui::init();
|
||||
let app_result = run(terminal).context("app loop failed");
|
||||
ratatui::restore();
|
||||
app_result
|
||||
ratatui::run(run).context("failed to run app")
|
||||
}
|
||||
|
||||
/// Run the application loop. This is where you would handle events and update the application
|
||||
/// state. This example exits when the user presses 'q'. Other styles of application loops are
|
||||
/// possible, for example, you could have multiple application states and switch between them based
|
||||
/// on events, or you could have a single application state and update it based on events.
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
fn run(terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if should_quit()? {
|
||||
|
@ -7,9 +7,8 @@
|
||||
/// [`latest`]: https://github.com/ratatui/ratatui/tree/latest
|
||||
/// [OSC 8]: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
|
||||
use color_eyre::Result;
|
||||
use crossterm::event::{self, KeyCode};
|
||||
use crossterm::event;
|
||||
use itertools::Itertools;
|
||||
use ratatui::DefaultTerminal;
|
||||
use ratatui::buffer::Buffer;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::style::Stylize;
|
||||
@ -18,35 +17,18 @@ use ratatui::widgets::Widget;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = App::new().run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
}
|
||||
|
||||
struct App {
|
||||
hyperlink: Hyperlink<'static>,
|
||||
}
|
||||
let text = Line::from(vec!["Example ".into(), "hyperlink".blue()]);
|
||||
let hyperlink = Hyperlink::new(text, "https://example.com");
|
||||
|
||||
impl App {
|
||||
fn new() -> Self {
|
||||
let text = Line::from(vec!["Example ".into(), "hyperlink".blue()]);
|
||||
let hyperlink = Hyperlink::new(text, "https://example.com");
|
||||
Self { hyperlink }
|
||||
}
|
||||
|
||||
fn run(self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(|frame| frame.render_widget(&self.hyperlink, frame.area()))?;
|
||||
if event::read()?
|
||||
.as_key_press_event()
|
||||
.is_some_and(|key| matches!(key.code, KeyCode::Char('q') | KeyCode::Esc))
|
||||
{
|
||||
break;
|
||||
terminal.draw(|frame| frame.render_widget(&hyperlink, frame.area()))?;
|
||||
if event::read()?.is_key_press() {
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// A hyperlink widget that renders a hyperlink in the terminal using [OSC 8].
|
||||
|
@ -26,12 +26,8 @@ use serde::Serialize;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = App::default().run(terminal);
|
||||
ratatui::restore();
|
||||
|
||||
// serialize the form to JSON if the user submitted it, otherwise print "Canceled"
|
||||
match result {
|
||||
match ratatui::run(|terminal| App::default().run(terminal)) {
|
||||
Ok(Some(form)) => println!("{}", serde_json::to_string_pretty(&form)?),
|
||||
Ok(None) => println!("Canceled"),
|
||||
Err(err) => eprintln!("{err}"),
|
||||
@ -54,7 +50,7 @@ enum AppState {
|
||||
}
|
||||
|
||||
impl App {
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<Option<InputForm>> {
|
||||
fn run(mut self, terminal: &mut DefaultTerminal) -> Result<Option<InputForm>> {
|
||||
while self.state == AppState::Running {
|
||||
terminal.draw(|frame| self.render(frame))?;
|
||||
self.handle_events()?;
|
||||
|
@ -1,28 +1,23 @@
|
||||
/// A minimal example of a Ratatui application.
|
||||
///
|
||||
/// This is a bare minimum example. There are many approaches to running an application loop,
|
||||
/// so this is not meant to be prescriptive. See the [examples] folder for more complete
|
||||
/// examples. In particular, the [hello-world] example is a good starting point.
|
||||
///
|
||||
/// This example runs with the Ratatui library code in the branch that you are currently
|
||||
/// reading. See the [`latest`] branch for the code which works with the most recent Ratatui
|
||||
/// release.
|
||||
///
|
||||
/// [`latest`]: https://github.com/ratatui/ratatui/tree/latest
|
||||
/// [examples]: https://github.com/ratatui/ratatui/blob/main/examples
|
||||
/// [hello-world]: https://github.com/ratatui/ratatui/blob/main/examples/apps/hello-world
|
||||
use crossterm::event;
|
||||
use ratatui::text::Text;
|
||||
|
||||
fn main() {
|
||||
let mut terminal = ratatui::init();
|
||||
loop {
|
||||
terminal
|
||||
.draw(|frame| frame.render_widget(Text::raw("Hello World!"), frame.area()))
|
||||
.expect("failed to draw frame");
|
||||
if event::read().expect("failed to read event").is_key_press() {
|
||||
break;
|
||||
//! A minimal example of a Ratatui application.
|
||||
//!
|
||||
//! This is a bare minimum example. There are many approaches to running an application loop,
|
||||
//! so this is not meant to be prescriptive. See the [examples] folder for more complete
|
||||
//! examples. In particular, the [hello-world] example is a good starting point.
|
||||
//!
|
||||
//! This example runs with the Ratatui library code in the branch that you are currently
|
||||
//! reading. See the [`latest`] branch for the code which works with the most recent Ratatui
|
||||
//! release.
|
||||
//!
|
||||
//! [`latest`]: https://github.com/ratatui/ratatui/tree/latest
|
||||
//! [examples]: https://github.com/ratatui/ratatui/blob/main/examples
|
||||
//! [hello-world]: https://github.com/ratatui/ratatui/blob/main/examples/apps/hello-world
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(|frame| frame.render_widget("Hello World!", frame.area()))?;
|
||||
if crossterm::event::read()?.is_key_press() {
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
ratatui::restore();
|
||||
})
|
||||
}
|
||||
|
@ -12,29 +12,24 @@ use std::{error::Error, iter::once, result};
|
||||
|
||||
use crossterm::event;
|
||||
use itertools::Itertools;
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Constraint, Layout};
|
||||
use ratatui::style::{Color, Modifier, Style, Stylize};
|
||||
use ratatui::text::Line;
|
||||
use ratatui::widgets::Paragraph;
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
|
||||
type Result<T> = result::Result<T, Box<dyn Error>>;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
}
|
||||
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
return Ok(());
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn render(frame: &mut Frame) {
|
||||
|
@ -21,10 +21,7 @@ use ratatui::{DefaultTerminal, Frame, symbols};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = MouseDrawingApp::default().run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
ratatui::run(|terminal| MouseDrawingApp::default().run(terminal))
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@ -40,7 +37,7 @@ struct MouseDrawingApp {
|
||||
}
|
||||
|
||||
impl MouseDrawingApp {
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
fn run(mut self, terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
execute!(std::io::stdout(), EnableMouseCapture)?;
|
||||
while !self.should_exit {
|
||||
terminal.draw(|frame| self.render(frame))?;
|
||||
|
@ -31,69 +31,58 @@
|
||||
/// [Color Eyre recipe]: https://ratatui.rs/recipes/apps/color-eyre
|
||||
use color_eyre::{Result, eyre::bail};
|
||||
use crossterm::event::{self, KeyCode};
|
||||
use ratatui::Frame;
|
||||
use ratatui::text::Line;
|
||||
use ratatui::widgets::{Block, Paragraph};
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum PanicHandlerState {
|
||||
Enabled,
|
||||
Disabled,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = App::new().run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
}
|
||||
struct App {
|
||||
hook_enabled: bool,
|
||||
}
|
||||
|
||||
impl App {
|
||||
const fn new() -> Self {
|
||||
Self { hook_enabled: true }
|
||||
}
|
||||
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
let mut panic_hook_state = PanicHandlerState::Enabled;
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(|frame| self.render(frame))?;
|
||||
|
||||
terminal.draw(|frame| render(frame, &panic_hook_state))?;
|
||||
if let Some(key) = event::read()?.as_key_press_event() {
|
||||
match key.code {
|
||||
KeyCode::Char('p') => panic!("intentional demo panic"),
|
||||
KeyCode::Char('e') => bail!("intentional demo error"),
|
||||
KeyCode::Char('h') => {
|
||||
let _ = std::panic::take_hook();
|
||||
self.hook_enabled = false;
|
||||
panic_hook_state = PanicHandlerState::Disabled;
|
||||
}
|
||||
KeyCode::Char('q') => return Ok(()),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&self, frame: &mut Frame) {
|
||||
let text = vec![
|
||||
if self.hook_enabled {
|
||||
Line::from("HOOK IS CURRENTLY **ENABLED**")
|
||||
} else {
|
||||
Line::from("HOOK IS CURRENTLY **DISABLED**")
|
||||
},
|
||||
Line::from(""),
|
||||
Line::from("Press `p` to cause a panic"),
|
||||
Line::from("Press `e` to cause an error"),
|
||||
Line::from("Press `h` to disable the panic hook"),
|
||||
Line::from("Press `q` to quit"),
|
||||
Line::from(""),
|
||||
Line::from("When your app panics without a panic hook, you will likely have to"),
|
||||
Line::from("reset your terminal afterwards with the `reset` command"),
|
||||
Line::from(""),
|
||||
Line::from("Try first with the panic handler enabled, and then with it disabled"),
|
||||
Line::from("to see the difference"),
|
||||
];
|
||||
|
||||
let paragraph = Paragraph::new(text)
|
||||
.block(Block::bordered().title("Panic Handler Demo"))
|
||||
.centered();
|
||||
|
||||
frame.render_widget(paragraph, frame.area());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn render(frame: &mut Frame, state: &PanicHandlerState) {
|
||||
let text = vec![
|
||||
Line::from(format!("Panic hook is currently: {state:?}")),
|
||||
Line::from(""),
|
||||
Line::from("Press `p` to cause a panic"),
|
||||
Line::from("Press `e` to cause an error"),
|
||||
Line::from("Press `h` to disable the panic hook"),
|
||||
Line::from("Press `q` to quit"),
|
||||
Line::from(""),
|
||||
Line::from("When your app panics without a panic hook, you will likely have to"),
|
||||
Line::from("reset your terminal afterwards with the `reset` command"),
|
||||
Line::from(""),
|
||||
Line::from("Try first with the panic handler enabled, and then with it disabled"),
|
||||
Line::from("to see the difference"),
|
||||
];
|
||||
|
||||
let paragraph = Paragraph::new(text)
|
||||
.block(Block::bordered().title("Panic Handler Demo"))
|
||||
.centered();
|
||||
|
||||
frame.render_widget(paragraph, frame.area());
|
||||
}
|
||||
|
@ -1,77 +1,67 @@
|
||||
/// A Ratatui example that demonstrates how to handle popups.
|
||||
// See also https://github.com/joshka/tui-popup and
|
||||
// https://github.com/sephiroth74/tui-confirm-dialog
|
||||
///
|
||||
/// This example runs with the Ratatui library code in the branch that you are currently
|
||||
/// reading. See the [`latest`] branch for the code which works with the most recent Ratatui
|
||||
/// release.
|
||||
///
|
||||
/// [`latest`]: https://github.com/ratatui/ratatui/tree/latest
|
||||
//! A Ratatui example that demonstrates how to handle popups.
|
||||
//! See also:
|
||||
//! - <https://github.com/joshka/tui-popup> and
|
||||
//! - <https://github.com/sephiroth74/tui-confirm-dialog>
|
||||
//!
|
||||
//! This example runs with the Ratatui library code in the branch that you are currently
|
||||
//! reading. See the [`latest`] branch for the code which works with the most recent Ratatui
|
||||
//! release.
|
||||
//!
|
||||
//! [`latest`]: https://github.com/ratatui/ratatui/tree/latest
|
||||
use color_eyre::Result;
|
||||
use crossterm::event::{self, KeyCode};
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Constraint, Flex, Layout, Rect};
|
||||
use ratatui::style::Stylize;
|
||||
use ratatui::widgets::{Block, Clear, Paragraph, Wrap};
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
use ratatui::text::Line;
|
||||
use ratatui::widgets::{Block, Clear};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = App::default().run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct App {
|
||||
show_popup: bool,
|
||||
}
|
||||
// This flag will be toggled when the user presses 'p'. This could be stored in an app struct
|
||||
// if you have more state to manage than just this flag.
|
||||
let mut show_popup = false;
|
||||
|
||||
impl App {
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(|frame| self.render(frame))?;
|
||||
terminal.draw(|frame| render(frame, show_popup))?;
|
||||
|
||||
if let Some(key) = event::read()?.as_key_press_event() {
|
||||
match key.code {
|
||||
KeyCode::Char('q') => return Ok(()),
|
||||
KeyCode::Char('p') => self.show_popup = !self.show_popup,
|
||||
KeyCode::Char('p') => show_popup = !show_popup,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn render(&self, frame: &mut Frame) {
|
||||
let area = frame.area();
|
||||
fn render(frame: &mut Frame, show_popup: bool) {
|
||||
let area = frame.area();
|
||||
|
||||
let vertical = Layout::vertical([Constraint::Percentage(20), Constraint::Percentage(80)]);
|
||||
let [instructions, content] = vertical.areas(area);
|
||||
let vertical = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]);
|
||||
let [instructions, content] = vertical.areas(area);
|
||||
|
||||
let text = if self.show_popup {
|
||||
"Press p to close the popup"
|
||||
} else {
|
||||
"Press p to show the popup"
|
||||
};
|
||||
let paragraph = Paragraph::new(text.slow_blink())
|
||||
.centered()
|
||||
.wrap(Wrap { trim: true });
|
||||
frame.render_widget(paragraph, instructions);
|
||||
frame.render_widget(
|
||||
Line::from("Press 'p' to toggle popup, 'q' to quit").centered(),
|
||||
instructions,
|
||||
);
|
||||
|
||||
let block = Block::bordered().title("Content").on_blue();
|
||||
frame.render_widget(block, content);
|
||||
frame.render_widget(Block::bordered().title("Content").on_blue(), content);
|
||||
|
||||
if self.show_popup {
|
||||
let block = Block::bordered().title("Popup");
|
||||
let area = popup_area(area, 60, 20);
|
||||
frame.render_widget(Clear, area); //this clears out the background
|
||||
frame.render_widget(block, area);
|
||||
}
|
||||
if show_popup {
|
||||
let popup = Block::bordered().title("Popup");
|
||||
let popup_area = centered_area(area, 60, 20);
|
||||
// clears out any background in the area before rendering the popup
|
||||
frame.render_widget(Clear, popup_area);
|
||||
frame.render_widget(popup, popup_area);
|
||||
}
|
||||
}
|
||||
|
||||
/// helper function to create a centered rect using up certain percentage of the available rect `r`
|
||||
fn popup_area(area: Rect, percent_x: u16, percent_y: u16) -> Rect {
|
||||
/// Create a centered rect using up certain percentage of the available rect
|
||||
fn centered_area(area: Rect, percent_x: u16, percent_y: u16) -> Rect {
|
||||
let vertical = Layout::vertical([Constraint::Percentage(percent_y)]).flex(Flex::Center);
|
||||
let horizontal = Layout::horizontal([Constraint::Percentage(percent_x)]).flex(Flex::Center);
|
||||
let [area] = vertical.areas(area);
|
||||
|
@ -29,14 +29,11 @@ struct App {
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = App::default().run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
ratatui::run(|terminal| App::default().run(terminal))
|
||||
}
|
||||
|
||||
impl App {
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
fn run(mut self, terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
let tick_rate = Duration::from_millis(250);
|
||||
let mut last_tick = Instant::now();
|
||||
loop {
|
||||
|
@ -34,10 +34,7 @@ const ITEM_HEIGHT: usize = 4;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = App::new().run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
ratatui::run(|terminal| App::new().run(terminal))
|
||||
}
|
||||
struct TableColors {
|
||||
buffer_bg: Color,
|
||||
@ -120,6 +117,7 @@ impl App {
|
||||
items: data_vec,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_row(&mut self) {
|
||||
let i = match self.state.selected() {
|
||||
Some(i) => {
|
||||
@ -171,7 +169,7 @@ impl App {
|
||||
self.colors = TableColors::new(&PALETTES[self.color_index]);
|
||||
}
|
||||
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
fn run(mut self, terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(|frame| self.render(frame))?;
|
||||
|
||||
|
@ -27,10 +27,7 @@ const COMPLETED_TEXT_FG_COLOR: Color = GREEN.c500;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = App::default().run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
ratatui::run(|terminal| App::default().run(terminal))
|
||||
}
|
||||
|
||||
/// This struct holds the current state of the app. In particular, it has the `todo_list` field
|
||||
@ -124,7 +121,7 @@ impl TodoItem {
|
||||
}
|
||||
|
||||
impl App {
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
fn run(mut self, terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
while !self.should_exit {
|
||||
terminal.draw(|frame| frame.render_widget(&mut self, frame.area()))?;
|
||||
if let Some(key) = event::read()?.as_key_press_event() {
|
||||
|
@ -30,10 +30,7 @@ use ratatui::{DefaultTerminal, Frame};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = App::new().run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
ratatui::run(|terminal| App::new().run(terminal))
|
||||
}
|
||||
|
||||
/// App holds the state of the application
|
||||
@ -127,7 +124,7 @@ impl App {
|
||||
self.reset_cursor();
|
||||
}
|
||||
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
fn run(mut self, terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(|frame| self.render(frame))?;
|
||||
|
||||
|
@ -9,63 +9,35 @@
|
||||
//! [`BarChart`]: https://docs.rs/ratatui/latest/ratatui/widgets/struct.BarChart.html
|
||||
|
||||
use color_eyre::Result;
|
||||
use crossterm::event::{self, KeyCode};
|
||||
use crossterm::event;
|
||||
use rand::{Rng, rng};
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Constraint, Layout};
|
||||
use ratatui::style::{Color, Style, Stylize};
|
||||
use ratatui::text::Line;
|
||||
use ratatui::widgets::{Bar, BarChart, BarGroup};
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = App::new().run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
|
||||
let temperatures: Vec<u8> = (0..24).map(|_| rng().random_range(50..90)).collect();
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(|frame| render(frame, &temperatures))?;
|
||||
if event::read()?.is_key_press() {
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
struct App {
|
||||
should_exit: bool,
|
||||
temperatures: Vec<u8>,
|
||||
}
|
||||
fn render(frame: &mut Frame, temperatures: &[u8]) {
|
||||
let [title, main] = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)])
|
||||
.spacing(1)
|
||||
.areas(frame.area());
|
||||
|
||||
impl App {
|
||||
fn new() -> Self {
|
||||
let mut rng = rng();
|
||||
let temperatures = (0..24).map(|_| rng.random_range(50..90)).collect();
|
||||
Self {
|
||||
should_exit: false,
|
||||
temperatures,
|
||||
}
|
||||
}
|
||||
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
while !self.should_exit {
|
||||
terminal.draw(|frame| self.render(frame))?;
|
||||
self.handle_events()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_events(&mut self) -> Result<()> {
|
||||
if event::read()?
|
||||
.as_key_press_event()
|
||||
.is_some_and(|key| key.code == KeyCode::Char('q'))
|
||||
{
|
||||
self.should_exit = true;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render(&self, frame: &mut Frame) {
|
||||
let [title, main] = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)])
|
||||
.spacing(1)
|
||||
.areas(frame.area());
|
||||
|
||||
frame.render_widget("Weather demo".bold().into_centered_line(), title);
|
||||
frame.render_widget(vertical_barchart(&self.temperatures), main);
|
||||
}
|
||||
frame.render_widget("Weather demo".bold().into_centered_line(), title);
|
||||
frame.render_widget(vertical_barchart(temperatures), main);
|
||||
}
|
||||
|
||||
/// Create a vertical bar chart from the temperatures data.
|
||||
|
@ -1,39 +1,34 @@
|
||||
/// An example of how to use [`WidgetRef`] to store heterogeneous widgets in a container.
|
||||
///
|
||||
/// This example creates a `StackContainer` widget that can hold any number of widgets of
|
||||
/// different types. It creates two widgets, `Greeting` and `Farewell`, and stores them in a
|
||||
/// `StackContainer` with a vertical layout. The `StackContainer` widget renders each of its
|
||||
/// child widgets in the order they were added.
|
||||
///
|
||||
/// This example runs with the Ratatui library code in the branch that you are currently
|
||||
/// reading. See the [`latest`] branch for the code which works with the most recent Ratatui
|
||||
/// release.
|
||||
///
|
||||
/// [`latest`]: https://github.com/ratatui/ratatui/tree/latest
|
||||
//! An example of how to use [`WidgetRef`] to store heterogeneous widgets in a container.
|
||||
//!
|
||||
//! This example creates a `StackContainer` widget that can hold any number of widgets of
|
||||
//! different types. It creates two widgets, `Greeting` and `Farewell`, and stores them in a
|
||||
//! `StackContainer` with a vertical layout. The `StackContainer` widget renders each of its
|
||||
//! child widgets in the order they were added.
|
||||
//!
|
||||
//! This example runs with the Ratatui library code in the branch that you are currently
|
||||
//! reading. See the [`latest`] branch for the code which works with the most recent Ratatui
|
||||
//! release.
|
||||
//!
|
||||
//! [`latest`]: https://github.com/ratatui/ratatui/tree/latest
|
||||
use std::iter::zip;
|
||||
|
||||
use color_eyre::Result;
|
||||
use crossterm::event;
|
||||
use ratatui::Frame;
|
||||
use ratatui::buffer::Buffer;
|
||||
use ratatui::layout::{Constraint, Direction, Layout, Rect};
|
||||
use ratatui::widgets::{Block, Paragraph, Widget, WidgetRef};
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
return Ok(());
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn render(frame: &mut Frame) {
|
||||
|
@ -18,28 +18,22 @@ use core::iter::zip;
|
||||
|
||||
use color_eyre::Result;
|
||||
use crossterm::event;
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Constraint, Direction, Layout, Rect};
|
||||
use ratatui::style::{Color, Stylize};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Bar, BarChart, BarGroup};
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
|
||||
/// Run the application.
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
return Ok(());
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Render the UI with a barchart on the left and right side.
|
||||
|
@ -16,28 +16,22 @@
|
||||
|
||||
use color_eyre::Result;
|
||||
use crossterm::event;
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Constraint, Layout, Rect};
|
||||
use ratatui::style::Stylize;
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Bar, BarChart};
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
|
||||
/// Run the application.
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
return Ok(());
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Render the UI with a title and two barcharts.
|
||||
|
@ -16,28 +16,22 @@
|
||||
|
||||
use color_eyre::Result;
|
||||
use crossterm::event;
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Constraint, Layout, Rect};
|
||||
use ratatui::style::{Style, Stylize};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Block, BorderType};
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
|
||||
/// Run the application.
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
return Ok(());
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Render the UI with various blocks.
|
||||
|
@ -16,30 +16,24 @@
|
||||
|
||||
use color_eyre::Result;
|
||||
use crossterm::event;
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Constraint, Layout, Rect};
|
||||
use ratatui::style::{Color, Modifier, Style, Stylize};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Block, Padding};
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
use ratatui_widgets::calendar::{CalendarEventStore, Monthly};
|
||||
use time::{Date, Month, OffsetDateTime};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
|
||||
/// Run the application.
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
return Ok(());
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Render the UI with 2 monthly calendars side by side.
|
||||
|
@ -16,30 +16,24 @@
|
||||
|
||||
use color_eyre::Result;
|
||||
use crossterm::event;
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Constraint, Layout, Rect};
|
||||
use ratatui::style::{Color, Stylize};
|
||||
use ratatui::symbols::Marker;
|
||||
use ratatui::text::{Line as TextLine, Span};
|
||||
use ratatui::widgets::canvas::{Canvas, Line, Map, MapResolution, Rectangle};
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
use ratatui_widgets::canvas::Points;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
|
||||
/// Run the application.
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
return Ok(());
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Render the UI with a canvas widget.
|
||||
|
@ -16,29 +16,23 @@
|
||||
|
||||
use color_eyre::Result;
|
||||
use crossterm::event;
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Constraint, Layout, Rect};
|
||||
use ratatui::style::{Color, Stylize};
|
||||
use ratatui::symbols::Marker;
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Axis, Chart, Dataset, GraphType};
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
|
||||
/// Run the application.
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
return Ok(());
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Render the UI with a chart.
|
||||
|
@ -20,24 +20,18 @@ use ratatui::layout::{Constraint, Layout, Rect};
|
||||
use ratatui::style::{Modifier, Style, Stylize};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Gauge, LineGauge};
|
||||
use ratatui::{DefaultTerminal, Frame, symbols};
|
||||
use ratatui::{Frame, symbols};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
|
||||
/// Run the application.
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
return Ok(());
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Render the UI with various progress bars.
|
||||
|
@ -28,10 +28,7 @@ use ratatui::widgets::{LineGauge, Paragraph, Widget};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let app_result = App::default().run(terminal);
|
||||
ratatui::restore();
|
||||
app_result
|
||||
ratatui::run(|terminal| App::default().run(terminal))
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
@ -50,7 +47,7 @@ enum AppState {
|
||||
}
|
||||
|
||||
impl App {
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
fn run(mut self, terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
while self.state != AppState::Quit {
|
||||
terminal.draw(|frame| frame.render_widget(&self, frame.area()))?;
|
||||
self.handle_events()?;
|
||||
|
@ -14,36 +14,30 @@
|
||||
//! [widget examples]: https://github.com/ratatui/ratatui/blob/main/ratatui-widgets/examples
|
||||
//! [examples readme]: https://github.com/ratatui/ratatui/blob/main/examples/README.md
|
||||
|
||||
use color_eyre::Result;
|
||||
use crossterm::event::{self, KeyCode};
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Constraint, Layout, Rect};
|
||||
use ratatui::style::{Color, Modifier, Style, Stylize};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{List, ListDirection, ListState};
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
fn main() -> color_eyre::Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
|
||||
/// Run the application.
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
let mut list_state = ListState::default().with_selected(Some(0));
|
||||
loop {
|
||||
terminal.draw(|frame| render(frame, &mut list_state))?;
|
||||
if let Some(key) = event::read()?.as_key_press_event() {
|
||||
match key.code {
|
||||
KeyCode::Char('j') | KeyCode::Down => list_state.select_next(),
|
||||
KeyCode::Char('k') | KeyCode::Up => list_state.select_previous(),
|
||||
KeyCode::Char('q') | KeyCode::Esc => return Ok(()),
|
||||
_ => {}
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(|frame| render(frame, &mut list_state))?;
|
||||
if let Some(key) = event::read()?.as_key_press_event() {
|
||||
match key.code {
|
||||
KeyCode::Char('j') | KeyCode::Down => list_state.select_next(),
|
||||
KeyCode::Char('k') | KeyCode::Up => list_state.select_previous(),
|
||||
KeyCode::Char('q') | KeyCode::Esc => break Ok(()),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Render the UI with various lists.
|
||||
|
@ -43,7 +43,7 @@ fn run(mut terminal: DefaultTerminal, size: RatatuiLogoSize) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(|frame| render(frame, size))?;
|
||||
if event::read()?.is_key_press() {
|
||||
return Ok(());
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,28 +16,22 @@
|
||||
|
||||
use color_eyre::Result;
|
||||
use crossterm::event;
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Alignment, Constraint, Layout, Rect};
|
||||
use ratatui::style::{Color, Stylize};
|
||||
use ratatui::text::{Line, Masked, Span};
|
||||
use ratatui::widgets::{Paragraph, Wrap};
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
|
||||
/// Run the application.
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
return Ok(());
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::read()?.is_key_press() {
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Render the UI with various text.
|
||||
|
@ -16,38 +16,33 @@
|
||||
|
||||
use color_eyre::Result;
|
||||
use crossterm::event::{self, KeyCode};
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Constraint, Layout, Margin, Rect};
|
||||
use ratatui::style::{Color, Stylize};
|
||||
use ratatui::symbols::scrollbar::Set;
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Paragraph, Scrollbar, ScrollbarOrientation, ScrollbarState};
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
|
||||
/// Run the application.
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
let mut vertical = ScrollbarState::new(100);
|
||||
let mut horizontal = ScrollbarState::new(100);
|
||||
loop {
|
||||
terminal.draw(|frame| render(frame, &mut vertical, &mut horizontal))?;
|
||||
if let Some(key) = event::read()?.as_key_press_event() {
|
||||
match key.code {
|
||||
KeyCode::Char('q') | KeyCode::Esc => return Ok(()),
|
||||
KeyCode::Char('j') | KeyCode::Down => vertical.next(),
|
||||
KeyCode::Char('k') | KeyCode::Up => vertical.prev(),
|
||||
KeyCode::Char('l') | KeyCode::Right => horizontal.next(),
|
||||
KeyCode::Char('h') | KeyCode::Left => horizontal.prev(),
|
||||
_ => {}
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(|frame| render(frame, &mut vertical, &mut horizontal))?;
|
||||
if let Some(key) = event::read()?.as_key_press_event() {
|
||||
match key.code {
|
||||
KeyCode::Char('q') | KeyCode::Esc => break Ok(()),
|
||||
KeyCode::Char('j') | KeyCode::Down => vertical.next(),
|
||||
KeyCode::Char('k') | KeyCode::Up => vertical.prev(),
|
||||
KeyCode::Char('l') | KeyCode::Right => horizontal.next(),
|
||||
KeyCode::Char('h') | KeyCode::Left => horizontal.prev(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Render the UI with vertical/horizontal scrollbars.
|
||||
|
@ -22,28 +22,19 @@ use ratatui::layout::{Constraint, Layout, Rect};
|
||||
use ratatui::style::{Color, Style, Stylize};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{RenderDirection, Sparkline};
|
||||
use ratatui::{DefaultTerminal, Frame, symbols};
|
||||
use ratatui::{Frame, symbols};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
|
||||
/// Run the application.
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
// Ensure that the animations renders at 50 FPS (GIF speed)
|
||||
if !event::poll(Duration::from_secs_f64(1.0 / 50.0))? {
|
||||
continue;
|
||||
let frame_timeout = Duration::from_secs_f64(1.0 / 60.0); // run at 60 FPS
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(render)?;
|
||||
if event::poll(frame_timeout)? && event::read()?.is_key_press() {
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
if event::read()?.is_key_press() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Render the UI with various sparklines.
|
||||
|
@ -16,40 +16,35 @@
|
||||
|
||||
use color_eyre::Result;
|
||||
use crossterm::event::{self, KeyCode};
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Constraint, Layout, Rect};
|
||||
use ratatui::style::{Color, Style, Stylize};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Row, Table, TableState};
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
|
||||
/// Run the application.
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
let mut table_state = TableState::default();
|
||||
table_state.select_first();
|
||||
table_state.select_first_column();
|
||||
loop {
|
||||
terminal.draw(|frame| render(frame, &mut table_state))?;
|
||||
if let Some(key) = event::read()?.as_key_press_event() {
|
||||
match key.code {
|
||||
KeyCode::Char('q') | KeyCode::Esc => return Ok(()),
|
||||
KeyCode::Char('j') | KeyCode::Down => table_state.select_next(),
|
||||
KeyCode::Char('k') | KeyCode::Up => table_state.select_previous(),
|
||||
KeyCode::Char('l') | KeyCode::Right => table_state.select_next_column(),
|
||||
KeyCode::Char('h') | KeyCode::Left => table_state.select_previous_column(),
|
||||
KeyCode::Char('g') => table_state.select_first(),
|
||||
KeyCode::Char('G') => table_state.select_last(),
|
||||
_ => {}
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(|frame| render(frame, &mut table_state))?;
|
||||
if let Some(key) = event::read()?.as_key_press_event() {
|
||||
match key.code {
|
||||
KeyCode::Char('q') | KeyCode::Esc => return Ok(()),
|
||||
KeyCode::Char('j') | KeyCode::Down => table_state.select_next(),
|
||||
KeyCode::Char('k') | KeyCode::Up => table_state.select_previous(),
|
||||
KeyCode::Char('l') | KeyCode::Right => table_state.select_next_column(),
|
||||
KeyCode::Char('h') | KeyCode::Left => table_state.select_previous_column(),
|
||||
KeyCode::Char('g') => table_state.select_first(),
|
||||
KeyCode::Char('G') => table_state.select_last(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Render the UI with a table.
|
||||
|
@ -20,32 +20,25 @@ use ratatui::layout::{Alignment, Constraint, Layout, Offset, Rect};
|
||||
use ratatui::style::{Color, Style, Stylize};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Block, Paragraph, Tabs};
|
||||
use ratatui::{DefaultTerminal, Frame, symbols};
|
||||
use ratatui::{Frame, symbols};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
|
||||
/// Run the application.
|
||||
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
let mut selected_tab = 0;
|
||||
loop {
|
||||
terminal.draw(|frame| render(frame, selected_tab))?;
|
||||
if let Some(key) = event::read()?.as_key_press_event() {
|
||||
match key.code {
|
||||
KeyCode::Char('l') | KeyCode::Right | KeyCode::Tab => {
|
||||
selected_tab = (selected_tab + 1) % 3;
|
||||
let mut selection = 0;
|
||||
ratatui::run(|terminal| {
|
||||
loop {
|
||||
terminal.draw(|frame| render(frame, selection))?;
|
||||
if let Some(key) = event::read()?.as_key_press_event() {
|
||||
match key.code {
|
||||
KeyCode::Char('q') | KeyCode::Esc => break Ok(()),
|
||||
KeyCode::Char('l') | KeyCode::Right => selection = (selection + 1) % 3,
|
||||
KeyCode::Char('h') | KeyCode::Left => selection = (selection + 2) % 3,
|
||||
_ => {}
|
||||
}
|
||||
KeyCode::Char('h') | KeyCode::Left => selected_tab = (selected_tab + 2) % 3,
|
||||
KeyCode::Char('q') | KeyCode::Esc => return Ok(()),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Render the UI with tabs.
|
||||
|
@ -14,6 +14,116 @@ use ratatui_crossterm::crossterm::terminal::{
|
||||
/// use [`Terminal`] and a [backend][`crate::backend`] of your choice directly.
|
||||
pub type DefaultTerminal = Terminal<CrosstermBackend<Stdout>>;
|
||||
|
||||
/// Run a closure with a terminal initialized with reasonable defaults for most applications.
|
||||
///
|
||||
/// This function creates a new [`DefaultTerminal`] with [`init`] and then runs the given closure
|
||||
/// with a mutable reference to the terminal. After the closure completes, the terminal is restored
|
||||
/// to its original state with [`restore`].
|
||||
///
|
||||
/// This function is a convenience wrapper around [`init`] and [`restore`], and is useful for simple
|
||||
/// applications that need a terminal with reasonable defaults for the entire lifetime of the
|
||||
/// application.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// A simple example where the app logic is contained in the closure:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use crossterm::event;
|
||||
///
|
||||
/// fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// ratatui::run(|terminal| {
|
||||
/// loop {
|
||||
/// terminal.draw(|frame| frame.render_widget("Hello, world!", frame.area()))?;
|
||||
/// if event::read()?.is_key_press() {
|
||||
/// break Ok(());
|
||||
/// }
|
||||
/// }
|
||||
/// })
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// A more complex example where the app logic is contained in a separate function:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use crossterm::event;
|
||||
///
|
||||
/// type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||
///
|
||||
/// fn main() -> Result<()> {
|
||||
/// ratatui::run(app)
|
||||
/// }
|
||||
///
|
||||
/// fn app(terminal: &mut ratatui::DefaultTerminal) -> Result<()> {
|
||||
/// const GREETING: &str = "Hello, world!";
|
||||
/// loop {
|
||||
/// terminal.draw(|frame| frame.render_widget(format!("{GREETING}"), frame.area()))?;
|
||||
/// if matches!(event::read()?, event::Event::Key(_)) {
|
||||
/// break Ok(());
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Once the app logic becomes more complex, it may be beneficial to move the app logic into a
|
||||
/// separate struct. This allows the app logic to be split into multiple methods with each having
|
||||
/// access to the state of the app. This can make the app logic easier to understand and maintain.
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use crossterm::event;
|
||||
///
|
||||
/// type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||
///
|
||||
/// fn main() -> Result<()> {
|
||||
/// let mut app = App::new();
|
||||
/// ratatui::run(|terminal| app.run(terminal))
|
||||
/// }
|
||||
///
|
||||
/// struct App {
|
||||
/// should_quit: bool,
|
||||
/// name: String,
|
||||
/// }
|
||||
///
|
||||
/// impl App {
|
||||
/// fn new() -> Self {
|
||||
/// Self {
|
||||
/// should_quit: false,
|
||||
/// name: "world".to_string(),
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn run(&mut self, terminal: &mut ratatui::DefaultTerminal) -> Result<()> {
|
||||
/// while !self.should_quit {
|
||||
/// terminal.draw(|frame| frame.render_widget("Hello, world!", frame.area()))?;
|
||||
/// self.handle_events()?;
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
///
|
||||
/// fn render(&mut self, frame: &mut ratatui::Frame) -> Result<()> {
|
||||
/// let greeting = format!("Hello, {}!", self.name);
|
||||
/// frame.render_widget(greeting, frame.area());
|
||||
/// Ok(())
|
||||
/// }
|
||||
///
|
||||
/// fn handle_events(&mut self) -> Result<()> {
|
||||
/// if event::read()?.is_key_press() {
|
||||
/// self.should_quit = true;
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn run<F, R>(f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut DefaultTerminal) -> R,
|
||||
{
|
||||
let mut terminal = init();
|
||||
let result = f(&mut terminal);
|
||||
restore();
|
||||
result
|
||||
}
|
||||
|
||||
/// Initialize a terminal with reasonable defaults for most applications.
|
||||
///
|
||||
/// This will create a new [`DefaultTerminal`] and initialize it with the following defaults:
|
||||
|
@ -351,7 +351,8 @@ pub use ratatui_termwiz::termwiz;
|
||||
|
||||
#[cfg(feature = "crossterm")]
|
||||
pub use crate::init::{
|
||||
DefaultTerminal, init, init_with_options, restore, try_init, try_init_with_options, try_restore,
|
||||
DefaultTerminal, init, init_with_options, restore, run, try_init, try_init_with_options,
|
||||
try_restore,
|
||||
};
|
||||
|
||||
/// Re-exports for the backend implementations.
|
||||
|
Loading…
x
Reference in New Issue
Block a user