Closed piegamesde closed 1 year ago
I managed to get it somewhat working with Termion with a custom panic handler. Since I don't know how to explicitly disable raw mode, I simply switch back to the main Screen and add \r
to each println!
command. Here's my current handler, with some copy-paste from Rust's default handler:
fn panic_hook(info: &PanicInfo<'_>) {
let location = info.location().unwrap(); // The current implementation always returns Some
let msg = match info.payload().downcast_ref::<&'static str>() {
Some(s) => *s,
None => match info.payload().downcast_ref::<String>() {
Some(s) => &s[..],
None => "Box<Any>",
}
};
println!("{}thread '<unnamed>' panicked at '{}', {}\r", termion::screen::ToMainScreen, msg, location);
}
It works, but has quite a few drawbacks:
I had a similar issue with crossterm and I also used a panic_hook along with better_panic:
fn setup_panic_hook() {
panic::set_hook(Box::new(|panic_info| {
// Exits raw mode.
cleanup_terminal();
better_panic::Settings::auto().create_panic_handler()(panic_info);
}));
}
https://github.com/cjbassi/ytop/blob/master/src/main.rs#L114
With termion backend, the easy workaround is to set a raw handle on startup and to pass it to the hook. Here's a simple case:
use termion::raw::IntoRawMode;
use termion::screen::AlternateScreen;
use tui::backend::TermionBackend;
fn main() {
setup_panic();
let mut tui = tui::Terminal::new(TermionBackend::new(AlternateScreen::from(
std::io::stdout().into_raw_mode().unwrap(),
)))
.unwrap();
tui.clear().unwrap();
panic!("noes");
}
fn setup_panic() {
let raw_handle = std::io::stdout().into_raw_mode().unwrap();
let default_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |info| {
raw_handle
.suspend_raw_mode()
.unwrap_or_else(|e| log::error!("Could not suspend raw mode: {}", e));
default_hook(info);
// or better_panic::Settings::new().create_panic_handler()(info);
}));
}
I had a similar issue with crossterm and I also used a panic_hook along with better_panic:
fn setup_panic_hook() { panic::set_hook(Box::new(|panic_info| { // Exits raw mode. cleanup_terminal(); better_panic::Settings::auto().create_panic_handler()(panic_info); })); }
https://github.com/cjbassi/ytop/blob/master/src/main.rs#L114
Thanks for the example, this convinced me to move from termion to crossterm. Crossterm's handling of terminal state (raw mode etc.) seems much more sensible!
How do you accomplish this when using a AlternateScreen
?
Nevermind:
std::panic::set_hook(Box::new(move |x| {
stdout()
.into_raw_mode()
.unwrap()
.suspend_raw_mode()
.unwrap();
write!(stdout().into_raw_mode().unwrap(), "{}", ToMainScreen).unwrap();
write!(stdout(), "{:?}", x).unwrap();
}));
I tried this both with the
Termion
and theRustBox
backend: when my application panics, it will simply quit without printing any messages to the output. This is presumably because the terminal is in raw mode and exits it after the message was printed, thus clearing the screen.Is there any way to write stuff to console (especially errors), so that I know why my application crashed?