ziyy 2.0.3

Terminal Styling using HTML-like syntax.
Documentation
#![allow(dead_code)]
use std::{env::Args, fmt::Display};

#[derive(Debug)]
pub enum Arg {
    ShortFlag(String, String),
    LongFlag(String, String),
    ShortSwitch(String),
    LongSwitch(String),
    Param(String),
}

impl Arg {
    pub fn is_long_switch_and(&self, f: fn(&String) -> bool) -> bool {
        match self {
            Arg::LongSwitch(s) => f(s),
            _ => false,
        }
    }

    pub fn is_short_switch_and(&self, f: fn(&String) -> bool) -> bool {
        match self {
            Arg::ShortSwitch(s) => f(s),
            _ => false,
        }
    }

    #[allow(clippy::wrong_self_convention)]
    pub fn is_params_and(self, mut f: impl FnMut(String)) {
        if let Arg::Param(s) = self {
            f(s)
        }
    }
}

#[derive(Debug)]
pub enum Error {
    Long(String),
    Short(String),
}

impl Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Error::Long(v) => f.write_fmt(format_args!("--{v}")),
            Error::Short(v) => f.write_fmt(format_args!("-{v}")),
        }
    }
}

pub struct Cli<'a> {
    pub short_flags: &'a [&'a str],
    pub long_flags: &'a [&'a str],
    pub short_switches: &'a [&'a str],
    pub long_switches: &'a [&'a str],
}

fn split_args(args0: Args) -> Vec<String> {
    let mut args: Vec<String> = vec![];

    for arg in args0 {
        if let Some(ch) = arg.strip_prefix('-') {
            if ch.starts_with('-') {
                args.push(arg.clone());
                continue;
            }

            let _: Vec<_> = ch.chars().map(|v| args.push(format!("-{v}"))).collect();
            continue;
        }

        args.push(arg.clone());
    }

    args
}

pub fn parse_args(args0: Args, cli: Cli) -> Result<Vec<Arg>, Error> {
    let _args0 = split_args(args0);
    let mut parts = _args0.split(|x| x == "--");
    let args0 = parts.next().unwrap();
    let mut args = vec![];

    let mut i = 0;
    let length = args0.len();
    while i < length {
        let arg = args0[i].clone();
        if let Some(arg) = arg.strip_prefix("--") {
            if arg.contains('=') {
                let mut split = arg.split('=');
                let key = split.next().unwrap();
                let value = split.collect::<Vec<_>>().join("=");
                if cli.long_flags.contains(&key) {
                    args.push(Arg::LongFlag(key.to_owned(), value));
                } else {
                    return Err(Error::Long(key.to_owned()));
                }
            } else {
                let key = arg;
                if cli.long_flags.contains(&key) {
                    args.push(Arg::LongFlag(key.to_owned(), args0[i + 1].clone()));
                    i += 1;
                } else if cli.long_switches.contains(&key) {
                    args.push(Arg::LongSwitch(key.to_owned()));
                } else {
                    return Err(Error::Long(key.to_owned()));
                }
            }
        } else if let Some(arg) = arg.strip_prefix("-") {
            if arg.contains('=') {
                let mut split = arg.split('=');
                let key = split.next().unwrap();
                let value = split.collect::<Vec<_>>().join("=");
                if cli.short_flags.contains(&key) {
                    args.push(Arg::ShortFlag(key.to_owned(), value));
                } else {
                    return Err(Error::Short(key.to_owned()));
                }
            } else {
                let key = arg;
                if cli.short_flags.contains(&key) {
                    args.push(Arg::ShortFlag(key.to_owned(), args0[i + 1].clone()));
                    i += 1;
                } else if cli.short_switches.contains(&key) {
                    args.push(Arg::ShortSwitch(key.to_owned()));
                } else {
                    return Err(Error::Short(key.to_owned()));
                }
            }
        } else {
            args.push(Arg::Param(arg));
        }
        i += 1;
    }

    args.extend(
        parts
            .collect::<Vec<_>>()
            .join(&String::from("--"))
            .iter()
            .map(|x| Arg::Param(x.clone())),
    );

    Ok(args)
}