pub mod state;
pub mod event;
pub mod ui;
pub mod widgets;
pub mod command;
use crate::error::{Error, Result};
use event::EventHandler;
use ratatui::backend::{Backend, CrosstermBackend};
use ratatui::crossterm::event::{DisableMouseCapture, EnableMouseCapture};
use ratatui::crossterm::terminal::{self, EnterAlternateScreen, LeaveAlternateScreen};
use ratatui::Terminal;
use state::State;
use std::sync::atomic::Ordering;
use std::{io, panic};
#[derive(Debug)]
pub struct Tui<B: Backend> {
terminal: Terminal<B>,
pub events: EventHandler,
pub paused: bool,
}
impl<B> Tui<B>
where
B: Backend,
Error: From<B::Error>,
{
pub fn new(terminal: Terminal<B>, events: EventHandler) -> Self {
Self {
terminal,
events,
paused: false,
}
}
pub fn init(&mut self) -> Result<()> {
terminal::enable_raw_mode()?;
ratatui::crossterm::execute!(io::stdout(), EnterAlternateScreen, EnableMouseCapture)?;
panic::set_hook(Box::new(move |panic| {
Self::reset().expect("failed to reset the terminal");
better_panic::Settings::auto()
.most_recent_first(false)
.lineno_suffix(true)
.create_panic_handler()(panic);
std::process::exit(1);
}));
self.terminal.hide_cursor()?;
self.terminal.clear()?;
Ok(())
}
pub fn draw(&mut self, app: &mut State) -> Result<()> {
self.terminal.draw(|frame| ui::render(app, frame))?;
Ok(())
}
pub fn toggle_pause(&mut self) -> Result<()> {
self.paused = !self.paused;
if self.paused {
Self::reset()?;
} else {
self.init()?;
}
self.events
.key_input_disabled
.store(self.paused, Ordering::Relaxed);
Ok(())
}
pub fn reset() -> Result<()> {
terminal::disable_raw_mode()?;
ratatui::crossterm::execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture)?;
Terminal::new(CrosstermBackend::new(io::stdout()))?.show_cursor()?;
Ok(())
}
pub fn exit(&mut self) -> Result<()> {
terminal::disable_raw_mode()?;
ratatui::crossterm::execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture)?;
self.terminal.show_cursor()?;
self.events.stop();
Ok(())
}
}