use crate::client::{ClientOpts, ConfigGetOpt, ConfigSetOpt};
use std::env::{self, Args};
use super::HelpType;
pub enum CliOpts {
Command(ClientOpts),
Help(ParseError, HelpType),
}
pub struct ParseError(i8);
pub const NO_PARSE_ERROR: ParseError = ParseError(0);
pub const PARSE_ERROR: ParseError = ParseError(1);
impl ParseError {
pub fn code(self) -> i32 {
self.0 as i32
}
}
impl CliOpts {
pub fn parse() -> CliOpts {
let mut args = env::args();
args.next();
let cmd = args.next();
match cmd {
Some(cmdname) => {
if cmdname == "help" {
Self::Help(PARSE_ERROR, HelpType::None)
} else {
dispatcher::dispatch(&cmdname, &mut args)
}
}
None => Self::Help(NO_PARSE_ERROR, HelpType::None),
}
}
fn parse_config_set(args: &mut Args) -> CliOpts {
let subcommand = args.next();
let setting = args.next();
match (subcommand, setting) {
(Some(option), Some(value)) => match option.as_str() {
"input" => Self::Command(ClientOpts::ConfigSet(ConfigSetOpt::Kconfig(
value.to_string(),
))),
"output" => Self::Command(ClientOpts::ConfigSet(ConfigSetOpt::Dotconfig(
value.to_string(),
))),
_ => {
eprintln!("⛔ Option {option} does not exist");
CliOpts::Help(PARSE_ERROR, HelpType::Set)
}
},
(Some(option), _) => match option.as_str() {
"input" => {
Self::Command(ClientOpts::ConfigSet(ConfigSetOpt::Kconfig("".to_owned())))
}
"output" => Self::Command(ClientOpts::ConfigSet(ConfigSetOpt::Dotconfig(
"".to_owned(),
))),
"--help" => CliOpts::Help(NO_PARSE_ERROR, HelpType::Set),
_ => {
eprintln!(
"⛔ Wrong amount of arguments to set command, expected two arguments"
);
CliOpts::Help(PARSE_ERROR, HelpType::Set)
}
},
_ => {
eprintln!("⛔ Wrong amount of arguments to set command, expected two arguments");
CliOpts::Help(PARSE_ERROR, HelpType::Set)
}
}
}
fn parse_config_get(args: &mut Args) -> CliOpts {
let subcommand = args.next();
match subcommand {
Some(option) => match option.as_str() {
"input" => Self::Command(ClientOpts::ConfigGet(ConfigGetOpt::Kconfig)),
"output" => Self::Command(ClientOpts::ConfigGet(ConfigGetOpt::Dotconfig)),
"list" => Self::Command(ClientOpts::ConfigGet(ConfigGetOpt::List)),
"--help" => CliOpts::Help(NO_PARSE_ERROR, HelpType::Get),
_ => {
eprintln!("⛔ Option {option} does not exist");
CliOpts::Help(PARSE_ERROR, HelpType::Get)
}
},
_ => {
eprintln!("⛔ Wrong amount of arguments to get command, expected two arguments");
CliOpts::Help(PARSE_ERROR, HelpType::Get)
}
}
}
fn parse_list(args: &mut Args) -> CliOpts {
let result: Vec<String> = args.collect();
for v in &result {
if v == "--help" {
return CliOpts::Help(NO_PARSE_ERROR, HelpType::List);
}
}
CliOpts::Command(ClientOpts::List(result))
}
fn parse_info(args: &mut Args) -> CliOpts {
let value = args.next();
match value {
Some(value) => {
if value == "--help" {
CliOpts::Help(NO_PARSE_ERROR, HelpType::Info)
} else {
CliOpts::Command(ClientOpts::Info(value))
}
}
_ => {
eprintln!("⛔ Wrong amount of arguments to info command, expected one argument");
CliOpts::Help(PARSE_ERROR, HelpType::Info)
}
}
}
fn parse_update(args: &mut Args) -> CliOpts {
let value = args.next();
match value {
Some(value) => {
if value == "--help" {
CliOpts::Help(NO_PARSE_ERROR, HelpType::Update)
} else {
CliOpts::Command(ClientOpts::Update(value))
}
}
_ => {
eprintln!("⛔ Wrong amount of arguments to update command, expected one argument");
CliOpts::Help(PARSE_ERROR, HelpType::Update)
}
}
}
}
mod dispatcher {
use std::{collections::HashMap, env::Args, sync::Once};
use crate::cli::{HelpType, PARSE_ERROR};
use super::CliOpts;
#[derive(Clone)]
struct Dispatched {
callback: fn(&mut Args) -> CliOpts,
}
pub(super) fn dispatch(cmdname: &str, args: &mut Args) -> CliOpts {
match get_subcommands().get(cmdname) {
Some(dispatched) => (dispatched.callback)(args),
None => {
eprintln!("⛔ Invalid command {cmdname} received");
CliOpts::Help(PARSE_ERROR, HelpType::None)
}
}
}
static mut SUBCOMMANDS: Option<HashMap<String, Dispatched>> = None;
static START: Once = Once::new();
fn get_subcommands() -> &'static HashMap<String, Dispatched> {
START.call_once(|| unsafe {
let mut map = HashMap::new();
add_command(&mut map, "config-set", super::CliOpts::parse_config_set);
add_command(&mut map, "config-get", super::CliOpts::parse_config_get);
add_command(&mut map, "list", super::CliOpts::parse_list);
add_command(&mut map, "ls", super::CliOpts::parse_list);
add_command(&mut map, "info", super::CliOpts::parse_info);
add_command(&mut map, "update", super::CliOpts::parse_update);
SUBCOMMANDS = Some(map);
});
unsafe {
match &SUBCOMMANDS {
Some(subcommands) => subcommands,
None => panic!("⛔ Subcommand-map not initialized"),
}
}
}
fn add_command(
map: &mut HashMap<String, Dispatched>,
name: &str,
callback: fn(&mut Args) -> CliOpts,
) {
map.insert(name.to_owned(), Dispatched { callback });
}
}