storageshower 0.11.0

Cyberpunk disk usage TUI
Documentation
use clap::Parser;
use crossterm::event::{self, EnableMouseCapture, DisableMouseCapture, Event};
use ratatui::DefaultTerminal;
use std::io;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use sysinfo::System;

use storageshower::app::App;
use storageshower::cli::{self, Cli};
use storageshower::system::{collect_disk_entries, collect_sys_stats, spawn_bg_collector};
use storageshower::types::{DiskEntry, SysStats};
use storageshower::ui::draw;

fn main() -> io::Result<()> {
    let cli = Cli::parse();

    if cli.help {
        cli::print_help();
        return Ok(());
    }
    if cli.version {
        cli::print_version();
        return Ok(());
    }
    if cli.list_colors {
        cli::print_colors();
        return Ok(());
    }

    let sys = System::new_all();
    let initial_stats = collect_sys_stats(&sys);
    let initial_disks = collect_disk_entries();
    drop(sys);

    let shared: Arc<Mutex<(SysStats, Vec<DiskEntry>)>> =
        Arc::new(Mutex::new((initial_stats, initial_disks)));

    spawn_bg_collector(Arc::clone(&shared));

    let mut terminal = ratatui::init();
    crossterm::execute!(std::io::stdout(), EnableMouseCapture)?;
    let mut app = App::new(Arc::clone(&shared), &cli);
    let result = run_app(&mut terminal, &mut app);
    crossterm::execute!(std::io::stdout(), DisableMouseCapture)?;
    ratatui::restore();
    app.save();
    result
}

fn run_app(terminal: &mut DefaultTerminal, app: &mut App) -> io::Result<()> {
    let mut last_data_refresh = Instant::now();

    loop {
        let refresh_dur = Duration::from_secs(app.prefs.refresh_rate);
        if last_data_refresh.elapsed() >= refresh_dur {
            app.refresh_data();
            last_data_refresh = Instant::now();
        }

        terminal.draw(|f| draw(f, app))?;

        if event::poll(Duration::from_millis(200))? {
            match event::read()? {
                Event::Key(key) => {
                    if key.kind == crossterm::event::KeyEventKind::Press {
                        app.handle_key(key);
                        if app.quit {
                            return Ok(());
                        }
                    }
                }
                Event::Mouse(mouse) => {
                    let size = terminal.size()?;
                    app.handle_mouse(mouse, size.width);
                }
                Event::Resize(_, _) => {}
                _ => {}
            }
        }
    }
}