gitu 0.41.0

A git client inspired by Magit
Documentation
use super::{Action, OpTrait};
use crate::{
    app::{App, PromptParams, State, root_menu},
    item_data::ItemData,
    menu::PendingMenu,
    screen::NavMode,
    term::Term,
};
use std::rc::Rc;

pub(crate) struct Quit;
impl OpTrait for Quit {
    fn get_action(&self, _target: &ItemData) -> Option<Action> {
        Some(Rc::new(|app, term| {
            let menu = app
                .state
                .pending_menu
                .as_ref()
                .map(|pending_menu| pending_menu.menu);

            if menu == root_menu(&app.state.config) {
                if app.state.screens.len() == 1 {
                    if app.state.config.general.confirm_quit.enabled {
                        app.confirm(term, "Really quit? (y or n)")?;
                    };

                    app.state.quit = true;
                } else {
                    app.state.screens.pop();
                }
            } else {
                app.close_menu();
                return Ok(());
            }

            Ok(())
        }))
    }

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

pub(crate) struct OpenMenu(pub crate::menu::Menu);
impl OpTrait for OpenMenu {
    fn get_action(&self, _target: &ItemData) -> Option<Action> {
        let submenu = self.0;
        Some(Rc::new(move |app, _term| {
            app.state.pending_menu = Some(PendingMenu::init(submenu));
            Ok(())
        }))
    }

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

pub(crate) struct Refresh;
impl OpTrait for Refresh {
    fn get_action(&self, _target: &ItemData) -> Option<Action> {
        Some(Rc::new(|app, _term| {
            app.close_menu();
            app.update_screens()
        }))
    }

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

pub(crate) struct ToggleArg(pub String);
impl OpTrait for ToggleArg {
    fn get_action(&self, _target: &ItemData) -> Option<Action> {
        let arg_name = self.0.clone();
        Some(Rc::new(move |app, term| {
            let mut need_prompt = None;
            let mut default = None;

            let maybe_entry = if let Some(menu) = &mut app.state.pending_menu {
                Some(menu.args.entry(arg_name.clone().into()))
            } else {
                None
            };

            if let Some(entry) = maybe_entry {
                entry.and_modify(|arg| {
                    if arg.is_active() {
                        arg.unset();
                    } else if arg.expects_value() {
                        default = arg.default_as_string();
                        need_prompt = Some(arg.display);
                    } else {
                        arg.set("").expect("Should succeed");
                    }
                });
            }

            let arg_name = arg_name.clone();
            let parse_and_set_arg =
                Box::new(move |app: &mut App, _term: &mut Term, value: &str| {
                    if let Some(menu) = &mut app.state.pending_menu
                        && let Some(entry) = menu.args.get_mut(arg_name.as_str())
                    {
                        return entry.set(value);
                    }

                    Ok(())
                });

            if let Some(display) = need_prompt {
                let arg = app.prompt(
                    term,
                    &PromptParams {
                        prompt: display,
                        create_default_value: Box::new(move |_| default.clone()),
                        hide_menu: false,
                    },
                )?;

                parse_and_set_arg(app, term, &arg)?;
            }

            Ok(())
        }))
    }

    fn display(&self, _state: &State) -> String {
        self.0.clone()
    }
}

pub(crate) struct ToggleSection;
impl OpTrait for ToggleSection {
    fn get_action(&self, target: &ItemData) -> Option<Action> {
        if target.is_section() {
            Some(Rc::new(|app, _term| {
                app.close_menu();
                app.screen_mut().toggle_section();
                Ok(())
            }))
        } else {
            None
        }
    }

    fn is_target_op(&self) -> bool {
        true
    }

    fn display(&self, state: &State) -> String {
        let item = state.screens.last().unwrap().get_selected_item();
        if state.screens.last().unwrap().is_collapsed(item) {
            "Unfold".into()
        } else {
            "Fold".into()
        }
    }
}

pub(crate) struct MoveUp;
impl OpTrait for MoveUp {
    fn get_action(&self, _target: &ItemData) -> Option<Action> {
        Some(Rc::new(|app, _term| {
            app.close_menu();
            app.screen_mut().select_previous(NavMode::Normal);
            Ok(())
        }))
    }

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

pub(crate) struct MoveDown;
impl OpTrait for MoveDown {
    fn get_action(&self, _target: &ItemData) -> Option<Action> {
        Some(Rc::new(|app, _term| {
            app.close_menu();
            app.screen_mut().select_next(NavMode::Normal);
            Ok(())
        }))
    }

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

pub(crate) struct MoveDownLine;
impl OpTrait for MoveDownLine {
    fn get_action(&self, _target: &ItemData) -> Option<Action> {
        Some(Rc::new(|app, _term| {
            app.close_menu();
            app.screen_mut().select_next(NavMode::IncludeHunkLines);
            Ok(())
        }))
    }

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

pub(crate) struct MoveUpLine;
impl OpTrait for MoveUpLine {
    fn get_action(&self, _target: &ItemData) -> Option<Action> {
        Some(Rc::new(|app, _term| {
            app.close_menu();
            app.screen_mut().select_previous(NavMode::IncludeHunkLines);
            Ok(())
        }))
    }

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

pub(crate) struct MoveToScreenLine(pub usize);
impl OpTrait for MoveToScreenLine {
    fn get_action(&self, _target: &ItemData) -> Option<Action> {
        let screen_line = self.0;
        Some(Rc::new(move |app, _term| {
            app.close_menu();
            app.screen_mut().move_cursor_to_screen_line(screen_line);
            Ok(())
        }))
    }

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

pub(crate) struct MoveNextSection;
impl OpTrait for MoveNextSection {
    fn get_action(&self, _target: &ItemData) -> Option<Action> {
        Some(Rc::new(|app, _term| {
            app.close_menu();
            let depth = app.screen().get_selected_item().depth;
            app.screen_mut().select_next(NavMode::Siblings { depth });
            Ok(())
        }))
    }

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

pub(crate) struct MovePrevSection;
impl OpTrait for MovePrevSection {
    fn get_action(&self, _target: &ItemData) -> Option<Action> {
        Some(Rc::new(|app, _term| {
            app.close_menu();
            let depth = app.screen().get_selected_item().depth;
            app.screen_mut()
                .select_previous(NavMode::Siblings { depth });
            Ok(())
        }))
    }

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

pub(crate) struct MoveParentSection;
impl OpTrait for MoveParentSection {
    fn get_action(&self, _target: &ItemData) -> Option<Action> {
        Some(Rc::new(|app, _term| {
            app.close_menu();
            let depth = app.screen().get_selected_item().depth.saturating_sub(1);
            app.screen_mut()
                .select_previous(NavMode::Siblings { depth });
            Ok(())
        }))
    }

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

pub(crate) struct HalfPageUp;
impl OpTrait for HalfPageUp {
    fn get_action(&self, _target: &ItemData) -> Option<Action> {
        Some(Rc::new(|app, _term| {
            app.close_menu();
            app.screen_mut().scroll_half_page_up();
            Ok(())
        }))
    }

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

pub(crate) struct HalfPageDown;
impl OpTrait for HalfPageDown {
    fn get_action(&self, _target: &ItemData) -> Option<Action> {
        Some(Rc::new(|app, _term| {
            app.close_menu();
            app.screen_mut().scroll_half_page_down();
            Ok(())
        }))
    }

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