diff --git a/crates/command_definitions/src/config.rs b/crates/command_definitions/src/config.rs index ab185663..d2ca10e1 100644 --- a/crates/command_definitions/src/config.rs +++ b/crates/command_definitions/src/config.rs @@ -3,10 +3,11 @@ use command_parser::parameter; use super::*; pub fn cmds() -> impl Iterator { - let ap = tokens!(["config", "cfg"], ["autoproxy", "ap"]); + let cfg = ("config", ["cfg"]); + let ap = tokens!(cfg, ("autoproxy", ["ap"])); - let ap_account = concat_tokens!(ap, [["account", "ac"]]); - let ap_timeout = concat_tokens!(ap, [["timeout", "tm"]]); + let ap_account = tokens!(ap, ("account", ["ac"])); + let ap_timeout = tokens!(ap, ("timeout", ["tm"])); [ command!(ap_account => "cfg_ap_account_show") @@ -14,9 +15,9 @@ pub fn cmds() -> impl Iterator { command!(ap_account, Toggle => "cfg_ap_account_update") .help("Toggles autoproxy for the account"), command!(ap_timeout => "cfg_ap_timeout_show").help("Shows the autoproxy timeout"), - command!(ap_timeout, parameter::RESET => "cfg_ap_timeout_reset") + command!(ap_timeout, ("reset", ["clear", "default"]) => "cfg_ap_timeout_reset") .help("Resets the autoproxy timeout"), - command!(ap_timeout, parameter::DISABLE => "cfg_ap_timeout_off") + command!(ap_timeout, parameter::Toggle::Off => "cfg_ap_timeout_off") .help("Disables the autoproxy timeout"), command!(ap_timeout, ("timeout", OpaqueString) => "cfg_ap_timeout_update") .help("Sets the autoproxy timeout"), diff --git a/crates/command_definitions/src/fun.rs b/crates/command_definitions/src/fun.rs index 63ec0054..4119b71d 100644 --- a/crates/command_definitions/src/fun.rs +++ b/crates/command_definitions/src/fun.rs @@ -2,8 +2,8 @@ use super::*; pub fn cmds() -> impl Iterator { [ - command!(["thunder"] => "fun_thunder"), - command!(["meow"] => "fun_meow"), + command!("thunder" => "fun_thunder"), + command!("meow" => "fun_meow"), ] .into_iter() } diff --git a/crates/command_definitions/src/help.rs b/crates/command_definitions/src/help.rs index d18cca3e..dd5942cd 100644 --- a/crates/command_definitions/src/help.rs +++ b/crates/command_definitions/src/help.rs @@ -1,13 +1,13 @@ use super::*; pub fn cmds() -> impl Iterator { - let help = ["help", "h"]; + let help = ("help", ["h"]); [ - command!([help] => "help") + command!(help => "help") .flag(("foo", OpaqueString)) // todo: just for testing .help("Shows the help command"), - command!([help, "commands"] => "help_commands").help("help commands"), - command!([help, "proxy"] => "help_proxy").help("help proxy"), + command!(help, "commands" => "help_commands").help("help commands"), + command!(help, "proxy" => "help_proxy").help("help proxy"), ] .into_iter() } diff --git a/crates/command_definitions/src/lib.rs b/crates/command_definitions/src/lib.rs index 96df8091..d25f1daf 100644 --- a/crates/command_definitions/src/lib.rs +++ b/crates/command_definitions/src/lib.rs @@ -18,9 +18,7 @@ pub mod server_config; pub mod switch; pub mod system; -use command_parser::{ - command, command::Command, concat_tokens, parameter::ParameterKind::*, tokens, -}; +use command_parser::{command, command::Command, parameter::ParameterKind::*, tokens}; pub fn all() -> impl Iterator { (help::cmds()) @@ -29,3 +27,5 @@ pub fn all() -> impl Iterator { .chain(config::cmds()) .chain(fun::cmds()) } + +pub const RESET: (&str, [&str; 2]) = ("reset", ["clear", "default"]); diff --git a/crates/command_definitions/src/member.rs b/crates/command_definitions/src/member.rs index 5ab968b9..504995d4 100644 --- a/crates/command_definitions/src/member.rs +++ b/crates/command_definitions/src/member.rs @@ -1,17 +1,17 @@ use super::*; pub fn cmds() -> impl Iterator { - let member = ["member", "m"]; - let description = ["description", "desc"]; - let privacy = ["privacy", "priv"]; - let new = ["new", "n"]; + let member = ("member", ["m"]); + let description = ("description", ["desc"]); + let privacy = ("privacy", ["priv"]); + let new = ("new", ["n"]); let member_target = tokens!(member, MemberRef); - let member_desc = concat_tokens!(member_target, [description]); - let member_privacy = concat_tokens!(member_target, [privacy]); + let member_desc = tokens!(member_target, description); + let member_privacy = tokens!(member_target, privacy); [ - command!([member, new, ("name", OpaqueString)] => "member_new") + command!(member, new, ("name", OpaqueString) => "member_new") .help("Creates a new system member"), command!(member_target => "member_show") .flag("pt") diff --git a/crates/command_definitions/src/system.rs b/crates/command_definitions/src/system.rs index 6093f6f1..da1d85f1 100644 --- a/crates/command_definitions/src/system.rs +++ b/crates/command_definitions/src/system.rs @@ -1,13 +1,13 @@ use super::*; pub fn cmds() -> impl Iterator { - let system = ["system", "s"]; - let new = ["new", "n"]; + let system = ("system", ["s"]); + let new = ("new", ["n"]); let system_new = tokens!(system, new); [ - command!([system] => "system_show").help("Shows information about your system"), + command!(system => "system_show").help("Shows information about your system"), command!(system_new => "system_new").help("Creates a new system"), command!(system_new, ("name", OpaqueString) => "system_new_name") .help("Creates a new system (using the provided name)"), diff --git a/crates/command_parser/src/command.rs b/crates/command_parser/src/command.rs index 027e162f..b7fd65ce 100644 --- a/crates/command_parser/src/command.rs +++ b/crates/command_parser/src/command.rs @@ -90,27 +90,7 @@ impl Display for Command { // (and something like &dyn Trait would require everything to be referenced which doesnt look nice anyway) #[macro_export] macro_rules! command { - ([$($v:expr),+] => $cb:expr$(,)*) => { + ($($v:expr),+ => $cb:expr$(,)*) => { $crate::command::Command::new($crate::tokens!($($v),+), $cb) }; - ($tokens:expr => $cb:expr$(,)*) => { - $crate::command::Command::new($tokens.clone(), $cb) - }; - ($tokens:expr, $($v:expr),+ => $cb:expr$(,)*) => { - $crate::command::Command::new($crate::concat_tokens!($tokens.clone(), [$($v),+]), $cb) - }; -} - -#[macro_export] -macro_rules! tokens { - ($($v:expr),+$(,)*) => { - [$($crate::token::Token::from($v)),+] - }; -} - -#[macro_export] -macro_rules! concat_tokens { - ($tokens:expr, [$($v:expr),+]$(,)*) => { - $tokens.clone().into_iter().chain($crate::tokens!($($v),+).into_iter()).collect::>() - }; } diff --git a/crates/command_parser/src/parameter.rs b/crates/command_parser/src/parameter.rs index c1ad77b7..297b91e9 100644 --- a/crates/command_parser/src/parameter.rs +++ b/crates/command_parser/src/parameter.rs @@ -2,6 +2,8 @@ use std::{fmt::Debug, str::FromStr}; use smol_str::SmolStr; +use crate::token::Token; + #[derive(Debug, Clone)] pub enum ParameterValue { OpaqueString(String), @@ -180,10 +182,7 @@ impl FromStr for PrivacyLevelKind { } } -pub const ENABLE: [&str; 5] = ["on", "yes", "true", "enable", "enabled"]; -pub const DISABLE: [&str; 5] = ["off", "no", "false", "disable", "disabled"]; - -#[derive(Debug, Clone, Eq, Hash, PartialEq)] +#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] pub enum Toggle { On, Off, @@ -193,10 +192,20 @@ impl FromStr for Toggle { type Err = SmolStr; fn from_str(s: &str) -> Result { - match s { - ref s if ENABLE.contains(s) => Ok(Self::On), - ref s if DISABLE.contains(s) => Ok(Self::Off), - _ => Err("invalid toggle, must be on/off".into()), + let matches_self = + |toggle: &Self| matches!(Token::from(*toggle).try_match(Some(s)), Some(Ok(None))); + [Self::On, Self::Off] + .into_iter() + .find(matches_self) + .ok_or_else(|| SmolStr::new("invalid toggle, must be on/off")) + } +} + +impl From for Token { + fn from(toggle: Toggle) -> Self { + match toggle { + Toggle::On => Self::from(("on", ["yes", "true", "enable", "enabled"])), + Toggle::Off => Self::from(("off", ["no", "false", "disable", "disabled"])), } } } @@ -209,5 +218,3 @@ impl Into for Toggle { } } } - -pub const RESET: [&str; 3] = ["reset", "clear", "default"]; diff --git a/crates/command_parser/src/token.rs b/crates/command_parser/src/token.rs index 7188012e..79300279 100644 --- a/crates/command_parser/src/token.rs +++ b/crates/command_parser/src/token.rs @@ -104,46 +104,96 @@ impl Token { impl Display for Token { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Token::Empty => write!(f, ""), - Token::Value { name, .. } => write!(f, "{name}"), - Token::Parameter(param) => param.kind().format(f, param.name()), + Self::Empty => write!(f, ""), + Self::Value { name, .. } => write!(f, "{name}"), + Self::Parameter(param) => param.kind().format(f, param.name()), + } + } +} + +impl From<(&str, [&str; L])> for Token { + fn from((name, aliases): (&str, [&str; L])) -> Self { + Self::Value { + name: name.into(), + aliases: aliases.into_iter().map(SmolStr::new).collect::>(), } } } impl From<&str> for Token { - fn from(name: &str) -> Self { - Token::Value { - name: SmolStr::new(name), - aliases: Vec::new(), - } - } -} - -impl From<[&str; L]> for Token { - fn from(value: [&str; L]) -> Self { - assert!(value.len() > 0, "can't create a Token::Value from nothing"); - Token::Value { - name: value[0].into(), - aliases: value.into_iter().skip(1).map(SmolStr::new).collect::>(), - } + fn from(value: &str) -> Self { + Self::from((value, [])) } } impl From for Token { fn from(value: Parameter) -> Self { - Token::Parameter(value) + Self::Parameter(value) } } impl From for Token { fn from(value: ParameterKind) -> Self { - Token::from(Parameter::from(value)) + Self::from(Parameter::from(value)) } } impl From<(&str, ParameterKind)> for Token { fn from(value: (&str, ParameterKind)) -> Self { - Token::from(Parameter::from(value)) + Self::from(Parameter::from(value)) } } + +#[derive(Debug, Clone)] +pub struct TokensIterator { + inner: Vec, +} + +impl Iterator for TokensIterator { + type Item = Token; + + fn next(&mut self) -> Option { + (self.inner.len() > 0).then(|| self.inner.remove(0)) + } +} + +impl> From for TokensIterator { + fn from(value: T) -> Self { + Self { + inner: vec![value.into()], + } + } +} + +impl From<[Token; L]> for TokensIterator { + fn from(value: [Token; L]) -> Self { + Self { + inner: value.into_iter().collect(), + } + } +} + +impl From<[Self; L]> for TokensIterator { + fn from(value: [Self; L]) -> Self { + Self { + inner: value + .into_iter() + .map(|t| t.collect::>()) + .flatten() + .collect(), + } + } +} + +impl From> for TokensIterator { + fn from(value: Vec) -> Self { + Self { inner: value } + } +} + +#[macro_export] +macro_rules! tokens { + ($($v:expr),+$(,)*) => { + $crate::token::TokensIterator::from([$($crate::token::TokensIterator::from($v.clone())),+]) + }; +}