verco 5.5.1

A simple Git/Hg version control client based on keyboard shortcuts
use std::{
    env,
    fs::File,
    io::{self, BufRead, BufReader},
    process::Command,
};

use crate::action::ActionResult;

pub struct CustomAction {
    pub shortcut: String,
    pub command: String,
    pub args: Vec<String>,
}

impl CustomAction {
    pub fn load_custom_actions() -> Vec<CustomAction> {
        Self::try_load_custom_actions().unwrap_or(Vec::new())
    }

    fn try_load_custom_actions() -> io::Result<Vec<CustomAction>> {
        let mut path = env::current_dir()?;
        path.push(concat!(".", env!("CARGO_PKG_NAME"), "/custom_actions.txt"));
        if !path.exists() {
            return Ok(Vec::new());
        }

        let file = File::open(path)?;
        let mut reader = BufReader::new(file);

        let mut actions = Vec::new();
        let mut line = String::new();
        while next_line(&mut reader, &mut line) {
            let line = line.trim();
            if line.len() == 0 {
                continue;
            }

            let mut it = line.split(' ');

            let shortcut = it.nth(0);
            if shortcut.is_none() {
                continue;
            }

            let command = it.nth(0);
            if command.is_none() {
                continue;
            }

            let command = CustomAction {
                shortcut: shortcut.unwrap().into(),
                command: command.unwrap().into(),
                args: it.map(|s| s.into()).collect(),
            };
            actions.push(command);
        }

        Ok(actions)
    }

    pub fn execute(&self, current_dir: &str) -> ActionResult {
        let mut command = Command::new(&self.command);
        command.current_dir(current_dir);
        for a in &self.args {
            command.arg(a);
        }

        match command.output() {
            Ok(output) => {
                if output.status.success() {
                    ActionResult::from_ok(
                        String::from_utf8_lossy(&output.stdout[..])
                            .into_owned(),
                    )
                } else {
                    let mut out = String::new();
                    out.push_str(
                        &String::from_utf8_lossy(&output.stdout[..])
                            .into_owned()[..],
                    );
                    out.push('\n');
                    out.push('\n');
                    out.push_str(
                        &String::from_utf8_lossy(&output.stderr[..])
                            .into_owned()[..],
                    );
                    ActionResult::from_err(out)
                }
            }
            Err(error) => ActionResult::from_err(error.to_string()),
        }
    }
}

fn next_line<R: BufRead>(reader: &mut R, line: &mut String) -> bool {
    line.clear();
    reader.read_line(line).unwrap_or(0) > 0
}