aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAustin Hellyer <[email protected]>2016-11-08 14:56:37 -0800
committerAustin Hellyer <[email protected]>2016-11-08 14:56:37 -0800
commit489dab2f34588153079ab1373f988835170c9b9a (patch)
tree3f64350c97f294ffa31c8e245ac6507871585d15
parentAdd Manage Webhooks to permissions 2FA list (diff)
downloadserenity-489dab2f34588153079ab1373f988835170c9b9a.tar.xz
serenity-489dab2f34588153079ab1373f988835170c9b9a.zip
Framework: fix command arg positioning
The command system assumed that prefixes were only one character long, so count the total length of the prefix. In addition, the `allow_whitespace` configuration added some difficulty in deciding where to count as the initial position to start splitting for arguments. Instead of fixing that, rewrite the framework to make these types of changes easier in the future.
-rw-r--r--examples/06_command_framework.rs2
-rw-r--r--src/ext/framework/command.rs55
-rw-r--r--src/ext/framework/mod.rs62
3 files changed, 72 insertions, 47 deletions
diff --git a/examples/06_command_framework.rs b/examples/06_command_framework.rs
index cb838fd..b93b952 100644
--- a/examples/06_command_framework.rs
+++ b/examples/06_command_framework.rs
@@ -21,9 +21,9 @@ fn main() {
// Commands are equivilant to:
// "~about"
- // "~ping"
// "~emoji cat"
// "~emoji dog"
+ // "~ping"
// "~some complex command"
client.with_framework(|f| f
.configure(|c| c
diff --git a/src/ext/framework/command.rs b/src/ext/framework/command.rs
index 43d3c9a..6a9a713 100644
--- a/src/ext/framework/command.rs
+++ b/src/ext/framework/command.rs
@@ -1,7 +1,62 @@
use std::sync::Arc;
+use super::{CommandType, Configuration};
use ::client::Context;
use ::model::Message;
pub type Command = Fn(Context, Message, Vec<String>) + Send + Sync;
#[doc(hidden)]
pub type InternalCommand = Arc<Command>;
+
+pub fn positions(content: &str, conf: &Configuration)
+ -> Option<(Vec<usize>, CommandType)> {
+ if let Some(ref prefix) = conf.prefix {
+ // Find out if they were mentioned. If not, determine if the prefix
+ // was used. If not, return None.
+ let (mut positions, kind) = if let Some(mention_end) = find_mention_end(content, conf) {
+ (vec![mention_end], CommandType::Mention)
+ } else if content.starts_with(prefix) {
+ (vec![prefix.len()], CommandType::Prefix)
+ } else {
+ return None;
+ };
+
+ if conf.allow_whitespace {
+ let pos = *unsafe {
+ positions.get_unchecked(0)
+ };
+
+ positions.insert(0, pos + 1);
+ }
+
+ Some((positions, kind))
+ } else if conf.on_mention.is_some() {
+ match find_mention_end(content, conf) {
+ Some(mention_end) => {
+ let mut positions = vec![mention_end];
+
+ if conf.allow_whitespace {
+ positions.insert(0, mention_end + 1);
+ }
+
+ Some((positions, CommandType::Mention))
+ },
+ None => None,
+ }
+ } else {
+ None
+ }
+}
+
+fn find_mention_end(content: &str, conf: &Configuration) -> Option<usize> {
+ if let Some(ref mentions) = conf.on_mention {
+ for mention in mentions {
+ if !content.starts_with(&mention[..]) {
+ continue;
+ }
+
+ return Some(mention.len());
+ }
+ }
+
+ None
+}
diff --git a/src/ext/framework/mod.rs b/src/ext/framework/mod.rs
index 1949e24..80844c3 100644
--- a/src/ext/framework/mod.rs
+++ b/src/ext/framework/mod.rs
@@ -11,6 +11,13 @@ use std::thread;
use ::client::Context;
use ::model::Message;
+#[derive(Clone, Copy, Debug)]
+pub enum CommandType {
+ Mention,
+ None,
+ Prefix,
+}
+
#[allow(type_complexity)]
#[derive(Default)]
pub struct Framework {
@@ -31,54 +38,17 @@ impl Framework {
#[doc(hidden)]
pub fn dispatch(&mut self, context: Context, message: Message) {
- // Determine the point at which the prefix ends, and the command starts.
- let positions = if let Some(ref prefix) = self.configuration.prefix {
- let pos = if let Some(mention_ends) = self.find_mention_end(&message.content) {
- mention_ends
- } else if !message.content.starts_with(prefix) {
- return;
- } else {
- prefix.len()
- };
-
- let mut positions = vec![pos];
-
- if self.configuration.allow_whitespace {
- positions.push(pos - 1);
- }
-
- positions
- } else if self.configuration.on_mention.is_some() {
- match self.find_mention_end(&message.content) {
- Some(mention_end) => {
- let mut positions = vec![mention_end];
-
- if self.configuration.allow_whitespace {
- positions.push(mention_end - 1);
- }
+ let res = command::positions(&message.content, &self.configuration);
- positions
- },
- None => return,
- }
- } else {
- vec![0]
+ let (positions, kind) = match res {
+ Some((positions, kind)) => (positions, kind),
+ None => return,
};
- // Ensure that the message length is at least longer than the prefix
+ // Ensure that the message length is at least longer than a prefix
// length. There's no point in checking further ahead if there's nothing
- // to check.
- let mut less_than = true;
-
- for position in &positions {
- if message.content.len() > *position {
- less_than = false;
-
- break;
- }
- }
-
- if less_than {
+ // _to_ check.
+ if positions.iter().all(|p| message.content.len() <= *p) {
return;
}
@@ -86,7 +56,7 @@ impl Framework {
let mut built = String::new();
for i in 0..self.configuration.depth {
- if i > 0 {
+ if i != 0 {
built.push(' ');
}
@@ -113,7 +83,7 @@ impl Framework {
let command = command.clone();
thread::spawn(move || {
- let args = message.content[built.len() + 1..]
+ let args = message.content[position + built.len()..]
.split_whitespace()
.map(|arg| arg.to_owned())
.collect::<Vec<String>>();