gitu 0.41.0

A git client inspired by Magit
Documentation
use super::{Action, OpTrait, selected_rev};
use crate::{
    Res,
    app::{App, PromptParams, State},
    error::Error,
    item_data::{ItemData, Rev},
    menu::arg::{Arg, any_regex, positive_number},
    screen,
    term::Term,
};
use git2::Oid;
use regex::Regex;
use std::{rc::Rc, sync::Arc};

pub(crate) fn init_args() -> Vec<Arg> {
    vec![
        Arg::new_arg(
            "-n",
            "Limit number of commits",
            Some(|| 256),
            positive_number,
        ),
        Arg::new_arg("--grep", "Search messages", None, any_regex),
        // Arg::new_str("-S", "Search occurrences"), // TODO: Implement search
    ]
}

pub(crate) struct LogCurrent;
impl OpTrait for LogCurrent {
    fn get_action(&self, _target: &ItemData) -> Option<Action> {
        Some(Rc::new(|app: &mut App, _term: &mut Term| {
            goto_log_screen(app, None);
            Ok(())
        }))
    }

    fn display(&self, _state: &State) -> String {
        "current".into()
    }
}

pub(crate) struct LogOther;
impl OpTrait for LogOther {
    fn get_action(&self, _target: &ItemData) -> Option<Action> {
        Some(Rc::new(move |app: &mut App, term: &mut Term| {
            let rev = app.prompt(
                term,
                &PromptParams {
                    prompt: "Log rev",
                    create_default_value: Box::new(|app| {
                        selected_rev(app)
                            .as_ref()
                            .map(Rev::shorthand)
                            .map(String::from)
                    }),
                    ..Default::default()
                },
            )?;

            log_other(app, term, &rev)?;
            Ok(())
        }))
    }

    fn display(&self, _state: &State) -> String {
        "other".into()
    }
}

fn log_other(app: &mut App, _term: &mut Term, result: &str) -> Res<()> {
    let oid_result = match app.state.repo.revparse_single(result) {
        Ok(rev) => Ok(rev.id()),
        Err(err) => Err(Error::FindGitRev(err)),
    };

    if oid_result.is_err() {
        app.close_menu();
    }

    let oid = oid_result?;

    goto_log_screen(app, Some(oid));
    Ok(())
}

fn goto_log_screen(app: &mut App, rev: Option<Oid>) {
    app.state.screens.drain(1..);
    let size = app.state.screens.last().unwrap().size;
    let limit = *app
        .state
        .pending_menu
        .as_ref()
        .and_then(|m| m.args.get("-n"))
        .and_then(|arg| arg.value_as::<u32>())
        .unwrap_or(&u32::MAX);

    let msg_regex_menu = app
        .state
        .pending_menu
        .as_ref()
        .and_then(|m| m.args.get("--grep"));

    let msg_regex = msg_regex_menu.and_then(|arg| arg.value_as::<Regex>().cloned());

    app.close_menu();

    app.state.screens.push(
        screen::log::create(
            Arc::clone(&app.state.config),
            Rc::clone(&app.state.repo),
            size,
            limit as usize,
            rev,
            msg_regex,
        )
        .expect("Couldn't create screen"),
    );
}