git_iblame/
cli.rs

1use std::{io::stdout, path::Path};
2
3use crate::*;
4use crossterm::{clipboard::CopyToClipboard, execute, terminal};
5use git2::Oid;
6use log::*;
7
8pub struct Cli {
9    renderer: BlameRenderer,
10    commit_ids: Vec<Oid>,
11}
12
13impl Cli {
14    pub fn new(path: &Path) -> anyhow::Result<Self> {
15        Ok(Self {
16            renderer: BlameRenderer::new(path)?,
17            commit_ids: vec![],
18        })
19    }
20
21    pub fn run(&mut self) -> anyhow::Result<()> {
22        terminal::enable_raw_mode()?;
23        let result = self.run_core();
24        if let Err(e) = terminal::disable_raw_mode() {
25            warn!("Failed to disable raw mode, ignored: {e}");
26        }
27        result
28    }
29
30    fn run_core(&mut self) -> anyhow::Result<()> {
31        let renderer = &mut self.renderer;
32        let size = terminal::size()?;
33        renderer.set_size((size.0, size.1 - 1));
34        renderer.read()?;
35        let mut out = stdout();
36        let prompt = String::new();
37        loop {
38            renderer.render(&mut out)?;
39
40            let command = Command::read(renderer.rendered_rows(), &prompt)?;
41            match command {
42                Command::PrevDiff => renderer.move_to_prev_diff(),
43                Command::NextDiff => renderer.move_to_next_diff(),
44                Command::PageUp => renderer.move_to_prev_page(),
45                Command::PageDown => renderer.move_to_next_page(),
46                Command::FirstLine => renderer.move_to_first_line(),
47                Command::LastLine => renderer.move_to_last_line(),
48                Command::LineNumber(number) => renderer.set_current_number(number),
49                Command::Older => {
50                    let id = renderer.newest_commit_id();
51                    renderer.set_newest_commit_id_to_older()?;
52                    self.commit_ids.push(id);
53                }
54                Command::Newer => {
55                    if let Some(id) = self.commit_ids.pop() {
56                        renderer.set_newest_commit_id(id)?;
57                    }
58                }
59                Command::Copy => execute!(
60                    out,
61                    CopyToClipboard::to_clipboard_from(renderer.current_commit_id().to_string())
62                )?,
63                Command::Resize(columns, rows) => renderer.set_size((columns, rows - 1)),
64                Command::Quit => break,
65            }
66        }
67        Ok(())
68    }
69}