format code
This commit is contained in:
parent
413f88d145
commit
92e6d264b4
@ -1,25 +1,25 @@
|
||||
use crate::client::Client;
|
||||
use crate::commands::CommandSender;
|
||||
use crate::commands::CommandSender::Player;
|
||||
use crate::commands::dispatcher::InvalidTreeError;
|
||||
use crate::commands::dispatcher::InvalidTreeError::InvalidConsumptionError;
|
||||
use crate::commands::tree::{ConsumedArgs, RawArgs};
|
||||
use crate::commands::CommandSender;
|
||||
use crate::commands::CommandSender::Player;
|
||||
|
||||
/// todo: implement (so far only own name + @s/@p is implemented)
|
||||
pub fn consume_arg_player(src: &CommandSender, args: &mut RawArgs) -> Option<String> {
|
||||
let s = args.pop()?;
|
||||
|
||||
match s {
|
||||
|
||||
match s {
|
||||
"@s" if src.is_player() => Some(s.into()),
|
||||
"@p" if src.is_player() => Some(s.into()),
|
||||
"@r" => None, // todo: implement random player target selector
|
||||
"@r" => None, // todo: implement random player target selector
|
||||
"@a" | "@e" => None, // todo: implement all players target selector
|
||||
_ => {
|
||||
// todo: implement any other player than sender
|
||||
if let Player(client) = src {
|
||||
if let Some(profile) = &client.gameprofile {
|
||||
if profile.name == s {
|
||||
return Some(s.into())
|
||||
return Some(s.into());
|
||||
};
|
||||
};
|
||||
};
|
||||
@ -29,8 +29,13 @@ pub fn consume_arg_player(src: &CommandSender, args: &mut RawArgs) -> Option<Str
|
||||
}
|
||||
|
||||
/// todo: implement (so far only own name + @s/@p is implemented)
|
||||
pub fn parse_arg_player<'a>(src: &'a mut CommandSender, arg_name: &str, consumed_args: &ConsumedArgs) -> Result<&'a mut Client, InvalidTreeError> {
|
||||
let s = consumed_args.get(arg_name)
|
||||
pub fn parse_arg_player<'a>(
|
||||
src: &'a mut CommandSender,
|
||||
arg_name: &str,
|
||||
consumed_args: &ConsumedArgs,
|
||||
) -> Result<&'a mut Client, InvalidTreeError> {
|
||||
let s = consumed_args
|
||||
.get(arg_name)
|
||||
.ok_or(InvalidConsumptionError(None))?
|
||||
.as_str();
|
||||
|
||||
@ -44,11 +49,11 @@ pub fn parse_arg_player<'a>(src: &'a mut CommandSender, arg_name: &str, consumed
|
||||
if let Player(client) = src {
|
||||
if let Some(profile) = &client.gameprofile {
|
||||
if profile.name == s {
|
||||
return Ok(client)
|
||||
return Ok(client);
|
||||
};
|
||||
};
|
||||
};
|
||||
Err(InvalidConsumptionError(Some(s.into())))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,12 +5,14 @@ use pumpkin_text::TextComponent;
|
||||
|
||||
use crate::commands::arg_player::{consume_arg_player, parse_arg_player};
|
||||
|
||||
use crate::commands::CommandSender;
|
||||
use crate::commands::CommandSender::Player;
|
||||
use crate::commands::dispatcher::InvalidTreeError;
|
||||
use crate::commands::dispatcher::InvalidTreeError::{InvalidConsumptionError, InvalidRequirementError};
|
||||
use crate::commands::dispatcher::InvalidTreeError::{
|
||||
InvalidConsumptionError, InvalidRequirementError,
|
||||
};
|
||||
use crate::commands::tree::{CommandTree, ConsumedArgs, RawArgs};
|
||||
use crate::commands::tree_builder::{argument, require};
|
||||
use crate::commands::CommandSender;
|
||||
use crate::commands::CommandSender::Player;
|
||||
use crate::entity::player::GameMode;
|
||||
|
||||
pub(crate) const NAME: &str = "gamemode";
|
||||
@ -25,76 +27,70 @@ pub fn consume_arg_gamemode(_src: &CommandSender, args: &mut RawArgs) -> Option<
|
||||
|
||||
if let Ok(id) = s.parse::<u8>() {
|
||||
match GameMode::from_u8(id) {
|
||||
None | Some(GameMode::Undefined) => {},
|
||||
Some(_) => return Some(s.into())
|
||||
None | Some(GameMode::Undefined) => {}
|
||||
Some(_) => return Some(s.into()),
|
||||
};
|
||||
};
|
||||
|
||||
match GameMode::from_str(s) {
|
||||
Err(_) | Ok(GameMode::Undefined) => None,
|
||||
Ok(_) => Some(s.into())
|
||||
Ok(_) => Some(s.into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_arg_gamemode(consumed_args: &ConsumedArgs) -> Result<GameMode, InvalidTreeError> {
|
||||
let s = consumed_args.get(ARG_GAMEMODE)
|
||||
let s = consumed_args
|
||||
.get(ARG_GAMEMODE)
|
||||
.ok_or(InvalidConsumptionError(None))?;
|
||||
|
||||
if let Ok(id) = s.parse::<u8>() {
|
||||
match GameMode::from_u8(id) {
|
||||
None | Some(GameMode::Undefined) => {},
|
||||
Some(gamemode) => return Ok(gamemode)
|
||||
None | Some(GameMode::Undefined) => {}
|
||||
Some(gamemode) => return Ok(gamemode),
|
||||
};
|
||||
};
|
||||
|
||||
match GameMode::from_str(s) {
|
||||
Err(_) | Ok(GameMode::Undefined) => Err(InvalidConsumptionError(Some(s.into()))),
|
||||
Ok(gamemode) => Ok(gamemode)
|
||||
Ok(gamemode) => Ok(gamemode),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> {
|
||||
CommandTree::new(DESCRIPTION).with_child(
|
||||
|
||||
require(&|sender| {
|
||||
sender.permission_lvl() >= 2
|
||||
}).with_child(
|
||||
|
||||
argument(ARG_GAMEMODE, consume_arg_gamemode).with_child(
|
||||
|
||||
require(&|sender| sender.is_player())
|
||||
|
||||
.execute(&|sender, args| {
|
||||
require(&|sender| sender.permission_lvl() >= 2).with_child(
|
||||
argument(ARG_GAMEMODE, consume_arg_gamemode)
|
||||
.with_child(
|
||||
require(&|sender| sender.is_player()).execute(&|sender, args| {
|
||||
let gamemode = parse_arg_gamemode(args)?;
|
||||
|
||||
return if let Player(target) = sender {
|
||||
target.set_gamemode(gamemode);
|
||||
target.send_system_message(TextComponent::text(
|
||||
&format!("Game mode was set to {:?}", gamemode)
|
||||
));
|
||||
target.send_system_message(TextComponent::text(&format!(
|
||||
"Game mode was set to {:?}",
|
||||
gamemode
|
||||
)));
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(InvalidRequirementError)
|
||||
}
|
||||
})
|
||||
|
||||
).with_child(
|
||||
|
||||
argument(ARG_TARGET, consume_arg_player)
|
||||
|
||||
.execute(&|sender, args| {
|
||||
};
|
||||
}),
|
||||
)
|
||||
.with_child(
|
||||
argument(ARG_TARGET, consume_arg_player).execute(&|sender, args| {
|
||||
let gamemode = parse_arg_gamemode(args)?;
|
||||
let target = parse_arg_player(sender, ARG_TARGET, args)?;
|
||||
|
||||
target.set_gamemode(gamemode);
|
||||
target.send_system_message(TextComponent::text(
|
||||
&format!("Set own game mode to {:?}", gamemode)
|
||||
));
|
||||
target.send_system_message(TextComponent::text(&format!(
|
||||
"Set own game mode to {:?}",
|
||||
gamemode
|
||||
)));
|
||||
|
||||
Ok(())
|
||||
})
|
||||
)
|
||||
)
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
use pumpkin_text::TextComponent;
|
||||
use crate::commands::{CommandSender, DISPATCHER, dispatcher_init};
|
||||
use crate::commands::dispatcher::{CommandDispatcher, InvalidTreeError};
|
||||
use crate::commands::dispatcher::InvalidTreeError::InvalidConsumptionError;
|
||||
use crate::commands::dispatcher::{CommandDispatcher, InvalidTreeError};
|
||||
use crate::commands::tree::{CommandTree, ConsumedArgs, RawArgs};
|
||||
use crate::commands::tree_builder::argument;
|
||||
use crate::commands::{dispatcher_init, CommandSender, DISPATCHER};
|
||||
use pumpkin_text::TextComponent;
|
||||
|
||||
pub(crate) const NAME: &str = "help";
|
||||
pub(crate) const ALIAS: &str = "?";
|
||||
@ -17,12 +17,19 @@ fn consume_arg_command(_src: &CommandSender, args: &mut RawArgs) -> Option<Strin
|
||||
|
||||
let dispatcher = DISPATCHER.get_or_init(dispatcher_init);
|
||||
|
||||
if dispatcher.commands.contains_key(s) { Some(s.into()) }
|
||||
else { None }
|
||||
if dispatcher.commands.contains_key(s) {
|
||||
Some(s.into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_arg_command<'a>(consumed_args: &'a ConsumedArgs, dispatcher: &'a CommandDispatcher) -> Result<(&'a str, &'a CommandTree<'a>), InvalidTreeError> {
|
||||
let command_name = consumed_args.get(ARG_COMMAND)
|
||||
fn parse_arg_command<'a>(
|
||||
consumed_args: &'a ConsumedArgs,
|
||||
dispatcher: &'a CommandDispatcher,
|
||||
) -> Result<(&'a str, &'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()) {
|
||||
@ -33,31 +40,35 @@ fn parse_arg_command<'a>(consumed_args: &'a ConsumedArgs, dispatcher: &'a Comman
|
||||
}
|
||||
|
||||
pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> {
|
||||
CommandTree::new(DESCRIPTION).with_child(
|
||||
argument(ARG_COMMAND, consume_arg_command).execute(&|sender, args| {
|
||||
CommandTree::new(DESCRIPTION)
|
||||
.with_child(
|
||||
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)?;
|
||||
|
||||
sender.send_message(TextComponent::text(&format!(
|
||||
"{} - {} Usage:{}",
|
||||
name,
|
||||
tree.description,
|
||||
tree.paths_formatted(name)
|
||||
)));
|
||||
|
||||
Ok(())
|
||||
}),
|
||||
)
|
||||
.execute(&|sender, _args| {
|
||||
let dispatcher = DISPATCHER.get_or_init(dispatcher_init);
|
||||
|
||||
let (name, tree) = parse_arg_command(args, dispatcher)?;
|
||||
|
||||
sender.send_message(
|
||||
TextComponent::text(
|
||||
&format!("{} - {} Usage:{}", name, tree.description, tree.paths_formatted(name))
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
for (name, tree) in &dispatcher.commands {
|
||||
sender.send_message(TextComponent::text(&format!(
|
||||
"{} - {} Usage:{}",
|
||||
name,
|
||||
tree.description,
|
||||
tree.paths_formatted(name)
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
).execute(&|sender, _args| {
|
||||
let dispatcher = DISPATCHER.get_or_init(dispatcher_init);
|
||||
|
||||
for (name, tree) in &dispatcher.commands {
|
||||
sender.send_message(
|
||||
TextComponent::text(
|
||||
&format!("{} - {} Usage:{}", name, tree.description, tree.paths_formatted(name))
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use pumpkin_text::{color::NamedColor, TextComponent};
|
||||
use pumpkin_protocol::CURRENT_MC_PROTOCOL;
|
||||
use crate::server::CURRENT_MC_VERSION;
|
||||
use pumpkin_protocol::CURRENT_MC_PROTOCOL;
|
||||
use pumpkin_text::{color::NamedColor, TextComponent};
|
||||
|
||||
use crate::commands::tree::CommandTree;
|
||||
|
||||
@ -12,7 +12,7 @@ pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> {
|
||||
CommandTree::new(DESCRIPTION).execute(&|sender, _| {
|
||||
let version = env!("CARGO_PKG_VERSION");
|
||||
let description = env!("CARGO_PKG_DESCRIPTION");
|
||||
|
||||
|
||||
sender.send_message(TextComponent::text(
|
||||
&format!("Pumpkin {version}, {description} (Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL})")
|
||||
).color_named(NamedColor::Green));
|
||||
|
||||
@ -7,9 +7,7 @@ const DESCRIPTION: &str = "Stop the server.";
|
||||
|
||||
pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> {
|
||||
CommandTree::new(DESCRIPTION).with_child(
|
||||
require(&|sender| { sender.permission_lvl() >= 4 })
|
||||
.execute(&|_sender, _args| {
|
||||
std::process::exit(0)
|
||||
})
|
||||
require(&|sender| sender.permission_lvl() >= 4)
|
||||
.execute(&|_sender, _args| std::process::exit(0)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
use std::collections::HashMap;
|
||||
use crate::commands::dispatcher::InvalidTreeError::{
|
||||
InvalidConsumptionError, InvalidRequirementError,
|
||||
};
|
||||
use crate::commands::tree::{CommandTree, ConsumedArgs, NodeType, RawArgs};
|
||||
use crate::commands::CommandSender;
|
||||
use crate::commands::dispatcher::InvalidTreeError::{InvalidConsumptionError, InvalidRequirementError};
|
||||
use crate::commands::tree::{ConsumedArgs, NodeType, RawArgs, CommandTree};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum InvalidTreeError {
|
||||
/// This error means that there was an error while parsing a previously consumed argument.
|
||||
/// That only happens when consumption is wrongly implemented, as it should ensure parsing may
|
||||
/// That only happens when consumption is wrongly implemented, as it should ensure parsing may
|
||||
/// never fail.
|
||||
InvalidConsumptionError(Option<String>),
|
||||
|
||||
@ -15,15 +17,13 @@ pub(crate) enum InvalidTreeError {
|
||||
}
|
||||
|
||||
pub(crate) struct CommandDispatcher<'a> {
|
||||
pub(crate) commands: HashMap<&'a str, CommandTree<'a>>
|
||||
pub(crate) commands: HashMap<&'a str, CommandTree<'a>>,
|
||||
}
|
||||
|
||||
/// Stores registered [CommandTree]s and dispatches commands to them.
|
||||
impl <'a> CommandDispatcher<'a> {
|
||||
|
||||
impl<'a> CommandDispatcher<'a> {
|
||||
/// Execute a command using its corresponding [CommandTree].
|
||||
pub(crate) fn dispatch(&'a self, src: &mut CommandSender, cmd: &str) -> Result<(), String> {
|
||||
|
||||
let mut parts = cmd.split_ascii_whitespace();
|
||||
let key = parts.next().ok_or("Empty Command")?;
|
||||
let raw_args: Vec<&str> = parts.rev().collect();
|
||||
@ -35,23 +35,32 @@ impl <'a> CommandDispatcher<'a> {
|
||||
match Self::try_is_fitting_path(src, path, tree, raw_args.clone()) {
|
||||
Err(InvalidConsumptionError(s)) => {
|
||||
println!("Error while parsing command \"{cmd}\": {s:?} was consumed, but couldn't be parsed");
|
||||
return Err("Internal Error (See logs for details)".into())
|
||||
},
|
||||
return Err("Internal Error (See logs for details)".into());
|
||||
}
|
||||
Err(InvalidRequirementError) => {
|
||||
println!("Error while parsing command \"{cmd}\": a requirement that was expected was not met.");
|
||||
return Err("Internal Error (See logs for details)".into())
|
||||
},
|
||||
return Err("Internal Error (See logs for details)".into());
|
||||
}
|
||||
Ok(is_fitting_path) => {
|
||||
if is_fitting_path { return Ok(()) }
|
||||
if is_fitting_path {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(format!("Invalid Syntax. Usage:{}", tree.paths_formatted(key)))
|
||||
Err(format!(
|
||||
"Invalid Syntax. Usage:{}",
|
||||
tree.paths_formatted(key)
|
||||
))
|
||||
}
|
||||
|
||||
fn try_is_fitting_path(src: &mut CommandSender, path: Vec<usize>, tree: &CommandTree, mut raw_args: RawArgs) -> Result<bool, InvalidTreeError> {
|
||||
|
||||
fn try_is_fitting_path(
|
||||
src: &mut CommandSender,
|
||||
path: Vec<usize>,
|
||||
tree: &CommandTree,
|
||||
mut raw_args: RawArgs,
|
||||
) -> Result<bool, InvalidTreeError> {
|
||||
let mut parsed_args: ConsumedArgs = HashMap::new();
|
||||
|
||||
for node in path.iter().map(|&i| &tree.nodes[i]) {
|
||||
@ -69,7 +78,11 @@ impl <'a> CommandDispatcher<'a> {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
NodeType::Argument { consumer: consume, name, .. } => {
|
||||
NodeType::Argument {
|
||||
consumer: consume,
|
||||
name,
|
||||
..
|
||||
} => {
|
||||
if let Some(consumed) = consume(src, &mut raw_args) {
|
||||
parsed_args.insert(name, consumed);
|
||||
} else {
|
||||
@ -82,8 +95,8 @@ impl <'a> CommandDispatcher<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
use pumpkin_text::TextComponent;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::OnceLock;
|
||||
use pumpkin_text::TextComponent;
|
||||
|
||||
use crate::client::Client;
|
||||
use crate::commands::dispatcher::CommandDispatcher;
|
||||
mod arg_player;
|
||||
mod cmd_gamemode;
|
||||
mod cmd_help;
|
||||
mod cmd_pumpkin;
|
||||
mod cmd_stop;
|
||||
mod dispatcher;
|
||||
mod tree;
|
||||
mod tree_builder;
|
||||
mod dispatcher;
|
||||
mod arg_player;
|
||||
mod cmd_help;
|
||||
|
||||
pub enum CommandSender<'a> {
|
||||
Rcon(&'a mut Vec<String>),
|
||||
@ -78,9 +78,7 @@ fn dispatcher_init<'a>() -> CommandDispatcher<'a> {
|
||||
map.insert(cmd_help::NAME, cmd_help::init_command_tree());
|
||||
map.insert(cmd_help::ALIAS, cmd_help::init_command_tree());
|
||||
|
||||
CommandDispatcher {
|
||||
commands: map,
|
||||
}
|
||||
CommandDispatcher { commands: map }
|
||||
}
|
||||
|
||||
pub fn handle_command(sender: &mut CommandSender, cmd: &str) {
|
||||
@ -88,8 +86,7 @@ pub fn handle_command(sender: &mut CommandSender, cmd: &str) {
|
||||
|
||||
if let Err(err) = dispatcher.dispatch(sender, cmd) {
|
||||
sender.send_message(
|
||||
TextComponent::text(&err)
|
||||
.color_named(pumpkin_text::color::NamedColor::Red),
|
||||
TextComponent::text(&err).color_named(pumpkin_text::color::NamedColor::Red),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
use crate::commands::CommandSender;
|
||||
use crate::commands::dispatcher::InvalidTreeError;
|
||||
use crate::commands::CommandSender;
|
||||
/// see [crate::commands::tree_builder::argument]
|
||||
pub(crate) type RawArgs<'a> = Vec<&'a str>;
|
||||
|
||||
@ -21,16 +21,14 @@ pub(crate) enum NodeType<'a> {
|
||||
run: &'a (dyn Fn(&mut CommandSender, &ConsumedArgs) -> Result<(), InvalidTreeError> + Sync),
|
||||
},
|
||||
#[allow(dead_code)] // todo: remove (so far no commands requiring this are implemented)
|
||||
Literal {
|
||||
string: &'a str,
|
||||
},
|
||||
Literal { string: &'a str },
|
||||
Argument {
|
||||
name: &'a str,
|
||||
consumer: ArgumentConsumer<'a>,
|
||||
},
|
||||
Require {
|
||||
predicate: &'a (dyn Fn(&CommandSender) -> bool + Sync),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
pub(crate) struct CommandTree<'a> {
|
||||
@ -39,7 +37,7 @@ pub(crate) struct CommandTree<'a> {
|
||||
pub(crate) description: &'a str,
|
||||
}
|
||||
|
||||
impl <'a> CommandTree<'a> {
|
||||
impl<'a> CommandTree<'a> {
|
||||
/// iterate over all possible paths that end in a [NodeType::ExecuteLeaf]
|
||||
pub(crate) fn iter_paths(&'a self) -> impl Iterator<Item = Vec<usize>> + 'a {
|
||||
let mut todo = VecDeque::<(usize, usize)>::new();
|
||||
@ -54,25 +52,29 @@ impl <'a> CommandTree<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// format possible paths as [String], using ```name``` as the command name
|
||||
pub(crate) fn paths_formatted(&'a self, name: &str) -> String {
|
||||
let paths: Vec<Vec<&NodeType>> = self.iter_paths()
|
||||
let paths: Vec<Vec<&NodeType>> = self
|
||||
.iter_paths()
|
||||
.map(|path| path.iter().map(|&i| &self.nodes[i].node_type).collect())
|
||||
.collect();
|
||||
|
||||
let len = paths.iter()
|
||||
.map(|path| path.iter()
|
||||
.map(|node| match node {
|
||||
NodeType::ExecuteLeaf { .. } => 0,
|
||||
NodeType::Literal { string } => string.len() + 1,
|
||||
NodeType::Argument { name, .. } => name.len() + 3,
|
||||
NodeType::Require { .. } => 0,
|
||||
})
|
||||
.sum::<usize>() + name.len() + 2
|
||||
)
|
||||
|
||||
let len = paths
|
||||
.iter()
|
||||
.map(|path| {
|
||||
path.iter()
|
||||
.map(|node| match node {
|
||||
NodeType::ExecuteLeaf { .. } => 0,
|
||||
NodeType::Literal { string } => string.len() + 1,
|
||||
NodeType::Argument { name, .. } => name.len() + 3,
|
||||
NodeType::Require { .. } => 0,
|
||||
})
|
||||
.sum::<usize>()
|
||||
+ name.len()
|
||||
+ 2
|
||||
})
|
||||
.sum::<usize>();
|
||||
|
||||
|
||||
let mut s = String::with_capacity(len);
|
||||
|
||||
for path in paths.iter() {
|
||||
@ -95,7 +97,7 @@ impl <'a> CommandTree<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
s
|
||||
}
|
||||
}
|
||||
@ -107,8 +109,7 @@ struct TraverseAllPathsIter<'a> {
|
||||
todo: VecDeque<(usize, usize)>,
|
||||
}
|
||||
|
||||
impl <'a>Iterator for TraverseAllPathsIter<'a> {
|
||||
|
||||
impl<'a> Iterator for TraverseAllPathsIter<'a> {
|
||||
type Item = Vec<usize>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
@ -118,12 +119,15 @@ impl <'a>Iterator for TraverseAllPathsIter<'a> {
|
||||
|
||||
// add new children to front
|
||||
self.todo.reserve(node.children.len());
|
||||
node.children.iter().rev().for_each(|&c| self.todo.push_front((depth + 1, c)));
|
||||
node.children
|
||||
.iter()
|
||||
.rev()
|
||||
.for_each(|&c| self.todo.push_front((depth + 1, c)));
|
||||
|
||||
// update path
|
||||
while self.path.len() > depth {
|
||||
self.path.pop();
|
||||
};
|
||||
}
|
||||
self.path.push(i);
|
||||
|
||||
if let NodeType::ExecuteLeaf { .. } = node.node_type {
|
||||
@ -132,4 +136,3 @@ impl <'a>Iterator for TraverseAllPathsIter<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
use crate::commands::CommandSender;
|
||||
use crate::commands::dispatcher::InvalidTreeError;
|
||||
use crate::commands::tree::{ArgumentConsumer, ConsumedArgs, Node, NodeType, CommandTree};
|
||||
|
||||
impl <'a> CommandTree<'a> {
|
||||
use crate::commands::tree::{ArgumentConsumer, CommandTree, ConsumedArgs, Node, NodeType};
|
||||
use crate::commands::CommandSender;
|
||||
|
||||
impl<'a> CommandTree<'a> {
|
||||
/// Add a child [Node] to the root of this [CommandTree].
|
||||
pub fn with_child(mut self, child: impl NodeBuilder<'a>) -> Self {
|
||||
let node = child.build(&mut self);
|
||||
@ -11,7 +10,7 @@ impl <'a> CommandTree<'a> {
|
||||
self.nodes.push(node);
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
pub fn new(description: &'a str) -> Self {
|
||||
Self {
|
||||
nodes: Vec::new(),
|
||||
@ -27,11 +26,12 @@ impl <'a> CommandTree<'a> {
|
||||
/// desired type.
|
||||
///
|
||||
/// Also see [NonLeafNodeBuilder::execute].
|
||||
pub fn execute(mut self, run: &'a (dyn Fn(&mut CommandSender, &ConsumedArgs) -> Result<(), InvalidTreeError> + Sync)) -> Self {
|
||||
pub fn execute(
|
||||
mut self,
|
||||
run: &'a (dyn Fn(&mut CommandSender, &ConsumedArgs) -> Result<(), InvalidTreeError> + Sync),
|
||||
) -> Self {
|
||||
let node = Node {
|
||||
node_type: NodeType::ExecuteLeaf {
|
||||
run,
|
||||
},
|
||||
node_type: NodeType::ExecuteLeaf { run },
|
||||
children: Vec::new(),
|
||||
};
|
||||
|
||||
@ -50,7 +50,7 @@ struct LeafNodeBuilder<'a> {
|
||||
node_type: NodeType<'a>,
|
||||
}
|
||||
|
||||
impl <'a>NodeBuilder<'a> for LeafNodeBuilder<'a> {
|
||||
impl<'a> NodeBuilder<'a> for LeafNodeBuilder<'a> {
|
||||
fn build(self, _tree: &mut CommandTree<'a>) -> Node<'a> {
|
||||
Node {
|
||||
children: Vec::new(),
|
||||
@ -62,10 +62,10 @@ impl <'a>NodeBuilder<'a> for LeafNodeBuilder<'a> {
|
||||
pub struct NonLeafNodeBuilder<'a> {
|
||||
node_type: NodeType<'a>,
|
||||
child_nodes: Vec<NonLeafNodeBuilder<'a>>,
|
||||
leaf_nodes: Vec<LeafNodeBuilder<'a>>
|
||||
leaf_nodes: Vec<LeafNodeBuilder<'a>>,
|
||||
}
|
||||
|
||||
impl <'a>NodeBuilder<'a> for NonLeafNodeBuilder<'a> {
|
||||
impl<'a> NodeBuilder<'a> for NonLeafNodeBuilder<'a> {
|
||||
fn build(self, tree: &mut CommandTree<'a>) -> Node<'a> {
|
||||
let mut child_indices = Vec::new();
|
||||
|
||||
@ -88,8 +88,7 @@ impl <'a>NodeBuilder<'a> for NonLeafNodeBuilder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a>NonLeafNodeBuilder<'a> {
|
||||
|
||||
impl<'a> NonLeafNodeBuilder<'a> {
|
||||
/// Add a child [Node] to this one.
|
||||
pub fn with_child(mut self, child: NonLeafNodeBuilder<'a>) -> Self {
|
||||
self.child_nodes.push(child);
|
||||
@ -103,13 +102,14 @@ impl <'a>NonLeafNodeBuilder<'a> {
|
||||
/// desired type.
|
||||
///
|
||||
/// Also see [CommandTree::execute].
|
||||
pub fn execute(mut self, run: &'a (dyn Fn(&mut CommandSender, &ConsumedArgs) -> Result<(), InvalidTreeError> + Sync)) -> Self {
|
||||
pub fn execute(
|
||||
mut self,
|
||||
run: &'a (dyn Fn(&mut CommandSender, &ConsumedArgs) -> Result<(), InvalidTreeError> + Sync),
|
||||
) -> Self {
|
||||
self.leaf_nodes.push(LeafNodeBuilder {
|
||||
node_type: NodeType::ExecuteLeaf {
|
||||
run
|
||||
},
|
||||
node_type: NodeType::ExecuteLeaf { run },
|
||||
});
|
||||
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
@ -118,9 +118,7 @@ impl <'a>NonLeafNodeBuilder<'a> {
|
||||
#[allow(dead_code)] // todo: remove (so far no commands requiring this are implemented)
|
||||
pub fn literal(string: &str) -> NonLeafNodeBuilder {
|
||||
NonLeafNodeBuilder {
|
||||
node_type: NodeType::Literal {
|
||||
string
|
||||
},
|
||||
node_type: NodeType::Literal { string },
|
||||
child_nodes: Vec::new(),
|
||||
leaf_nodes: Vec::new(),
|
||||
}
|
||||
@ -136,10 +134,7 @@ pub fn literal(string: &str) -> NonLeafNodeBuilder {
|
||||
/// reversed, so [Vec::pop] can be used to obtain args in ltr order.
|
||||
pub fn argument<'a>(name: &'a str, consumer: ArgumentConsumer) -> NonLeafNodeBuilder<'a> {
|
||||
NonLeafNodeBuilder {
|
||||
node_type: NodeType::Argument {
|
||||
name,
|
||||
consumer,
|
||||
},
|
||||
node_type: NodeType::Argument { name, consumer },
|
||||
child_nodes: Vec::new(),
|
||||
leaf_nodes: Vec::new(),
|
||||
}
|
||||
@ -149,9 +144,7 @@ pub fn argument<'a>(name: &'a str, consumer: ArgumentConsumer) -> NonLeafNodeBui
|
||||
/// met.
|
||||
pub fn require(predicate: &(dyn Fn(&CommandSender) -> bool + Sync)) -> NonLeafNodeBuilder {
|
||||
NonLeafNodeBuilder {
|
||||
node_type: NodeType::Require {
|
||||
predicate
|
||||
},
|
||||
node_type: NodeType::Require { predicate },
|
||||
child_nodes: Vec::new(),
|
||||
leaf_nodes: Vec::new(),
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user