use crate::cmd::get_os_args;
use std::collections::HashMap;
use std::fmt::Display;
#[derive(Debug)]
pub struct Args {
pub command: String,
pub sub_command: String,
pub option: Vec<String>,
pub data: HashMap<String, Vec<String>>,
pub raw: Vec<String>,
}
impl Args {
pub fn get_data(&self, key: &str) -> Option<&Vec<String>> {
if let Some(value) = self.get_value(vec![key]) {
return Some(value);
}
None
}
pub fn get_value(&self, keys: Vec<&str>) -> Option<&Vec<String>> {
if self.data.is_empty() {
return None;
}
for key in keys {
if self.data.contains_key(key) {
return self.data.get(key);
}
}
None
}
pub fn get_value_string(&self, keys: Vec<&str>) -> String {
let mut value = String::new();
if let Some(v) = self.get_value(keys) {
value = String::from(v.join(" ").trim());
}
value
}
#[deprecated(since = "2.0.1", note = "use the `get_option_string` instead")]
pub fn get_value_string_option(&self, keys: Vec<&str>) -> Option<String> {
self.get_option_string(keys)
}
pub fn get_value_i32(&self, keys: Vec<&str>) -> i32 {
if let Some(v) = self.get_option_isize(keys) {
return v as i32;
}
0
}
pub fn get_value_bool(&self, keys: Vec<&str>) -> bool {
return if let Some(v) = self.get_option_bool(keys) {
v
} else {
false
};
}
pub fn get_value_f64(&self, keys: Vec<&str>) -> f64 {
return if let Some(v) = self.get_option_f64(keys) {
v
} else {
0.0
};
}
pub fn contain_opts(&self, keys: Vec<&str>) -> bool {
for key in keys {
if self.option.contains(&String::from(key)) {
return true;
}
}
false
}
fn _args_update_data(
data: &HashMap<String, Vec<String>>,
last_opt: &String,
last_value: &Vec<String>,
) -> (HashMap<String, Vec<String>>, Vec<String>) {
let mut new_data = data.clone();
let mut new_value = last_value.clone();
if !last_opt.is_empty() && !last_value.is_empty() {
if data.contains_key(last_opt.as_str()) {
let mut exits_value = data.get(last_opt.as_str()).unwrap().to_vec();
for lv in new_value {
exits_value.push(lv);
}
new_data.insert(last_opt.clone(), exits_value.to_vec());
} else {
new_data.insert(last_opt.clone(), new_value);
}
new_value = Vec::new();
}
(new_data, new_value)
}
pub fn from_args(args: &Vec<String>) -> Args {
let mut command = String::new(); let mut sub_command = String::new(); let mut option = Vec::new();
let mut data: HashMap<String, Vec<String>> = HashMap::new();
let mut count = 0;
let mut last_opt = String::new(); let mut last_value: Vec<String> = Vec::new();
for arg in args {
let arg = &String::from(arg.trim());
if arg.is_empty() || arg.len() < 1 {
continue;
}
let mut long_opt: i32 = -1;
let mut shot_opt: i32 = -1;
let mut equal_opt: usize = 0; if let Some(vi) = arg.find("--") {
long_opt = vi as i32;
};
if let Some(vi) = arg.find("-") {
shot_opt = vi as i32;
};
if let Some(vi) = arg.find("=") {
equal_opt = vi;
}
let is_not_opt = shot_opt != 0;
if count == 0 && is_not_opt {
command = String::from(arg);
} else if count == 1 && sub_command.len() == 0 && is_not_opt {
sub_command = String::from(arg);
} else {
if long_opt == 0 || shot_opt == 0 {
let (ndt, nv) = Args::_args_update_data(&data, &last_opt, &last_value);
data = ndt;
last_value = nv;
let is_log_opt = long_opt == 0;
let split_idx = if is_log_opt { 2 } else { 1 };
let (_, opt) = arg.split_at(split_idx);
if is_log_opt {
last_opt = String::from(opt);
} else {
for by in opt.chars() {
last_opt = String::from(by);
if last_opt.find("=").is_none() {
option.push(String::from(&last_opt));
}
}
}
if let Some(vi) = last_opt.find("=") {
equal_opt = vi;
}
if equal_opt > 0 {
let (eq_key, eq_value) = last_opt.split_at(equal_opt);
last_value.push(String::from(&eq_value[1..]));
last_opt = String::from(eq_key);
}
option.push(String::from(&last_opt));
} else {
last_value.push(String::from(arg));
}
}
count += 1;
}
let (ndt, _) = Args::_args_update_data(&data, &last_opt, &last_value);
data = ndt;
Args {
command,
sub_command,
option,
data,
raw: args.to_vec(),
}
}
pub fn from_os() -> Args {
Args::from_args(&get_os_args())
}
pub fn from_str(param: &str) -> Args {
let queue = param.split(' ').collect();
let args: Vec<String> = into_string_vec(queue);
Args::from_args(&args)
}
pub fn get_option_string(&self, keys: Vec<&str>) -> Option<String> {
if let Some(v) = self.get_value(keys) {
let value = String::from(v.join(" ").trim());
return Some(value);
}
None
}
pub fn get_option_isize(&self, keys: Vec<&str>) -> Option<isize> {
if let Some(v) = self.get_option_string(keys) {
match v.parse::<isize>() {
Ok(value) => return Some(value),
Err(_) => (),
};
}
None
}
pub fn get_option_bool(&self, keys: Vec<&str>) -> Option<bool> {
if let Some(v) = self.get_option_string(keys) {
match v.parse::<bool>() {
Ok(value) => return Some(value),
Err(_) => (),
};
return Some(true);
}
None
}
pub fn get_option_f64(&self, keys: Vec<&str>) -> Option<f64> {
if let Some(v) = self.get_option_string(keys) {
match v.parse::<f64>() {
Ok(value) => return Some(value),
Err(_) => (),
};
}
None
}
}
pub trait ArgsFromOs {
fn new() -> Args;
}
impl ArgsFromOs for Args {
fn new() -> Args {
Args::from_os()
}
}
pub trait ArgsNew<T> {
fn new(param: T) -> Self;
}
impl ArgsNew<&Vec<String>> for Args {
fn new(param: &Vec<String>) -> Self {
Args::from_args(¶m)
}
}
impl<T> ArgsNew<Vec<T>> for Args
where
T: Display,
{
fn new(param: Vec<T>) -> Self {
let args: Vec<String> = into_string_vec(param);
Args::from_args(&args)
}
}
fn into_string_vec<T>(args: Vec<T>) -> Vec<String>
where
T: Display,
{
let mut value: Vec<String> = Vec::new();
for arg in args {
value.push(format!("{}", arg));
}
value
}
impl Clone for Args {
fn clone(&self) -> Self {
Args {
command: self.command.clone(),
sub_command: self.sub_command.clone(),
option: self.option.clone(),
data: self.data.clone(),
raw: self.raw.clone(),
}
}
}