Skip to main content

gitkit_cli/
lib.rs

1use clap::Parser;
2use crossterm::{
3    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyEventKind},
4    terminal::{self, EnterAlternateScreen, LeaveAlternateScreen},
5};
6use std::{io, panic, time::Duration};
7
8use ratatui::{Terminal, backend::CrosstermBackend};
9
10use crate::{
11    error::Result,
12    git::kit::KitRepo,
13    tui::{state::TuiState, ui::render},
14    worker::Worker,
15};
16
17pub mod error;
18pub mod git;
19pub mod metrics;
20pub mod tui;
21pub mod worker;
22
23#[derive(Parser, Debug)]
24#[command(version, about, long_about = None)]
25pub struct GKitArgs {
26    #[arg(default_value = ".")]
27    target_path: String,
28
29    #[arg(long, hide = true)]
30    pub debug: bool,
31}
32
33pub fn run(args: GKitArgs) -> Result<()> {
34    let repo = KitRepo::open(args.target_path)?;
35
36    if args.debug {
37        println!("Debug Mode\n");
38        let x = repo.list_branch();
39        // println!("{:?}", x.len());
40
41        return Ok(());
42    }
43    let mut state = TuiState::new(&repo)?; // blocking
44
45    let backend = CrosstermBackend::new(io::stdout());
46    let mut terminal = Terminal::new(backend)?;
47
48    terminal::enable_raw_mode()?;
49    ratatui::crossterm::execute!(io::stdout(), EnterAlternateScreen, EnableMouseCapture)?;
50
51    panic::set_hook(Box::new(move |panic| {
52        let _ = terminal::disable_raw_mode();
53        let _ =
54            ratatui::crossterm::execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture);
55        eprintln!("Panic??: {}", panic);
56    }));
57
58    terminal.hide_cursor()?;
59    terminal.clear()?;
60
61    let tui_result = tui(&mut terminal, &mut state, &repo);
62
63    let _ = terminal.show_cursor();
64    let _ = ratatui::crossterm::execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture);
65    let _ = terminal::disable_raw_mode();
66
67    tui_result // returns once drawing stops
68}
69
70pub fn tui<'a>(
71    terminal: &mut Terminal<CrosstermBackend<io::Stdout>>,
72    state: &mut TuiState,
73    repo: &'a KitRepo,
74) -> Result<()> {
75    let repo_path = repo.inner.path().to_path_buf();
76
77    let worker = Worker::start(repo_path);
78
79    while !state.is_quit {
80        terminal.draw(|frame| render(frame, state))?;
81
82        if state.refresh {
83            state.refresh = false;
84            state.loading = true;
85            worker.trigger_refresh();
86        }
87
88        // when chan gets message do refresh
89        if let Ok(payload) = worker.payload_rx.try_recv() {
90            state.refresh(payload);
91        }
92
93        if event::poll(Duration::from_millis(16))? {
94            if let Event::Key(key) = event::read()? {
95                if key.kind == KeyEventKind::Press {
96                    state.handle_key_event(key, repo);
97                }
98            }
99        }
100    }
101
102    worker.quit();
103
104    Ok(())
105}