mirror of
https://github.com/PluralKit/PluralKit.git
synced 2026-02-12 08:40:11 +00:00
feat(command_parser): allow aliases in flags
This commit is contained in:
parent
bf5e448aad
commit
ff6dc12cae
4 changed files with 51 additions and 17 deletions
|
|
@ -4,7 +4,7 @@ pub fn cmds() -> impl Iterator<Item = Command> {
|
||||||
let help = ["help", "h"];
|
let help = ["help", "h"];
|
||||||
[
|
[
|
||||||
command!([help] => "help")
|
command!([help] => "help")
|
||||||
.value_flag("foo", OpaqueString) // todo: just for testing
|
.flag(("foo", OpaqueString)) // todo: just for testing
|
||||||
.help("Shows the help command"),
|
.help("Shows the help command"),
|
||||||
command!([help, "commands"] => "help_commands").help("help commands"),
|
command!([help, "commands"] => "help_commands").help("help commands"),
|
||||||
command!([help, "proxy"] => "help_proxy").help("help proxy"),
|
command!([help, "proxy"] => "help_proxy").help("help proxy"),
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::fmt::{Debug, Display};
|
||||||
|
|
||||||
use smol_str::SmolStr;
|
use smol_str::SmolStr;
|
||||||
|
|
||||||
use crate::{flag::Flag, parameter::*, token::Token};
|
use crate::{flag::Flag, token::Token};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Command {
|
pub struct Command {
|
||||||
|
|
@ -57,13 +57,8 @@ impl Command {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flag(mut self, name: impl Into<SmolStr>) -> Self {
|
pub fn flag(mut self, flag: impl Into<Flag>) -> Self {
|
||||||
self.flags.push(Flag::new(name));
|
self.flags.push(flag.into());
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn value_flag(mut self, name: impl Into<SmolStr>, value: ParameterKind) -> Self {
|
|
||||||
self.flags.push(Flag::new(name).with_value(value));
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ pub enum FlagValueMatchError {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Flag {
|
pub struct Flag {
|
||||||
name: SmolStr,
|
name: SmolStr,
|
||||||
|
aliases: Vec<SmolStr>,
|
||||||
value: Option<ParameterKind>,
|
value: Option<ParameterKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,26 +39,36 @@ impl Flag {
|
||||||
pub fn new(name: impl Into<SmolStr>) -> Self {
|
pub fn new(name: impl Into<SmolStr>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
|
aliases: Vec::new(),
|
||||||
value: None,
|
value: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_value(mut self, param: ParameterKind) -> Self {
|
pub fn value(mut self, param: ParameterKind) -> Self {
|
||||||
self.value = Some(param);
|
self.value = Some(param);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn alias(mut self, alias: impl Into<SmolStr>) -> Self {
|
||||||
|
self.aliases.push(alias.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_name(&self) -> &str {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value_kind(&self) -> Option<ParameterKind> {
|
pub fn get_value(&self) -> Option<ParameterKind> {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_aliases(&self) -> impl Iterator<Item = &str> {
|
||||||
|
self.aliases.iter().map(|s| s.as_str())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn try_match(&self, input_name: &str, input_value: Option<&str>) -> TryMatchFlagResult {
|
pub fn try_match(&self, input_name: &str, input_value: Option<&str>) -> TryMatchFlagResult {
|
||||||
// if not matching flag then skip anymore matching
|
// if not matching the name or any aliases then skip anymore matching
|
||||||
if self.name != input_name {
|
if self.name != input_name && self.get_aliases().all(|s| s.ne(input_name)) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
// get token to try matching with, if flag doesn't have one then that means it is matched (it is without any value)
|
// get token to try matching with, if flag doesn't have one then that means it is matched (it is without any value)
|
||||||
|
|
@ -82,3 +93,31 @@ impl Flag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Flag {
|
||||||
|
fn from(name: &str) -> Self {
|
||||||
|
Flag::new(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(&str, ParameterKind)> for Flag {
|
||||||
|
fn from((name, value): (&str, ParameterKind)) -> Self {
|
||||||
|
Flag::new(name).value(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const L: usize> From<[&str; L]> for Flag {
|
||||||
|
fn from(value: [&str; L]) -> Self {
|
||||||
|
let mut flag = Flag::new(value[0]);
|
||||||
|
for alias in &value[1..] {
|
||||||
|
flag = flag.alias(*alias);
|
||||||
|
}
|
||||||
|
flag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const L: usize> From<([&str; L], ParameterKind)> for Flag {
|
||||||
|
fn from((names, value): ([&str; L], ParameterKind)) -> Self {
|
||||||
|
Flag::from(names).value(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ pub fn parse_command(
|
||||||
FlagMatchError::ValueMatchFailed(FlagValueMatchError::ValueMissing) => {
|
FlagMatchError::ValueMatchFailed(FlagValueMatchError::ValueMissing) => {
|
||||||
format!(
|
format!(
|
||||||
"Flag `-{name}` in command `{prefix}{input}` is missing a value, try passing `{flag}`.",
|
"Flag `-{name}` in command `{prefix}{input}` is missing a value, try passing `{flag}`.",
|
||||||
name = flag.name()
|
name = flag.get_name()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
FlagMatchError::ValueMatchFailed(
|
FlagMatchError::ValueMatchFailed(
|
||||||
|
|
@ -141,7 +141,7 @@ pub fn parse_command(
|
||||||
) => {
|
) => {
|
||||||
format!(
|
format!(
|
||||||
"Flag `-{name}` in command `{prefix}{input}` has a value (`{raw}`) that could not be parsed: {msg}.",
|
"Flag `-{name}` in command `{prefix}{input}` has a value (`{raw}`) that could not be parsed: {msg}.",
|
||||||
name = flag.name()
|
name = flag.get_name()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -210,7 +210,7 @@ fn match_flag<'a>(
|
||||||
for flag in possible_flags {
|
for flag in possible_flags {
|
||||||
println!("matching flag {flag:?}");
|
println!("matching flag {flag:?}");
|
||||||
match flag.try_match(matched_flag.name, matched_flag.value) {
|
match flag.try_match(matched_flag.name, matched_flag.value) {
|
||||||
Some(Ok(param)) => return Some(Ok((flag.name().into(), param))),
|
Some(Ok(param)) => return Some(Ok((flag.get_name().into(), param))),
|
||||||
Some(Err(err)) => return Some(Err((flag, err))),
|
Some(Err(err)) => return Some(Err((flag, err))),
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue