From 948b27ce74e8dce458d427d8159f2a821d4d7cec Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Sat, 19 Aug 2017 09:36:15 -0700 Subject: Move builtin framework impl to its own module The framework is now moved in its entirity to the `framework` module, with the `Framework` trait currently on its own and the builtin implementation provided. The builtin implementation has been renamed to "Standard". Upgrade path: Rename the `BuiltinFramework` import to `StandardFramework`. Instead of importing builtin framework items from `serenity::framework`, import them from `serenity::framework::standard`. This is the beginning to #60. The root `framework` module (non-standard implementation) will be built more by the time it's closed. --- src/framework/standard/command.rs | 157 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 src/framework/standard/command.rs (limited to 'src/framework/standard/command.rs') diff --git a/src/framework/standard/command.rs b/src/framework/standard/command.rs new file mode 100644 index 0000000..01c4c5e --- /dev/null +++ b/src/framework/standard/command.rs @@ -0,0 +1,157 @@ +use std::sync::Arc; +use super::Configuration; +use client::Context; +use model::{Message, Permissions}; +use std::collections::HashMap; + +pub type Check = Fn(&mut Context, &Message, &[String], &Arc) -> bool + 'static; +pub type Exec = Fn(&mut Context, &Message, Vec, String) -> Result<(), String> + 'static; +pub type Help = Fn(&mut Context, + &Message, + HashMap>, + &[String]) + -> Result<(), String> + + 'static; +pub type BeforeHook = Fn(&mut Context, &Message, &str) -> bool + 'static; +pub type AfterHook = Fn(&mut Context, &Message, &str, Result<(), String>) + 'static; +pub(crate) type InternalCommand = Arc; +pub type PrefixCheck = Fn(&mut Context, &Message) -> Option + 'static; + +pub enum CommandOrAlias { + Alias(String), + Command(InternalCommand), +} + +/// Command function type. Allows to access internal framework things inside +/// your commands. +pub enum CommandType { + StringResponse(String), + Basic(Box), + WithCommands(Box), +} + +#[derive(Default)] +pub struct CommandGroup { + pub prefix: Option, + pub commands: HashMap, +} + +/// Command struct used to store commands internally. +pub struct Command { + /// A set of checks to be called prior to executing the command. The checks + /// will short-circuit on the first check that returns `false`. + pub checks: Vec>, + /// Function called when the command is called. + pub exec: CommandType, + /// Ratelimit bucket. + pub bucket: Option, + /// Command description, used by other commands. + pub desc: Option, + /// Example arguments, used by other commands. + pub example: Option, + /// Command usage schema, used by other commands. + pub usage: Option, + /// Whether arguments should be parsed using quote parser or not. + pub use_quotes: bool, + /// Minumum amount of arguments that should be passed. + pub min_args: Option, + /// Maximum amount of arguments that can be passed. + pub max_args: Option, + /// Permissions required to use this command. + pub required_permissions: Permissions, + /// Whether command should be displayed in help list or not, used by other commands. + pub help_available: bool, + /// Whether command can be used only privately or not. + pub dm_only: bool, + /// Whether command can be used only in guilds or not. + pub guild_only: bool, + /// Whether command can only be used by owners or not. + pub owners_only: bool, + pub(crate) aliases: Vec, +} + +impl Command { + pub fn new(f: F) -> Self + where F: Fn(&mut Context, &Message, Vec, String) -> Result<(), String> + 'static { + Command { + aliases: Vec::new(), + checks: Vec::default(), + exec: CommandType::Basic(Box::new(f)), + desc: None, + usage: None, + example: None, + use_quotes: false, + dm_only: false, + bucket: None, + guild_only: false, + help_available: true, + min_args: None, + max_args: None, + owners_only: false, + required_permissions: Permissions::empty(), + } + } +} + +pub fn positions(ctx: &mut Context, msg: &Message, conf: &Configuration) -> Option> { + if !conf.prefixes.is_empty() || conf.dynamic_prefix.is_some() { + // Find out if they were mentioned. If not, determine if the prefix + // was used. If not, return None. + let mut positions: Vec = vec![]; + + if let Some(mention_end) = find_mention_end(&msg.content, conf) { + positions.push(mention_end); + } else if let Some(ref func) = conf.dynamic_prefix { + if let Some(x) = func(ctx, msg) { + if msg.content.starts_with(&x) { + positions.push(x.len()); + } + } else { + for n in &conf.prefixes { + if msg.content.starts_with(n) { + positions.push(n.len()); + } + } + } + } else { + for n in &conf.prefixes { + if msg.content.starts_with(n) { + positions.push(n.len()); + } + } + }; + + if positions.is_empty() { + return None; + } + + if conf.allow_whitespace { + let pos = *unsafe { positions.get_unchecked(0) }; + + positions.insert(0, pos + 1); + } + + Some(positions) + } else if conf.on_mention.is_some() { + find_mention_end(&msg.content, conf).map(|mention_end| { + let mut positions = vec![mention_end]; + + if conf.allow_whitespace { + positions.insert(0, mention_end + 1); + } + + positions + }) + } else { + None + } +} + +fn find_mention_end(content: &str, conf: &Configuration) -> Option { + conf.on_mention.as_ref().and_then(|mentions| { + mentions + .iter() + .find(|mention| content.starts_with(&mention[..])) + .map(|m| m.len()) + }) +} -- cgit v1.2.3