1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]

use std::{
    fmt::{Display, Formatter, Result as FmtResult},
    process::{Command, Stdio},
};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

/// Corrects arguments passed to `gi_t` into the corresponding `git` command.
///
/// # Arguments
/// * `args` - the arguments to the program in Vec form.
///
/// # Errors
/// If the function receives malformed arguments or runs into errors setting terminal colors or
/// spawning a child process, the corresponding [`GiError`] will be returned.
pub fn process_args(mut args: Vec<String>) -> Result<(), GiError> {
    // remove program name
    args.remove(0);

    // save original arguments
    let original = args.join(" ");

    // expect some arguments (not just `gi`)
    if args.is_empty() {
        return Err(GiError::NoArgs);
    }

    // if the first argument doesn't start with a `t`, it's too far away to assume it should be git
    if !args[0].starts_with('t') {
        return Err(GiError::BadPrefix);
    }

    args[0].remove(0);

    if args[0].is_empty() {
        args.remove(0);
    }

    let mut stdout = StandardStream::stdout(ColorChoice::Auto);

    if stdout
        .set_color(ColorSpec::new().set_fg(Some(Color::Green)))
        .is_err()
    {
        return Err(GiError::StdoutSet);
    }

    println!(
        "Correcting `gi {}` to `git{}{}`...",
        original,
        if args.is_empty() { "" } else { " " },
        args.join(" ")
    );

    if stdout.reset().is_err() {
        return Err(GiError::StdoutReset);
    }

    println!();

    if Command::new("git")
        .args(&args)
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .output()
        .is_err()
    {
        return Err(GiError::GitFail);
    }

    Ok(())
}

/// An enum to describe different errors that could occur while executing `gi_t`.
#[derive(Debug, Clone)]
pub enum GiError {
    /// The first argument does not begin with a `t`.
    BadPrefix,

    /// Spawning `git` child process results in a failure.
    GitFail,

    /// No arguments are passed to `gi_t`.
    NoArgs,

    /// A failure is encountered resetting stdout terminal color.
    StdoutReset,

    /// A failure is encountered setting stdout terminal color.
    StdoutSet,
}

impl GiError {
    /// A helper method to print the associated error message for a [`GiError`].
    pub fn print(self) {
        StandardStream::stderr(ColorChoice::Always)
            .set_color(ColorSpec::new().set_fg(Some(Color::Red)))
            .expect("Unable to set stderr color!");

        println!("{}", self)
    }
}

impl Display for GiError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(
            f,
            "{}",
            match &self {
                Self::BadPrefix => "Argument does not start with a `t`!",
                Self::GitFail => "Failed to run git!",
                Self::NoArgs => "No arguments provided!",
                Self::StdoutReset => "Unable to reset stdout color!",
                Self::StdoutSet => "Unable to set stdout color!,",
            }
        )
    }
}