mirror of
https://github.com/PluralKit/PluralKit.git
synced 2026-02-14 01:30:13 +00:00
feat: implement proper ("static") parameters handling command parser -> bot
feat: handle few more commands bot side fix(commands): handle missing parameters and return error refactor(commands): use ordermap instead of relying on a sort function to sort tokens
This commit is contained in:
parent
1a781014bd
commit
eec9f64026
16 changed files with 358 additions and 502 deletions
|
|
@ -10,7 +10,8 @@ uniffi::include_scaffolding!("commands");
|
|||
use core::panic;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use smol_str::SmolStr;
|
||||
use ordermap::OrderMap;
|
||||
use smol_str::{format_smolstr, SmolStr};
|
||||
use tree::TreeBranch;
|
||||
|
||||
pub use commands::Command;
|
||||
|
|
@ -21,27 +22,70 @@ lazy_static::lazy_static! {
|
|||
let mut tree = TreeBranch {
|
||||
current_command_key: None,
|
||||
possible_tokens: vec![],
|
||||
branches: HashMap::new(),
|
||||
branches: OrderMap::new(),
|
||||
};
|
||||
|
||||
crate::commands::all().iter().for_each(|x| tree.register_command(x.clone()));
|
||||
|
||||
tree.sort_tokens();
|
||||
|
||||
// println!("{{tree:#?}}");
|
||||
crate::commands::all().into_iter().for_each(|x| tree.register_command(x));
|
||||
|
||||
tree
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CommandResult {
|
||||
Ok { command: ParsedCommand },
|
||||
Err { error: String },
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ParameterKind {
|
||||
MemberRef,
|
||||
SystemRef,
|
||||
MemberPrivacyTarget,
|
||||
PrivacyLevel,
|
||||
OpaqueString,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Parameter {
|
||||
raw: String,
|
||||
kind: ParameterKind,
|
||||
}
|
||||
|
||||
impl Parameter {
|
||||
fn new(raw: impl ToString, kind: ParameterKind) -> Self {
|
||||
Self {
|
||||
raw: raw.to_string(),
|
||||
kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! parameter_impl {
|
||||
($($name:ident $kind:ident),*) => {
|
||||
impl Parameter {
|
||||
$(
|
||||
fn $name(raw: impl ToString) -> Self {
|
||||
Self::new(raw, $crate::ParameterKind::$kind)
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
parameter_impl! {
|
||||
opaque OpaqueString,
|
||||
member MemberRef,
|
||||
system SystemRef,
|
||||
member_privacy_target MemberPrivacyTarget,
|
||||
privacy_level PrivacyLevel
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParsedCommand {
|
||||
pub command_ref: String,
|
||||
pub args: Vec<String>,
|
||||
pub params: HashMap<String, Parameter>,
|
||||
pub flags: HashMap<String, Option<String>>,
|
||||
}
|
||||
|
||||
|
|
@ -53,9 +97,11 @@ fn parse_command(input: String) -> CommandResult {
|
|||
let mut current_pos = 0;
|
||||
|
||||
let mut args: Vec<String> = Vec::new();
|
||||
let mut params: HashMap<String, Parameter> = HashMap::new();
|
||||
let mut flags: HashMap<String, Option<String>> = HashMap::new();
|
||||
|
||||
loop {
|
||||
println!("{:?}", local_tree.possible_tokens);
|
||||
let next = next_token(
|
||||
local_tree.possible_tokens.clone(),
|
||||
input.clone(),
|
||||
|
|
@ -70,8 +116,22 @@ fn parse_command(input: String) -> CommandResult {
|
|||
continue;
|
||||
}
|
||||
|
||||
if let Some(arg) = arg {
|
||||
args.push(arg.into());
|
||||
if let Some(arg) = arg.as_ref() {
|
||||
// get param name from token
|
||||
// TODO: idk if this should be on token itself, doesn't feel right, but does work
|
||||
let param = match &found_token {
|
||||
Token::FullString(n) => Some((n, Parameter::opaque(arg))),
|
||||
Token::MemberRef(n) => Some((n, Parameter::member(arg))),
|
||||
Token::MemberPrivacyTarget(n) => Some((n, Parameter::member_privacy_target(arg))),
|
||||
Token::SystemRef(n) => Some((n, Parameter::system(arg))),
|
||||
Token::PrivacyLevel(n) => Some((n, Parameter::privacy_level(arg))),
|
||||
_ => None,
|
||||
};
|
||||
// insert arg as paramater if this is a parameter
|
||||
if let Some((param_name, param)) = param {
|
||||
params.insert(param_name.to_string(), param);
|
||||
}
|
||||
args.push(arg.to_string());
|
||||
}
|
||||
|
||||
if let Some(next_tree) = local_tree.branches.get(&found_token) {
|
||||
|
|
@ -82,9 +142,11 @@ fn parse_command(input: String) -> CommandResult {
|
|||
}
|
||||
Err(None) => {
|
||||
if let Some(command_ref) = local_tree.current_command_key {
|
||||
println!("{command_ref} {params:?}");
|
||||
return CommandResult::Ok {
|
||||
command: ParsedCommand {
|
||||
command_ref: command_ref.into(),
|
||||
params,
|
||||
args,
|
||||
flags,
|
||||
},
|
||||
|
|
@ -136,19 +198,12 @@ fn next_token(
|
|||
|
||||
// iterate over tokens and run try_match
|
||||
for token in possible_tokens {
|
||||
if let TokenMatchResult::Match(value) =
|
||||
// for FullString just send the whole string
|
||||
token.try_match(if matches!(token, Token::FullString) {
|
||||
if input.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(input.clone())
|
||||
}
|
||||
} else {
|
||||
param.clone().map(|v| v.0)
|
||||
})
|
||||
{
|
||||
return Ok((token, value, param.map(|v| v.1).unwrap_or(current_pos)));
|
||||
// for FullString just send the whole string
|
||||
let input_to_match = param.clone().map(|v| v.0);
|
||||
match token.try_match(input_to_match) {
|
||||
TokenMatchResult::Match(value) => return Ok((token, value, param.map(|v| v.1).unwrap_or(current_pos))),
|
||||
TokenMatchResult::MissingParameter { name } => return Err(Some(format_smolstr!("Missing parameter `{name}` in command `{input} [{name}]`."))),
|
||||
TokenMatchResult::NoMatch => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue