use std::io;
use anyhow::Result;
use crossterm::terminal::{self, EnterAlternateScreen, LeaveAlternateScreen};
use ratatui::{backend::Backend, Terminal};
use crate::{app::App, event::EventHandler};
#[derive(Debug)]
pub struct Tui<B: Backend> {
terminal: Terminal<B>,
pub events: EventHandler,
}
impl<B: Backend> Tui<B> {
pub fn new(terminal: Terminal<B>, events: EventHandler) -> Self {
Self { terminal, events }
}
pub fn init(&mut self) -> Result<()> {
terminal::enable_raw_mode()?;
crossterm::execute!(io::stderr(), EnterAlternateScreen)?;
self.terminal.hide_cursor()?;
self.terminal.clear()?;
self.events.init();
Ok(())
}
pub fn draw(&mut self, app: &mut App) -> Result<()> {
self.terminal.draw(|frame| app.render(frame))?;
Ok(())
}
pub fn exit(&mut self) -> Result<()> {
terminal::disable_raw_mode()?;
crossterm::execute!(io::stderr(), LeaveAlternateScreen)?;
self.terminal.show_cursor()?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use ratatui::{
backend::TestBackend,
buffer::Buffer,
style::{Color, Modifier, Style},
Terminal,
};
use super::*;
use crate::args::parse_args;
#[test]
fn new() {
let backend = TestBackend::new(13, 10);
let terminal = Terminal::new(backend).unwrap();
let events = EventHandler::new(1);
let mut app = App::new(Some(parse_args()));
app.raw_buffer.state.color = Color::White;
let mut tui = Tui::new(terminal, events);
tui.draw(&mut app).unwrap();
let mut expected = Buffer::with_lines(vec![
"┌[0]'.*' (0)┐",
"│ │",
"│ │",
"│ │",
"│ │",
"│ │",
"│ │",
"│ │",
"│ │",
"└───────────┘",
]);
let bolds = 1..=11;
for x in 0..=12 {
for y in 0..=9 {
if bolds.contains(&x) && y == 0 {
expected[(x, y)].set_style(Style::default().add_modifier(Modifier::BOLD));
}
expected[(x, y)].set_fg(Color::White);
expected[(x, y)].set_bg(Color::Black);
}
}
tui.terminal.backend().assert_buffer(&expected);
tui.exit().unwrap();
}
}