aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml1
-rw-r--r--examples/06_command_framework/src/main.rs6
-rw-r--r--examples/08_search/src/main.rs15
-rw-r--r--src/client/context.rs39
-rw-r--r--src/ext/framework/command.rs16
-rw-r--r--src/ext/framework/configuration.rs2
-rw-r--r--src/ext/framework/create_command.rs10
-rw-r--r--src/ext/framework/create_group.rs4
-rw-r--r--src/ext/framework/help_commands.rs6
-rw-r--r--src/ext/framework/mod.rs38
-rw-r--r--src/utils/builder/search.rs11
-rw-r--r--tests/test_create_embed.rs22
12 files changed, 106 insertions, 64 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 9480917..9ef86a4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -51,4 +51,5 @@ cache = []
debug = []
framework = []
methods = []
+extras = []
voice = ["opus", "sodiumoxide"]
diff --git a/examples/06_command_framework/src/main.rs b/examples/06_command_framework/src/main.rs
index 4aeafe1..35a6994 100644
--- a/examples/06_command_framework/src/main.rs
+++ b/examples/06_command_framework/src/main.rs
@@ -81,9 +81,9 @@ fn main() {
let entry = counter.entry(command_name.clone()).or_insert(0);
*entry += 1;
- true
+ true // if `before` returns false, command processing doesn't happen.
})
- // Very similar to `before`, except this will be called directly _after_
+ // Similar to `before`, except will be called directly _after_
// command execution.
.after(|_, _, command_name, error| {
match error {
@@ -153,7 +153,7 @@ command!(commands(context, _msg, _args) {
// In this case, this command checks to ensure you are the owner of the message
// in order for the command to be executed. If the check fails, the command is
// not called.
-fn owner_check(_: &Context, message: &Message) -> bool {
+fn owner_check(_: &mut Context, message: &Message) -> bool {
// Replace 7 with your ID
message.author.id == 7
}
diff --git a/examples/08_search/src/main.rs b/examples/08_search/src/main.rs
index 53d194f..4fe0a0e 100644
--- a/examples/08_search/src/main.rs
+++ b/examples/08_search/src/main.rs
@@ -13,6 +13,7 @@
//! This particular example will automatically ensure that only the current user
//! may search; this acts as a "selfbot".
+#[macro_use]
extern crate serenity;
use serenity::client::{CACHE, Client, Context};
@@ -37,17 +38,17 @@ fn main() {
}
}
-fn self_check(_context: &Context, message: &Message) -> bool {
+fn self_check(_context: &mut Context, message: &Message) -> bool {
message.author.id == CACHE.read().unwrap().user.id
}
-fn search(context: &Context, message: &Message, args: Vec<String>) {
+command!(search(context, message, args) {
let query = args.join(" ");
if query.is_empty() {
let _ = context.say("You must provide a query");
- return;
+ return Ok(());
}
let guild_id = match message.guild_id() {
@@ -55,7 +56,7 @@ fn search(context: &Context, message: &Message, args: Vec<String>) {
None => {
let _ = context.say("Only supports guilds");
- return;
+ return Ok(());
},
};
@@ -67,7 +68,7 @@ fn search(context: &Context, message: &Message, args: Vec<String>) {
None => {
let _ = context.say("Guild data not found");
- return;
+ return Ok(());
},
};
@@ -94,7 +95,7 @@ fn search(context: &Context, message: &Message, args: Vec<String>) {
let _ = context.say("Error occurred while searching");
- return;
+ return Ok(());
},
};
@@ -112,4 +113,4 @@ fn search(context: &Context, message: &Message, args: Vec<String>) {
e
}));
-}
+});
diff --git a/src/client/context.rs b/src/client/context.rs
index d6d9ef9..ccf05fc 100644
--- a/src/client/context.rs
+++ b/src/client/context.rs
@@ -23,6 +23,9 @@ use ::internal::prelude::*;
use ::model::*;
use ::utils;
+#[cfg(feature="extras")]
+use std::ops::ShlAssign;
+
#[cfg(feature="cache")]
use super::CACHE;
@@ -94,6 +97,8 @@ pub struct Context {
/// Note that if you are sharding, in relevant terms, this is the shard
/// which received the event being dispatched.
pub shard: Arc<Mutex<Shard>>,
+ /// The queue of messages that are sent after context goes out of scope.
+ pub queue: String,
login_type: LoginType,
}
@@ -115,6 +120,7 @@ impl Context {
data: data,
shard: shard,
login_type: login_type,
+ queue: String::new(),
}
}
@@ -903,7 +909,7 @@ impl Context {
/// Change the current user's username:
///
/// ```rust,ignore
- /// context.edit_profile(|p| p.username("meew0"));
+ /// context.edit_profile(|p| p.username("Hakase"));
/// ```
pub fn edit_profile<F: FnOnce(EditProfile) -> EditProfile>(&self, f: F)
-> Result<CurrentUser> {
@@ -1445,6 +1451,20 @@ impl Context {
}
}
+ /// Adds a string to message queue, which is sent joined by a newline
+ /// when context goes out of scope.
+ ///
+ /// **Note**: Only works in a context where a channel is present. Refer to
+ /// [`say`] for a list of events where this is applicable.
+ ///
+ /// [`say`]: #method.say
+ pub fn queue(&mut self, content: &str) -> &mut Self {
+ self.queue.push('\n');
+ self.queue.push_str(content);
+
+ self
+ }
+
/// Searches a [`Channel`]'s messages by providing query parameters via the
/// search builder.
///
@@ -1880,3 +1900,20 @@ impl Context {
rest::unpin_message(channel_id.into().0, message_id.into().0)
}
}
+
+impl Drop for Context {
+ /// Combines and sends all queued messages.
+ fn drop(&mut self) {
+ if !self.queue.is_empty() {
+ let _ = self.say(&self.queue);
+ }
+ }
+}
+
+/// Allows the `<<=` operator to be used to queue messages.
+#[cfg(feature="extras")]
+impl<'a> ShlAssign<&'a str> for &'a mut Context {
+ fn shl_assign(&mut self, rhs: &str) {
+ self.queue(rhs);
+ }
+}
diff --git a/src/ext/framework/command.rs b/src/ext/framework/command.rs
index 92e6e93..70ee4ff 100644
--- a/src/ext/framework/command.rs
+++ b/src/ext/framework/command.rs
@@ -5,14 +5,14 @@ use ::model::Message;
use ::model::Permissions;
use std::collections::HashMap;
-pub type Check = Fn(&Context, &Message) -> bool + Send + Sync + 'static;
-pub type Exec = Fn(&Context, &Message, Vec<String>) -> Result<(), String> + Send + Sync + 'static;
-pub type Help = Fn(&Context, &Message, HashMap<String, Arc<CommandGroup>>, Vec<String>) -> Result<(), String> + Send + Sync + 'static;
-pub type BeforeHook = Fn(&Context, &Message, &String) -> bool + Send + Sync + 'static;
-pub type AfterHook = Fn(&Context, &Message, &String, Result<(), String>) + Send + Sync + 'static;
+pub type Check = Fn(&mut Context, &Message) -> bool + Send + Sync + 'static;
+pub type Exec = Fn(&mut Context, &Message, Vec<String>) -> Result<(), String> + Send + Sync + 'static;
+pub type Help = Fn(&mut Context, &Message, HashMap<String, Arc<CommandGroup>>, Vec<String>) -> Result<(), String> + Send + Sync + 'static;
+pub type BeforeHook = Fn(&mut Context, &Message, &String) -> bool + Send + Sync + 'static;
+pub type AfterHook = Fn(&mut Context, &Message, &String, Result<(), String>) + Send + Sync + 'static;
#[doc(hidden)]
pub type InternalCommand = Arc<Command>;
-pub type PrefixCheck = Fn(&Context) -> Option<String> + Send + Sync + 'static;
+pub type PrefixCheck = Fn(&mut Context) -> Option<String> + Send + Sync + 'static;
#[doc(hidden)]
pub enum CommandOrAlias {
@@ -71,7 +71,7 @@ pub struct Command {
impl Command {
pub fn new<F>(f: F) -> Self
- where F: Fn(&Context, &Message, Vec<String>) -> Result<(), String> + Send + Sync + 'static {
+ where F: Fn(&mut Context, &Message, Vec<String>) -> Result<(), String> + Send + Sync + 'static {
Command {
aliases: Vec::new(),
checks: Vec::default(),
@@ -92,7 +92,7 @@ impl Command {
}
}
-pub fn positions(ctx: &Context, content: &str, conf: &Configuration) -> Option<Vec<usize>> {
+pub fn positions(ctx: &mut Context, content: &str, 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.
diff --git a/src/ext/framework/configuration.rs b/src/ext/framework/configuration.rs
index d4ebb3e..611775a 100644
--- a/src/ext/framework/configuration.rs
+++ b/src/ext/framework/configuration.rs
@@ -177,7 +177,7 @@ impl Configuration {
/// Sets the prefix to respond to. This can either be a single- or
/// multi-char string.
pub fn dynamic_prefix<F>(mut self, dynamic_prefix: F) -> Self
- where F: Fn(&Context) -> Option<String> + Send + Sync + 'static {
+ where F: Fn(&mut Context) -> Option<String> + Send + Sync + 'static {
self.dynamic_prefix = Some(Box::new(dynamic_prefix));
self
diff --git a/src/ext/framework/create_command.rs b/src/ext/framework/create_command.rs
index c758f4a..4d1e1a5 100644
--- a/src/ext/framework/create_command.rs
+++ b/src/ext/framework/create_command.rs
@@ -54,19 +54,19 @@ impl CreateCommand {
/// .desc("Replies to a ping with a pong")
/// .exec(ping)));
///
- /// fn ping(context: &Context, _message: &Message, _args: Vec<String>) -> Result<(), String> {
+ /// fn ping(context: &mut Context, _message: &Message, _args: Vec<String>) -> Result<(), String> {
/// let _ = context.say("Pong!");
///
/// Ok(())
/// }
///
- /// fn owner_check(_context: &Context, message: &Message) -> bool {
+ /// fn owner_check(_context: &mut Context, message: &Message) -> bool {
/// // replace with your user ID
/// message.author.id == 7
/// }
/// ```
pub fn check<F>(mut self, check: F) -> Self
- where F: Fn(&Context, &Message) -> bool + Send + Sync + 'static {
+ where F: Fn(&mut Context, &Message) -> bool + Send + Sync + 'static {
self.0.checks.push(Box::new(check));
self
@@ -100,7 +100,7 @@ impl CreateCommand {
///
/// [`exec_str`]: #method.exec_str
pub fn exec<F>(mut self, func: F) -> Self
- where F: Fn(&Context, &Message, Vec<String>) -> Result<(), String> + Send + Sync + 'static {
+ where F: Fn(&mut Context, &Message, Vec<String>) -> Result<(), String> + Send + Sync + 'static {
self.0.exec = CommandType::Basic(Box::new(func));
self
@@ -112,7 +112,7 @@ impl CreateCommand {
///
/// You can return Err(string) if there's an error.
pub fn exec_help<F>(mut self, f: F) -> Self
- where F: Fn(&Context, &Message, HashMap<String, Arc<CommandGroup>>, Vec<String>) -> Result<(), String> + Send + Sync + 'static {
+ where F: Fn(&mut Context, &Message, HashMap<String, Arc<CommandGroup>>, Vec<String>) -> Result<(), String> + Send + Sync + 'static {
self.0.exec = CommandType::WithCommands(Box::new(f));
self
diff --git a/src/ext/framework/create_group.rs b/src/ext/framework/create_group.rs
index 465224d..03fc33e 100644
--- a/src/ext/framework/create_group.rs
+++ b/src/ext/framework/create_group.rs
@@ -21,7 +21,7 @@ pub struct CreateGroup(pub CommandGroup);
/// framework.group("Information", |g| g
/// .prefix("info")
/// .command("name", |c| c
-/// .exec_str("meew0")))
+/// .exec_str("Hakase")))
/// ```
impl CreateGroup {
/// Adds a command to group.
@@ -45,7 +45,7 @@ impl CreateGroup {
/// Adds a command to group with simplified API.
/// You can return Err(string) if there's an error.
pub fn on<F>(mut self, command_name: &str, f: F) -> Self
- where F: Fn(&Context, &Message, Vec<String>) -> Result<(), String> + Send + Sync + 'static {
+ where F: Fn(&mut Context, &Message, Vec<String>) -> Result<(), String> + Send + Sync + 'static {
let cmd = Arc::new(Command::new(f));
self.0.commands.insert(command_name.to_owned(), CommandOrAlias::Command(cmd));
diff --git a/src/ext/framework/help_commands.rs b/src/ext/framework/help_commands.rs
index 230d78a..119e362 100644
--- a/src/ext/framework/help_commands.rs
+++ b/src/ext/framework/help_commands.rs
@@ -7,7 +7,7 @@ use ::client::Context;
use ::model::Message;
use ::utils::Colour;
-fn error_embed(ctx: &Context, message: &Message, input: &str) {
+fn error_embed(ctx: &mut Context, message: &Message, input: &str) {
let _ = ctx.send_message(message.channel_id, |m| m
.embed(|e| e
.colour(Colour::dark_red())
@@ -26,7 +26,7 @@ fn remove_aliases(cmds: &HashMap<String, CommandOrAlias>) -> HashMap<&String, &I
result
}
-pub fn with_embeds(ctx: &Context,
+pub fn with_embeds(ctx: &mut Context,
message: &Message,
groups: HashMap<String, Arc<CommandGroup>>,
args: Vec<String>) -> Result<(), String> {
@@ -154,7 +154,7 @@ pub fn with_embeds(ctx: &Context,
Ok(())
}
-pub fn plain(ctx: &Context,
+pub fn plain(ctx: &mut Context,
_: &Message,
groups: HashMap<String, Arc<CommandGroup>>,
args: Vec<String>) -> Result<(), String> {
diff --git a/src/ext/framework/mod.rs b/src/ext/framework/mod.rs
index f1d5020..77c874f 100644
--- a/src/ext/framework/mod.rs
+++ b/src/ext/framework/mod.rs
@@ -113,28 +113,32 @@ use ::client::CACHE;
#[macro_export]
macro_rules! command {
($fname:ident($c:ident) $b:block) => {
- pub fn $fname($c: &$crate::client::Context, _: &$crate::model::Message, _: Vec<String>) -> ::std::result::Result<(), String> {
+ #[allow(unused_mut)]
+ pub fn $fname(mut $c: &mut $crate::client::Context, _: &$crate::model::Message, _: Vec<String>) -> ::std::result::Result<(), String> {
$b
Ok(())
}
};
($fname:ident($c:ident, $m:ident) $b:block) => {
- pub fn $fname($c: &$crate::client::Context, $m: &$crate::model::Message, _: Vec<String>) -> ::std::result::Result<(), String> {
+ #[allow(unused_mut)]
+ pub fn $fname(mut $c: &mut $crate::client::Context, $m: &$crate::model::Message, _: Vec<String>) -> ::std::result::Result<(), String> {
$b
Ok(())
}
};
($fname:ident($c:ident, $m:ident, $a:ident) $b:block) => {
- pub fn $fname($c: &$crate::client::Context, $m: &$crate::model::Message, $a: Vec<String>) -> ::std::result::Result<(), String> {
+ #[allow(unused_mut)]
+ pub fn $fname(mut $c: &mut $crate::client::Context, $m: &$crate::model::Message, $a: Vec<String>) -> ::std::result::Result<(), String> {
$b
Ok(())
}
};
($fname:ident($c:ident, $m:ident, $a:ident, $($name:ident: $t:ty),*) $b:block) => {
- pub fn $fname($c: &$crate::client::Context, $m: &$crate::model::Message, $a: Vec<String>) -> ::std::result::Result<(), String> {
+ #[allow(unused_mut)]
+ pub fn $fname(mut $c: &mut $crate::client::Context, $m: &$crate::model::Message, $a: Vec<String>) -> ::std::result::Result<(), String> {
let mut i = $a.iter();
let mut arg_counter = 0;
@@ -260,7 +264,7 @@ impl Framework {
#[allow(cyclomatic_complexity)]
#[doc(hidden)]
- pub fn dispatch(&mut self, context: Context, message: Message) {
+ pub fn dispatch(&mut self, mut context: Context, message: Message) {
match self.configuration.account_type {
AccountType::Selfbot => {
if message.author.id != self.user_info.0 {
@@ -281,7 +285,7 @@ impl Framework {
},
AccountType::Any => {}
}
- let res = command::positions(&context, &message.content, &self.configuration);
+ let res = command::positions(&mut context, &message.content, &self.configuration);
let positions = match res {
Some(mut positions) => {
@@ -437,7 +441,7 @@ impl Framework {
}
for check in &command.checks {
- if !(check)(&context, &message) {
+ if !(check)(&mut context, &message) {
if let Some(ref message) = self.configuration.invalid_check_message {
let _ = context.say(message);
}
@@ -516,27 +520,27 @@ impl Framework {
thread::spawn(move || {
if let Some(before) = before {
- if !(before)(&context, &message, &built) && !is_owner {
+ if !(before)(&mut context, &message, &built) && !is_owner {
return;
}
}
let result = match command.exec {
CommandType::StringResponse(ref x) => {
- let _ = &context.say(x);
+ let _ = &mut context.say(x);
Ok(())
},
CommandType::Basic(ref x) => {
- (x)(&context, &message, args)
+ (x)(&mut context, &message, args)
},
CommandType::WithCommands(ref x) => {
- (x)(&context, &message, groups, args)
+ (x)(&mut context, &message, groups, args)
}
};
if let Some(after) = after {
- (after)(&context, &message, &built, result);
+ (after)(&mut context, &message, &built, result);
}
});
@@ -563,7 +567,7 @@ impl Framework {
/// [`command`]: #method.command
/// [module-level documentation]: index.html
pub fn on<F, S>(mut self, command_name: S, f: F) -> Self
- where F: Fn(&Context, &Message, Vec<String>) -> Result<(), String> + Send + Sync + 'static,
+ where F: Fn(&mut Context, &Message, Vec<String>) -> Result<(), String> + Send + Sync + 'static,
S: Into<String> {
{
let ungrouped = self.groups.entry("Ungrouped".to_owned())
@@ -636,7 +640,7 @@ impl Framework {
/// Specify the function to be called prior to every command's execution.
/// If that function returns true, the command will be executed.
pub fn before<F>(mut self, f: F) -> Self
- where F: Fn(&Context, &Message, &String) -> bool + Send + Sync + 'static {
+ where F: Fn(&mut Context, &Message, &String) -> bool + Send + Sync + 'static {
self.before = Some(Arc::new(f));
self
@@ -645,7 +649,7 @@ impl Framework {
/// Specify the function to be called after every command's execution.
/// Fourth argument exists if command returned an error which you can handle.
pub fn after<F>(mut self, f: F) -> Self
- where F: Fn(&Context, &Message, &String, Result<(), String>) + Send + Sync + 'static {
+ where F: Fn(&mut Context, &Message, &String, Result<(), String>) + Send + Sync + 'static {
self.after = Some(Arc::new(f));
self
@@ -675,14 +679,14 @@ impl Framework {
/// let _ = context.say("Pong!");
/// });
///
- /// fn owner_check(_context: &Context, message: &Message) -> bool {
+ /// fn owner_check(_context: &mut Context, message: &Message) -> bool {
/// // replace with your user ID
/// message.author.id == 7
/// }
/// ```
#[deprecated(since="0.1.2", note="Use the `CreateCommand` builder's `check` instead.")]
pub fn set_check<F, S>(mut self, command: S, check: F) -> Self
- where F: Fn(&Context, &Message) -> bool + Send + Sync + 'static,
+ where F: Fn(&mut Context, &Message) -> bool + Send + Sync + 'static,
S: Into<String> {
{
let ungrouped = self.groups.entry("Ungrouped".to_owned())
diff --git a/src/utils/builder/search.rs b/src/utils/builder/search.rs
index 5b54157..cf61bed 100644
--- a/src/utils/builder/search.rs
+++ b/src/utils/builder/search.rs
@@ -108,7 +108,7 @@ impl SortingOrder {
/// limiting to 2 results, and only searching channels that have a name
/// prefixed with `"search-"`:
///
-/// ```rust,no_run
+/// ```rust,ignore
/// use serenity::client::{Client, Context};
/// use serenity::model::Message;
/// use serenity::utils::builder::{SortingMode, SortingOrder};
@@ -120,7 +120,7 @@ impl SortingOrder {
/// .configure(|c| c.prefix("~").on_mention(true))
/// .on("search", search));
///
-/// fn search(context: &Context, message: &Message, args: Vec<String>) -> Result<(), String> {
+/// command!(search(context, message, args) {
/// let query = args.join(" ");
///
/// if query.is_empty() {
@@ -131,7 +131,8 @@ impl SortingOrder {
///
/// let guild = message.guild().unwrap();
///
-/// let channel_ids = guild.channels
+/// let channel_ids = guild
+/// .channels
/// .values()
/// .filter(|c| c.name.starts_with("search-"))
/// .map(|c| c.id)
@@ -175,9 +176,7 @@ impl SortingOrder {
///
/// e
/// }));
-///
-/// Ok(())
-/// }
+/// });
/// ```
///
/// [`Channel`]: ../../model/enum.Channel.html
diff --git a/tests/test_create_embed.rs b/tests/test_create_embed.rs
index be9b82e..e76c907 100644
--- a/tests/test_create_embed.rs
+++ b/tests/test_create_embed.rs
@@ -28,30 +28,30 @@ fn test_from_embed() {
image: Some(EmbedImage {
height: 213,
proxy_url: "a".to_owned(),
- url: "https://i.imgur.com/q9MqLqZ.png".to_owned(),
+ url: "https://i.imgur.com/XfWpfCV.gif".to_owned(),
width: 224,
}),
kind: "rich".to_owned(),
provider: None,
thumbnail: None,
timestamp: None,
- title: Some("funny cat meme".to_owned()),
- url: Some("https://i.imgur.com/q9MqLqZ.png".to_owned()),
+ title: Some("hakase".to_owned()),
+ url: Some("https://i.imgur.com/XfWpfCV.gif".to_owned()),
video: None,
};
let builder = CreateEmbed::from(embed)
.colour(0xFF0000)
- .description("This is a cat description")
- .image("https://i.imgur.com/q9MqLqZ.jpg")
- .title("still a funny cat meme")
- .url("https://i.imgur.com/q9MqLqZ.jpg");
+ .description("This is a hakase description")
+ .image("https://i.imgur.com/XfWpfCV.gif")
+ .title("still a hakase")
+ .url("https://i.imgur.com/XfWpfCV.gif");
let built = Value::Object(builder.0);
let obj = ObjectBuilder::new()
.insert("color", 0xFF0000)
- .insert("description", "This is a cat description")
+ .insert("description", "This is a hakase description")
.insert_array("fields", |a| a
.push_object(|o| o
.insert("inline", false)
@@ -62,10 +62,10 @@ fn test_from_embed() {
.insert("name", "c")
.insert("value", "z")))
.insert_object("image", |o| o
- .insert("url", "https://i.imgur.com/q9MqLqZ.jpg"))
- .insert("title", "still a funny cat meme")
+ .insert("url", "https://i.imgur.com/XfWpfCV.gif"))
+ .insert("title", "still a hakase")
.insert("type", "rich")
- .insert("url", "https://i.imgur.com/q9MqLqZ.jpg")
+ .insert("url", "https://i.imgur.com/XfWpfCV.gif")
.build();
assert_eq!(built, obj);