use std::io::{self, Stdout};
use crossterm::event::{DisableMouseCapture, EnableMouseCapture};
use crossterm::terminal::{
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
};
use crossterm::{cursor, execute};
use ratatui::backend::CrosstermBackend;
use ratatui::{Frame, Terminal};
pub struct Tui {
terminal: Terminal<CrosstermBackend<Stdout>>,
}
impl Tui {
pub fn new() -> io::Result<Self> {
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(
stdout,
EnterAlternateScreen,
EnableMouseCapture,
cursor::Hide
)?;
let terminal = Terminal::new(CrosstermBackend::new(stdout))?;
Ok(Self { terminal })
}
pub fn draw(&mut self, render: impl FnOnce(&mut Frame)) -> io::Result<()> {
self.terminal.draw(render)?;
Ok(())
}
pub fn clear(&mut self) -> io::Result<()> {
execute!(
io::stdout(),
crossterm::terminal::Clear(crossterm::terminal::ClearType::All),
crossterm::cursor::MoveTo(0, 0)
)?;
if let Ok(size) = self.terminal.size() {
let _ = self.terminal.resize(size.into());
}
Ok(())
}
pub fn restore() -> io::Result<()> {
disable_raw_mode()?;
execute!(
io::stdout(),
DisableMouseCapture,
LeaveAlternateScreen,
cursor::Show
)?;
Ok(())
}
}
impl Drop for Tui {
fn drop(&mut self) {
let _ = Self::restore();
}
}
pub fn install_panic_hook() {
let default_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |info| {
let _ = Tui::restore();
default_hook(info);
}));
}