use crate::{event::EventHandler, Frame, Result};
use color_eyre::eyre;
use crossterm::{
cursor,
event::{DisableMouseCapture, EnableMouseCapture},
execute,
terminal::{self, Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen},
};
use ratatui::{backend::CrosstermBackend, layout::Rect, Terminal};
use std::{io, panic};
pub struct Tui {
terminal: CrosstermTerminal,
pub events: EventHandler,
}
impl Tui {
pub fn new(timeout: u64) -> Result<Tui> {
enter_terminal()?;
let terminal = CrosstermTerminal::new(CrosstermBackend::new(pipeline()))?;
let events = EventHandler::new(timeout);
Ok(Tui { terminal, events })
}
pub fn draw(&mut self, widgets: &mut Frame) -> Result<()> {
self.terminal
.draw(|frame| frame.render_widget(widgets, frame.size()))?;
Ok(())
}
pub fn size(&self) -> Result<Rect> {
Ok(self.terminal.size()?)
}
}
impl Drop for Tui {
fn drop(&mut self) {
restore_terminal().expect("Failed to restore terminal when dropping App");
}
}
pub type CrosstermTerminal = Terminal<CrosstermBackend<io::Stdout>>;
fn pipeline() -> io::Stdout {
io::stdout()
}
fn restore_terminal() -> io::Result<()> {
terminal::disable_raw_mode()?;
execute!(
pipeline(),
LeaveAlternateScreen,
DisableMouseCapture,
cursor::Show
)?;
Ok(())
}
fn enter_terminal() -> io::Result<()> {
terminal::enable_raw_mode()?;
execute!(
pipeline(),
EnterAlternateScreen,
EnableMouseCapture,
cursor::Hide,
Clear(ClearType::All)
)?;
Ok(())
}
pub fn install_hooks() -> crate::Result<()> {
let hook_builder = color_eyre::config::HookBuilder::default();
let (panic_hook, eyre_hook) = hook_builder.into_hooks();
let panic_hook = panic_hook.into_panic_hook();
panic::set_hook(Box::new(move |panic_info| {
restore_terminal().unwrap();
panic_hook(panic_info);
}));
let eyre_hook = eyre_hook.into_eyre_hook();
eyre::set_hook(Box::new(move |error| {
eyre_hook(error)
}))?;
Ok(())
}