diff --git a/pumpkin/src/commands/cmd_help.rs b/pumpkin/src/commands/cmd_help.rs index 1e1b0e5b7..71bce754b 100644 --- a/pumpkin/src/commands/cmd_help.rs +++ b/pumpkin/src/commands/cmd_help.rs @@ -1,6 +1,6 @@ use crate::commands::dispatcher::InvalidTreeError::InvalidConsumptionError; use crate::commands::dispatcher::{CommandDispatcher, InvalidTreeError}; -use crate::commands::tree::{CommandTree, ConsumedArgs, RawArgs}; +use crate::commands::tree::{Command, CommandTree, ConsumedArgs, RawArgs}; use crate::commands::tree_builder::argument; use crate::commands::{dispatcher_init, CommandSender, DISPATCHER}; use pumpkin_text::TextComponent; @@ -16,26 +16,20 @@ fn consume_arg_command(_src: &CommandSender, args: &mut RawArgs) -> Option( consumed_args: &'a ConsumedArgs, dispatcher: &'a CommandDispatcher, -) -> Result<(&'a str, &'a CommandTree<'a>), InvalidTreeError> { +) -> Result<&'a CommandTree<'a>, InvalidTreeError> { let command_name = consumed_args .get(ARG_COMMAND) .ok_or(InvalidConsumptionError(None))?; - if let Some(tree) = dispatcher.commands.get::<&str>(&command_name.as_str()) { - Ok((command_name, tree)) - } else { - Err(InvalidConsumptionError(Some(command_name.into()))) - } + dispatcher + .get_tree(command_name) + .map_err(|_| InvalidConsumptionError(Some(command_name.into()))) } pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { @@ -44,11 +38,13 @@ pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { argument(ARG_COMMAND, consume_arg_command).execute(&|sender, args| { let dispatcher = DISPATCHER.get_or_init(dispatcher_init); - let (name, tree) = parse_arg_command(args, dispatcher)?; + let tree = parse_arg_command(args, dispatcher)?; sender.send_message(TextComponent::text(&format!( "{} - {} Usage: {}", - name, tree.description, tree + tree.names.join("/"), + tree.description, + tree ))); Ok(()) @@ -57,15 +53,19 @@ pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { .execute(&|sender, _args| { let dispatcher = DISPATCHER.get_or_init(dispatcher_init); - let mut names: Vec<&str> = dispatcher.commands.keys().copied().collect(); - names.sort(); + let mut keys: Vec<&str> = dispatcher.commands.keys().copied().collect(); + keys.sort(); - for name in names { - let tree = &dispatcher.commands[name]; + for key in keys { + let Command::Tree(tree) = &dispatcher.commands[key] else { + continue; + }; sender.send_message(TextComponent::text(&format!( "{} - {} Usage: {}", - name, tree.description, tree + tree.names.join("/"), + tree.description, + tree ))); } diff --git a/pumpkin/src/commands/dispatcher.rs b/pumpkin/src/commands/dispatcher.rs index d4a829818..dac9c8894 100644 --- a/pumpkin/src/commands/dispatcher.rs +++ b/pumpkin/src/commands/dispatcher.rs @@ -1,7 +1,7 @@ use crate::commands::dispatcher::InvalidTreeError::{ InvalidConsumptionError, InvalidRequirementError, }; -use crate::commands::tree::{CommandTree, ConsumedArgs, NodeType, RawArgs}; +use crate::commands::tree::{Command, CommandTree, ConsumedArgs, NodeType, RawArgs}; use crate::commands::CommandSender; use std::collections::HashMap; @@ -17,7 +17,7 @@ pub(crate) enum InvalidTreeError { } pub(crate) struct CommandDispatcher<'a> { - pub(crate) commands: HashMap<&'a str, CommandTree<'a>>, + pub(crate) commands: HashMap<&'a str, Command<'a>>, } /// Stores registered [CommandTree]s and dispatches commands to them. @@ -28,7 +28,7 @@ impl<'a> CommandDispatcher<'a> { let key = parts.next().ok_or("Empty Command")?; let raw_args: Vec<&str> = parts.rev().collect(); - let tree = self.commands.get(key).ok_or("Command not found")?; + let tree = self.get_tree(key)?; // try paths until fitting path is found for path in tree.iter_paths() { @@ -52,6 +52,21 @@ impl<'a> CommandDispatcher<'a> { Err(format!("Invalid Syntax. Usage: {}", tree)) } + pub(crate) fn get_tree(&'a self, key: &str) -> Result<&'a CommandTree<'a>, String> { + let command = self.commands.get(key).ok_or("Command not found")?; + + match command { + Command::Tree(tree) => Ok(tree), + Command::Alias(target) => { + let Some(Command::Tree(tree)) = &self.commands.get(target) else { + println!("Error while parsing command alias \"{key}\": pointing to \"{target}\" which is not a valid tree"); + return Err("Internal Error (See logs for details)".into()); + }; + Ok(tree) + } + } + } + fn try_is_fitting_path( src: &mut CommandSender, path: Vec, @@ -104,9 +119,9 @@ impl<'a> CommandDispatcher<'a> { let primary_name = names.next().expect("at least one name must be provided"); for &name in names { - self.commands.insert(name, tree.clone()); + self.commands.insert(name, Command::Alias(primary_name)); } - self.commands.insert(primary_name, tree); + self.commands.insert(primary_name, Command::Tree(tree)); } } diff --git a/pumpkin/src/commands/tree.rs b/pumpkin/src/commands/tree.rs index 2e2741f38..59d2473c8 100644 --- a/pumpkin/src/commands/tree.rs +++ b/pumpkin/src/commands/tree.rs @@ -12,13 +12,11 @@ pub(crate) type ConsumedArgs<'a> = HashMap<&'a str, String>; /// see [crate::commands::tree_builder::argument] pub(crate) type ArgumentConsumer<'a> = fn(&CommandSender, &mut RawArgs) -> Option; -#[derive(Clone)] pub(crate) struct Node<'a> { pub(crate) children: Vec, pub(crate) node_type: NodeType<'a>, } -#[derive(Clone)] pub(crate) enum NodeType<'a> { ExecuteLeaf { run: &'a (dyn Fn(&mut CommandSender, &ConsumedArgs) -> Result<(), InvalidTreeError> + Sync), @@ -34,7 +32,11 @@ pub(crate) enum NodeType<'a> { }, } -#[derive(Clone)] +pub(crate) enum Command<'a> { + Tree(CommandTree<'a>), + Alias(&'a str), +} + pub(crate) struct CommandTree<'a> { pub(crate) nodes: Vec>, pub(crate) children: Vec,