aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
blob: 56016d3831b6df5398e81ef616cf034a822c4236 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
mod app;
mod event;
mod gentoo;
mod theme;
mod ui;

use std::{
    io::{self, Stdout, stdout},
    panic::{set_hook, take_hook},
};

use ratatui::{
    Terminal,
    backend::Backend,
    crossterm::{
        execute,
        terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
    },
    prelude::CrosstermBackend,
};

use crate::{app::App, event::handle_event, gentoo::Portage, ui::ui};

struct TuiGuard;

impl Drop for TuiGuard {
    fn drop(&mut self) {
        _ = restore_tui();
    }
}

fn main() -> color_eyre::Result<()> {
    color_eyre::install()?;
    init_panic_hook();

    let _guard = TuiGuard;

    let mut tui = init_tui()?;

    let mut p = Portage::new();
    p.load_world_packages()?;
    p.load_installed_packages()?;

    let mut app = App::new(p);

    run(&mut tui, &mut app)?;

    Ok(())
}

fn run<B: Backend>(terminal: &mut Terminal<B>, app: &mut App) -> io::Result<()>
where
    io::Error: From<B::Error>,
{
    loop {
        terminal.draw(|frame| ui(frame, app))?;
        let should_exit = handle_event(app)?;
        if should_exit {
            break;
        }
    }

    Ok(())
}

fn init_tui() -> io::Result<ratatui::Terminal<CrosstermBackend<Stdout>>> {
    enable_raw_mode()?;
    execute!(stdout(), EnterAlternateScreen)?;
    Terminal::new(CrosstermBackend::new(stdout()))
}

fn init_panic_hook() {
    let original_hook = take_hook();
    set_hook(Box::new(move |panic_info| {
        let _ = restore_tui();
        original_hook(panic_info);
    }));
}

fn restore_tui() -> io::Result<()> {
    disable_raw_mode()?;
    execute!(stdout(), LeaveAlternateScreen)?;
    Ok(())
}