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