use std::io;
use color_eyre::eyre::Result;
use crossterm::event::{Event, KeyCode};
use ratatui::Frame;
use ratatui::text::Text;
use tears::prelude::*;
use tears::subscription::terminal::TerminalEvents;
#[derive(Debug)]
enum Message {
Terminal(Event),
TerminalError(io::Error),
}
#[derive(Debug, Default)]
struct PanicDemo;
impl Application for PanicDemo {
type Message = Message;
type Flags = ();
fn new(_flags: Self::Flags) -> (Self, Command<Self::Message>) {
(Self, Command::none())
}
fn update(&mut self, msg: Self::Message) -> Command<Self::Message> {
match msg {
Message::Terminal(Event::Key(key)) => match key.code {
#[allow(clippy::panic, reason = "demonstrating panic recovery")]
KeyCode::Char('p') => panic!("intentional panic triggered by 'p'"),
KeyCode::Char('q') => Command::effect(Action::Quit),
_ => Command::none(),
},
Message::Terminal(_) => Command::none(),
Message::TerminalError(e) => {
eprintln!("Terminal error: {e}");
Command::effect(Action::Quit)
}
}
}
fn view(&self, frame: &mut Frame<'_>) {
let text = Text::raw("Press 'p' to panic (terminal should recover), 'q' to quit");
frame.render_widget(text, frame.area());
}
fn subscriptions(&self) -> Vec<Subscription<Self::Message>> {
vec![
Subscription::new(TerminalEvents::new()).map(|result| match result {
Ok(event) => Message::Terminal(event),
Err(e) => Message::TerminalError(e),
}),
]
}
}
#[tokio::main]
async fn main() -> Result<()> {
color_eyre::install()?;
let mut terminal = ratatui::init();
tears::install_panic_hook();
let runtime = Runtime::<PanicDemo>::try_new((), 60)?;
let result = runtime.run(&mut terminal).await;
ratatui::restore();
result?;
Ok(())
}