use std::io; use crate::ui; use crossterm::event::{DisableMouseCapture, EnableMouseCapture}; use crossterm::terminal::{self, *}; use std::panic; use crate::app::{App, AppResult}; use crate::event_handler::event::EventHandler; pub type CrosstermTerminal = ratatui::Terminal>; #[derive(Debug)] pub struct Tui { terminal: CrosstermTerminal, pub events: EventHandler, } impl Tui { pub fn new(terminal: CrosstermTerminal, events: EventHandler) -> Self { Self { terminal, events } } pub fn init(&mut self) -> AppResult<()> { terminal::enable_raw_mode()?; crossterm::execute!(io::stdout(), EnterAlternateScreen, EnableMouseCapture)?; let panic_hook = panic::take_hook(); panic::set_hook(Box::new(move |panic| { Self::reset().expect("failed to reset the terminal"); panic_hook(panic); })); Ok(()) } /// [`Draw`] the terminal interface by [`rendering`] the widgets. /// /// [`Draw`]: ratatui::Terminal::draw /// [`rendering`]: crate::ui::render pub fn draw(&mut self, app: &mut App) -> AppResult<()> { self.terminal.draw(|frame| ui::render(app, frame))?; Ok(()) } /// Resets the terminal interface. /// /// This function is also used for the panic hook to revert /// the terminal properties if unexpected errors occur. fn reset() -> AppResult<()> { terminal::disable_raw_mode()?; crossterm::execute!(io::stderr(), LeaveAlternateScreen, DisableMouseCapture)?; Ok(()) } /// Exits the terminal interface. /// /// It disables the raw mode and reverts back the terminal properties. pub fn exit(&mut self) -> AppResult<()> { Self::reset()?; self.terminal.show_cursor()?; Ok(()) } }