ecla 1.0.0

Easily build command line apps
Documentation

use std::env;
use std::collections::HashMap;
use command::Command;
use flag::Flag;
use show_help_tips;


#[derive(Debug)]
pub struct Parser {
    args: Vec<String>,
    command: Option<Command>,
    flags: HashMap<String, Flag>
}

impl Parser {
    pub fn new() -> Parser {
        let mut args = env::args().collect::<Vec<String>>();
        args.remove(0);
        let mut parser = Parser {
            args: args,
            command: None,
            flags: HashMap::new()
        };

        parser.parse();
        parser
    }

    pub fn get_command(&self, name: &str) -> Option<Command> {
        if self.command.is_none() || self.command.as_ref().unwrap().get_name() != name {
            None
        } else {
            self.command.clone()
        }
    }

    pub fn get_unknown_command(&self) -> Command {
        self.command.clone().unwrap()
    }

    pub fn get_flag(&self, name: &str) -> Option<Flag> {
        match self.flags.get(name) {
            Some(flag) => Some(flag.clone()),
            None => None
        }
    }

    pub fn no_args(&self) -> bool {
        self.args.is_empty()
    }

    pub fn has_flag(&self) -> bool {
        ! self.flags.is_empty()
    }

    pub fn no_command(&self) -> bool {
        self.command.is_none()
    }

    fn is_command(&self) -> bool {
        ! self.args.is_empty() && ! is_flag(self.args.get(0).unwrap())
    }

    fn parse(&mut self) {
        if ! self.args.is_empty() {
            if self.is_command() {
                self.command = Some(parse_command(&self.args));
            } else {
                self.flags = parse_flags(&self.args);
            }
        }
    }
}

fn is_flag(arg: &str) -> bool {
    arg.starts_with('-')
}

fn parse_command(args: &[String]) -> Command {
    let mut command = Command::new(args.first().unwrap().clone());

    if args.len() > 1 {
        for (index, arg) in args[1..].iter().enumerate() {
            if is_flag(arg) {
                command.set_flags(parse_flags(&args[(index+1)..]));
            } else {
                command.add_value(arg.clone());
            }
        }
    }

    command
}

fn parse_flags(args: &[String]) -> HashMap<String, Flag> {
    let mut flags = HashMap::new();
    let mut prev_name: Option<String> = None;
    let len = args.len();

    for (index, arg) in args.iter().enumerate() {
        if arg.starts_with('-') {
            if prev_name.is_some() {
                let name = prev_name.take().unwrap();
                flags.insert(name.clone(), Flag::new(name.clone(), None));
            }

            if index + 1 == len {
                flags.insert(arg.clone(), Flag::new(arg.clone(), None));
            } else {
                prev_name = Some(arg.clone());
            }
        } else {
            if prev_name.is_some() {
                let name = prev_name.take().unwrap();
                flags.insert(name.clone(), Flag::new(name.clone(), Some(arg.clone())));
            } else {
                invalid_arguments();
            }
        }
    }

    flags
}

fn invalid_arguments() {
    errors!("invalid arguments");
    show_help_tips();
}