1use anyhow::{Context, Result};
2use crossterm::{
3 cursor,
4 event::{DisableMouseCapture, EnableMouseCapture},
5 terminal::{EnterAlternateScreen, LeaveAlternateScreen},
6};
7use ratatui::prelude::CrosstermBackend as Backend;
8
9pub type Frame<'a> = ratatui::Frame<'a>;
10
11pub struct Tui {
12 pub terminal: ratatui::Terminal<Backend<std::io::Stdout>>,
13}
14
15impl Tui {
16 pub fn new() -> Result<Self> {
17 let terminal = ratatui::Terminal::new(Backend::new(std::io::stdout()))
18 .context("unable to create terminal")?;
19 Ok(Self { terminal })
20 }
21
22 pub fn enter(&mut self) -> Result<()> {
23 crossterm::terminal::enable_raw_mode()?;
24 crossterm::execute!(
25 std::io::stdout(),
26 EnterAlternateScreen,
27 EnableMouseCapture,
28 cursor::Hide
29 )?;
30 self.terminal.clear()?;
31 Ok(())
32 }
33
34 pub fn exit(&mut self) -> Result<()> {
35 self.terminal.clear()?;
36 crossterm::execute!(
37 std::io::stdout(),
38 LeaveAlternateScreen,
39 DisableMouseCapture,
40 cursor::Show
41 )?;
42 crossterm::terminal::disable_raw_mode()?;
43 Ok(())
44 }
45
46 pub fn suspend(&mut self) -> Result<()> {
47 self.exit()?;
48 #[cfg(windows)]
49 signal_hook::low_level::raise(signal_hook::consts::signal::SIGABRT)?;
50 #[cfg(not(windows))]
51 signal_hook::low_level::raise(signal_hook::consts::signal::SIGSTOP)?;
52 Ok(())
53 }
54
55 pub fn resume(&mut self) -> Result<()> {
56 self.enter()?;
57 Ok(())
58 }
59}