Panic Hooks
Demonstrates the setting up panic hooks
git clone https://github.com/ratatui/ratatui.git --branch latestcd ratatuicargo run --example=panic --features=crossterm
//! # [Ratatui] Panic Hook example//!//! The latest version of this example is available in the [examples] folder in the repository.//!//! Please note that the examples are designed to be run against the `main` branch of the Github//! repository. This means that you may not be able to compile with the latest release version on//! crates.io, or the one that you have installed locally.//!//! See the [examples readme] for more information on finding examples that match the version of the//! library you are using.//!//! [Ratatui]: https://github.com/ratatui/ratatui//! [examples]: https://github.com/ratatui/ratatui/blob/main/examples//! [examples readme]: https://github.com/ratatui/ratatui/blob/main/examples/README.md//!//! Prior to Ratatui 0.28.1, a panic hook had to be manually set up to ensure that the terminal was//! reset when a panic occurred. This was necessary because a panic would interrupt the normal//! control flow and leave the terminal in a distorted state.//!//! Starting with Ratatui 0.28.1, the panic hook is automatically set up by the new `ratatui::init`//! function, so you no longer need to manually set up the panic hook. This example now demonstrates//! how the panic hook acts when it is enabled by default.//!//! When exiting normally or when handling `Result::Err`, we can reset the terminal manually at the//! end of `main` just before we print the error.//!//! Because a panic interrupts the normal control flow, manually resetting the terminal at the end//! of `main` won't do us any good. Instead, we need to make sure to set up a panic hook that first//! resets the terminal before handling the panic. This both reuses the standard panic hook to//! ensure a consistent panic handling UX and properly resets the terminal to not distort the//! output.//!//! That's why this example is set up to show both situations, with and without the panic hook, to//! see the difference.//!//! For more information on how to set this up manually, see the [Color Eyre recipe] in the Ratatui//! website.//!//! [Color Eyre recipe]: https://ratatui.rs/recipes/apps/color-eyre
use color_eyre::{eyre::bail, Result};use ratatui::{ crossterm::event::{self, Event, KeyCode}, text::Line, widgets::{Block, Paragraph}, DefaultTerminal, Frame,};
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<()> { loop { terminal.draw(|frame| self.draw(frame))?;
if let Event::Key(key) = event::read()? { 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; } KeyCode::Char('q') => return Ok(()), _ => {} } } } }
fn draw(&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()); }}