diff options
| author | Zeyla Hellyer <[email protected]> | 2017-08-19 09:36:15 -0700 |
|---|---|---|
| committer | Zeyla Hellyer <[email protected]> | 2017-08-19 09:39:44 -0700 |
| commit | 948b27ce74e8dce458d427d8159f2a821d4d7cec (patch) | |
| tree | bf82bedd1821ca210e4a9f08644581486738aed6 /src/framework/standard/command.rs | |
| parent | Add html_root_url (diff) | |
| download | serenity-948b27ce74e8dce458d427d8159f2a821d4d7cec.tar.xz serenity-948b27ce74e8dce458d427d8159f2a821d4d7cec.zip | |
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.
Diffstat (limited to 'src/framework/standard/command.rs')
| -rw-r--r-- | src/framework/standard/command.rs | 157 |
1 files changed, 157 insertions, 0 deletions
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<Command>) -> bool + 'static; +pub type Exec = Fn(&mut Context, &Message, Vec<String>, String) -> Result<(), String> + 'static; +pub type Help = Fn(&mut Context, + &Message, + HashMap<String, Arc<CommandGroup>>, + &[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<Command>; +pub type PrefixCheck = Fn(&mut Context, &Message) -> Option<String> + '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<Exec>), + WithCommands(Box<Help>), +} + +#[derive(Default)] +pub struct CommandGroup { + pub prefix: Option<String>, + pub commands: HashMap<String, CommandOrAlias>, +} + +/// 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<Box<Check>>, + /// Function called when the command is called. + pub exec: CommandType, + /// Ratelimit bucket. + pub bucket: Option<String>, + /// Command description, used by other commands. + pub desc: Option<String>, + /// Example arguments, used by other commands. + pub example: Option<String>, + /// Command usage schema, used by other commands. + pub usage: Option<String>, + /// 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<i32>, + /// Maximum amount of arguments that can be passed. + pub max_args: Option<i32>, + /// 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<String>, +} + +impl Command { + pub fn new<F>(f: F) -> Self + where F: Fn(&mut Context, &Message, Vec<String>, 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<Vec<usize>> { + 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<usize> = 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<usize> { + conf.on_mention.as_ref().and_then(|mentions| { + mentions + .iter() + .find(|mention| content.starts_with(&mention[..])) + .map(|m| m.len()) + }) +} |