Full source code for this recipe is available at:
https://github.com/ratatui-org/ratatui-website/tree/main/code/how-to-color_eyre/
The color_eyre
crate provides error report handlers for panics and errors. It displays the
reports formatted and in color. To use these handlers, a Ratatui app needs to restore the terminal
before displaying the errors.
Installation
First add the crate to your Cargo.toml
Add the following imports to main.rs
Create a new function install_hooks()
which will ensure your app calls tui::restore()
before
exiting with a panic or an error.
/// This replaces the standard color_eyre panic and error hooks with hooks that
/// restore the terminal before printing the panic or error.
pub fn install_hooks () -> color_eyre :: Result<()> {
// add any extra configuration you need to the hook builder
let hook_builder = color_eyre :: config :: HookBuilder :: default ();
let ( panic_hook , eyre_hook ) = hook_builder . into_hooks ();
// convert from a color_eyre PanicHook to a standard panic hook
let panic_hook = panic_hook . into_panic_hook ();
panic :: set_hook (Box :: new ( move | panic_info | {
// convert from a color_eyre EyreHook to a eyre ErrorHook
let eyre_hook = eyre_hook . into_eyre_hook ();
eyre :: set_hook (Box :: new ( move | error | {
This example assumes that you have a tui
module in your app with init
and restore
functions
Example tui.rs module
use std :: io :: { self , stdout};
backend :: {Backend, CrosstermBackend},
terminal :: {disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
pub fn init () -> io :: Result<Terminal< impl Backend>> {
stdout () . execute (EnterAlternateScreen) ? ;
Terminal :: new (CrosstermBackend :: new ( stdout ()))
pub fn restore () -> io :: Result<()> {
stdout () . execute (LeaveAlternateScreen) ? ;
Usage
In your application, wrap errors with extra context as needed:
Add the following import:
use color_eyre :: eyre :: WrapErr;
Call wrap_err from methods that can fail with an error.
fn main () -> color_eyre :: Result<()> {
let terminal = tui :: init () ? ;
run ( terminal ) . wrap_err ( " run failed " ) ? ;
println! ( " user triggered quit " );
Demo
Full code
use color_eyre :: eyre :: WrapErr;
use color_eyre :: eyre :: bail;
crossterm :: event :: { self , Event, KeyCode, KeyEvent},
fn main () -> color_eyre :: Result<()> {
let terminal = tui :: init () ? ;
run ( terminal ) . wrap_err ( " run failed " ) ? ;
println! ( " user triggered quit " );
fn run ( mut terminal : Terminal< impl Backend>) -> color_eyre :: Result<()> {
let message = " Press <Q> to quit, <P> to panic, or <E> to error " ;
frame . render_widget (Paragraph :: new ( message ), frame . size ());
code : KeyCode :: Char ( 'q' ),
code : KeyCode :: Char ( 'p' ),
}) => panic! ( " User triggered panic " ),
code : KeyCode :: Char ( 'e' ),
}) => bail! ( " user triggered error " ),
/// This replaces the standard color_eyre panic and error hooks with hooks that
/// restore the terminal before printing the panic or error.
pub fn install_hooks () -> color_eyre :: Result<()> {
// add any extra configuration you need to the hook builder
let hook_builder = color_eyre :: config :: HookBuilder :: default ();
let ( panic_hook , eyre_hook ) = hook_builder . into_hooks ();
// convert from a color_eyre PanicHook to a standard panic hook
let panic_hook = panic_hook . into_panic_hook ();
panic :: set_hook (Box :: new ( move | panic_info | {
// convert from a color_eyre EyreHook to a eyre ErrorHook
let eyre_hook = eyre_hook . into_eyre_hook ();
eyre :: set_hook (Box :: new ( move | error | {
use std :: io :: { self , stdout};
backend :: {Backend, CrosstermBackend},
terminal :: {disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
pub fn init () -> io :: Result<Terminal< impl Backend>> {
stdout () . execute (EnterAlternateScreen) ? ;
Terminal :: new (CrosstermBackend :: new ( stdout ()))
pub fn restore () -> io :: Result<()> {
stdout () . execute (LeaveAlternateScreen) ? ;
Panic
With RUST_BACKTRACE=full
:
Error
With RUST_BACKTRACE=full
:
Normal exit
Further Steps
See the color_eyre
docs and examples for more advanced setups. E.g.: