eyre-rs / eyre

A trait object based error handling type for easy idiomatic error handling and reporting in Rust applications
Apache License 2.0
1.3k stars 57 forks source link

Add pre-hook callbacks #184

Open joshka opened 3 weeks ago

joshka commented 3 weeks ago

183 adds the ability to add custom pre-hook callbacks to the panic /

error hook. These callbacks will be called before the panic / error hook is called and can be used to print additional information or perform other actions before the panic / error hook is called (such as clearing the terminal, printing a message, etc.)

Often in an interactive TUI application, the terminal state is set to raw mode (where newlines do not automatically cause the cursor to move to the start of the next line), and is in the alternate screen buffer (which is a separate screen buffer that is used for full-screen apps).

This means that when a panic occurs, the terminal will display the panic message all janky. By adding a pre-hook callback that restores the terminal state to normal mode, the panic message can be displayed properly.

HookBuilder::default()
    .add_pre_hook_callback(Box::new(|| eprintln!("pre-hook callback")))
    .install()?

In a crossterm based app, that might look like the following instead of the more lengthy code in https://ratatui.rs/recipes/apps/color-eyre/

use crossterm::terminal::{disable_raw_mode, LeaveAlternateScreen};

HookBuilder::default()
    .add_pre_hook_callback(Box::new(|| {
        let _ = disable_raw_mode();
        let _ = execute!(stdout(), LeaveAlternateScreen);
    }))
    .install()?

I marked the PR as draft as i'd like to do the error hook side as well, but there's a bit more complexity to that side and I'd like to get some feedback on the idea first.

Some questions:

  1. Would it make sense to have the panic info passed to this callback (this might be good for callbacks that need to sanitize the info in the panic to remove confidential data)
  2. Would it make sense to have pre_panic_hook callbacks separate from pre_error_hook callbacks?

For the benefit of future devs reading this issue, and in case things change, the Ratatui code for configuring custom hooks from the link above generally looks like the following:

/// 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| {
        tui::restore().unwrap();
        panic_hook(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| {
        tui::restore().unwrap();
        eyre_hook(error)
    }))?;

    Ok(())
}
LeoniePhiline commented 2 weeks ago

I have definitely had need for that in the past, and I fully support this proposal.

joshka commented 4 days ago

ping