diff options
| author | Illia K <[email protected]> | 2016-11-28 12:28:23 +0000 |
|---|---|---|
| committer | Austin Hellyer <[email protected]> | 2016-11-28 10:16:22 -0800 |
| commit | 6c2c7b73d9fb5ed46b642e323065c560ffef9ef2 (patch) | |
| tree | 8cb587fd6fcd8e3e06f8960475ea2a54432e3d18 /src | |
| parent | Add an initial tiny test suite to get Travis going (diff) | |
| download | serenity-6c2c7b73d9fb5ed46b642e323065c560ffef9ef2.tar.xz serenity-6c2c7b73d9fb5ed46b642e323065c560ffef9ef2.zip | |
Improve docs and add new message builder methods
Add documentation for some missing methods - such as Game methods - and
add more methods to the Message Builder.
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/context.rs | 41 | ||||
| -rw-r--r-- | src/client/error.rs | 5 | ||||
| -rw-r--r-- | src/client/gateway/prep.rs | 4 | ||||
| -rw-r--r-- | src/client/gateway/shard.rs | 4 | ||||
| -rw-r--r-- | src/client/rest/mod.rs | 26 | ||||
| -rw-r--r-- | src/ext/cache/mod.rs | 12 | ||||
| -rw-r--r-- | src/ext/voice/threading.rs | 6 | ||||
| -rw-r--r-- | src/model/channel.rs | 26 | ||||
| -rw-r--r-- | src/model/gateway.rs | 2 | ||||
| -rw-r--r-- | src/model/id.rs | 14 | ||||
| -rw-r--r-- | src/model/webhook.rs | 10 | ||||
| -rw-r--r-- | src/utils/builder/edit_guild.rs | 10 | ||||
| -rw-r--r-- | src/utils/builder/edit_profile.rs | 10 | ||||
| -rw-r--r-- | src/utils/message_builder.rs | 171 | ||||
| -rw-r--r-- | src/utils/mod.rs | 10 |
15 files changed, 262 insertions, 89 deletions
diff --git a/src/client/context.rs b/src/client/context.rs index 26ed22c..5558658 100644 --- a/src/client/context.rs +++ b/src/client/context.rs @@ -403,6 +403,7 @@ impl Context { /// [`Role`]: ../model/struct.Role.html /// [Attach Files]: ../model/permissions/constant.ATTACH_FILES.html /// [Manage Channels]: ../model/permissions/constant.MANAGE_CHANNELS.html + /// [Manage Webhooks]: ../model/permissions/constant.MANAGE_WEBHOOKS.html /// [Send TTS Messages]: ../model/permissions/constant.SEND_TTS_MESSAGES.html pub fn create_permission<C>(&self, channel_id: C, @@ -495,7 +496,7 @@ impl Context { /// [`Channel`]: ../model/enum.Channel.html /// [`Guild`]: ../model/struct.Guild.html /// [`GuildChannel`]: ../model/struct.GuildChannel.html - /// [Manage Messages]: ../model/permissions/constant.MANAGE_CHANNELS.html + /// [Manage Channels]: ../model/permissions/constant.MANAGE_CHANNELS.html pub fn delete_channel<C>(&self, channel_id: C) -> Result<Channel> where C: Into<ChannelId> { rest::delete_channel(channel_id.into().0) @@ -522,7 +523,7 @@ impl Context { rest::delete_guild(guild_id.into().0) } - /// Deletes an integration by Id from a server which Id was given. + /// Deletes an integration by Id from a guild which Id was given. pub fn delete_integration<G, I>(&self, guild_id: G, integration_id: I) -> Result<()> where G: Into<GuildId>, I: Into<IntegrationId> { rest::delete_guild_integration(guild_id.into().0, @@ -622,7 +623,7 @@ impl Context { /// Deletes the given [`Reaction`], but only if the current user is the user /// who made the reaction or has permission to. /// - /// **Note**: Requires the [`Manage Messages`] permission, _if_ the current + /// **Note**: Requires the [Manage Messages] permission, _if_ the current /// user did not perform the reaction. /// /// [`Reaction`]: ../model/struct.Reaction.html @@ -698,7 +699,8 @@ impl Context { } /// Allows to configure channel options like position, name, etc. - /// You can see available methods in `EditChannel` docs. + /// + /// You can see available methods in `EditChannel`s docs. /// /// # Examples /// @@ -758,19 +760,14 @@ impl Context { /// /// # Examples /// - /// Change a server's icon using a file name "icon.png": + /// Change a guild's icon using a file name "icon.png": /// /// ```rust,ignore /// use serenity::utils; /// /// // We are using read_image helper function from utils. - /// let base64_icon = match utils::read_image("./icon.png") { - /// Ok(base64_icon) => base64_icon, - /// Err(why) => { - /// println!("Error reading image: {:?}", why); - /// return; - /// }, - /// }; + /// let base64_icon = utils::read_image("./icon.png") + /// .expect("Failed to read image"); /// /// context.edit_guild(guild_id, |g| /// g.icon(base64_icon)); @@ -782,14 +779,14 @@ impl Context { rest::edit_guild(guild_id.into().0, map) } - /// Allows to do specific things with members of a server - /// like mute, change nickname, etc. - /// Full list of methods is available at `EditMember` docs. + /// Modify the properties of member of a guild, such as muting or nicknaming + /// them. + /// + /// Refer to `EditMember`s documentation for a full list of methods. /// /// # Examples /// - /// Mute a member and set their roles to just one role with - /// the predefined Id. + /// Mute a member and set their roles to just one role with a predefined Id: /// /// ```rust,ignore /// context.edit_member(guild_id, user_id, |m| m @@ -913,7 +910,7 @@ impl Context { rest::edit_note(user_id.into().0, map) } - /// Gets a vector of bans server has. + /// Gets a vector of bans guild has. pub fn get_bans<G: Into<GuildId>>(&self, guild_id: G) -> Result<Vec<Ban>> { rest::get_bans(guild_id.into().0) } @@ -960,13 +957,13 @@ impl Context { Ok(channels) } - /// Gets [`Emoji`] by the given Id from a server. + /// Gets an `Emoji` by the given Id from a guild. pub fn get_emoji<E, G>(&self, guild_id: G, emoji_id: E) -> Result<Emoji> where E: Into<EmojiId>, G: Into<GuildId> { rest::get_emoji(guild_id.into().0, emoji_id.into().0) } - /// Gets a vector of all [`Emojis`] a server has. + /// Gets a vector of all `Emoji` a guild has. pub fn get_emojis<G: Into<GuildId>>(&self, guild_id: G) -> Result<Vec<Emoji>> { rest::get_emojis(guild_id.into().0) @@ -1013,7 +1010,7 @@ impl Context { rest::get_invite(code) } - /// Gets `Member` of a specific server by Id, checking cache first. + /// Gets `Member` of a specific guild by Id, checking cache first. pub fn get_member<G, U>(&self, guild_id: G, user_id: U) -> Result<Member> where G: Into<GuildId>, U: Into<UserId> { let guild_id = guild_id.into(); @@ -1490,7 +1487,7 @@ impl Context { .set_presence(game, status, afk) } - /// Deletes an undefined amount of members from the given server + /// Deletes an undefined amount of members from the given guild /// based on the amount of days they've been offline for. /// /// **Note**: This will trigger [`GuildMemberRemove`] events diff --git a/src/client/error.rs b/src/client/error.rs index 76e0d2c..0ed3bd8 100644 --- a/src/client/error.rs +++ b/src/client/error.rs @@ -21,10 +21,7 @@ use ::model::{ChannelType, Permissions}; /// let mut client = Client::login_bot(&token); /// /// client.on_member_unban(|context, guild_id, user| { -/// let discriminator = match user.discriminator.parse::<u16>() { -/// Ok(discriminator) => discriminator, -/// Err(_why) => return, -/// }; +/// let discriminator = user.discriminator.parse::<u16>().unwrap(); /// /// // If the user has an even discriminator, don't re-ban them. /// if discriminator % 2 == 0 { diff --git a/src/client/gateway/prep.rs b/src/client/gateway/prep.rs index e3b8656..2ca435b 100644 --- a/src/client/gateway/prep.rs +++ b/src/client/gateway/prep.rs @@ -117,7 +117,7 @@ pub fn keepalive(interval: u64, }, Ok(GatewayStatus::SendMessage(val)) => { if let Err(why) = sender.send_json(&val) { - warn!("Err sending message: {:?}", why); + warn!("Error sending message: {:?}", why); } }, Ok(GatewayStatus::Sequence(seq)) => { @@ -137,7 +137,7 @@ pub fn keepalive(interval: u64, .build(); if let Err(why) = sender.send_json(&map) { - warn!("Err sending keepalive: {:?}", why); + warn!("Error sending keepalive: {:?}", why); } } } diff --git a/src/client/gateway/shard.rs b/src/client/gateway/shard.rs index ab2e561..e64d6fe 100644 --- a/src/client/gateway/shard.rs +++ b/src/client/gateway/shard.rs @@ -315,7 +315,7 @@ impl Shard { if let Some(session_id) = self.session_id.clone() { match self.resume(session_id, receiver) { Ok((ev, rec)) => return Ok(Some((ev, Some(rec)))), - Err(why) => debug!("Err resuming: {:?}", why), + Err(why) => debug!("Error resuming: {:?}", why), } } } @@ -335,7 +335,7 @@ impl Shard { if let Some(session_id) = self.session_id.clone() { match self.resume(session_id, &mut receiver) { Ok((ev, rec)) => return Ok(Some((ev, Some(rec)))), - Err(why) => debug!("Err resuming: {:?}", why), + Err(why) => debug!("Error resuming: {:?}", why), } } diff --git a/src/client/rest/mod.rs b/src/client/rest/mod.rs index b6218cd..4c2199a 100644 --- a/src/client/rest/mod.rs +++ b/src/client/rest/mod.rs @@ -392,7 +392,7 @@ pub fn create_role(guild_id: u64) -> Result<Role> { /// let channel_id = 81384788765712384; /// let map = ObjectBuilder::new().insert("name", "test").build(); /// -/// let webhook = rest::create_webhook(channel_id, map).expect("err creating"); +/// let webhook = rest::create_webhook(channel_id, map).expect("Error creating"); /// ``` /// /// [`GuildChannel`]: ../../model/struct.GuildChannel.html @@ -484,10 +484,8 @@ pub fn delete_messages(channel_id: u64, map: Value) -> Result<()> { /// let channel_id = ChannelId(7); /// let message_id = MessageId(8); /// -/// match rest::delete_message_reactions(channel_id.0, message_id.0) { -/// Ok(()) => println!("Reactions deleted"), -/// Err(why) => println!("Error deleting reactions: {:?}", why), -/// } +/// let _ = rest::delete_message_reactions(channel_id.0, message_id.0) +/// .expect("Error deleting reactions"); /// ``` /// /// [`Message`]: ../../model/struct.Message.html @@ -555,7 +553,7 @@ pub fn delete_role(guild_id: u64, role_id: u64) -> Result<()> { /// // must have initialized a client first. /// let client = Client::login_user(&env::var("DISCORD_TOKEN").unwrap()); /// -/// rest::delete_webhook(245037420704169985).expect("err deleting webhook"); +/// rest::delete_webhook(245037420704169985).expect("Error deleting webhook"); /// ``` /// /// [`Webhook`]: ../../model/struct.Webhook.html @@ -578,7 +576,7 @@ pub fn delete_webhook(webhook_id: u64) -> Result<()> { /// let id = 245037420704169985; /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV"; /// -/// rest::delete_webhook_with_token(id, token).expect("err deleting webhook"); +/// rest::delete_webhook_with_token(id, token).expect("Error deleting webhook"); /// /// [`Webhook`]: ../../model/struct.Webhook.html pub fn delete_webhook_with_token(webhook_id: u64, token: &str) -> Result<()> { @@ -727,11 +725,11 @@ pub fn edit_role(guild_id: u64, role_id: u64, map: Value) /// let id = 245037420704169985; /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV"; /// let image = serenity::utils::read_image("./webhook_img.png") -/// .expect("err reading image"); +/// .expect("Error reading image"); /// let map = ObjectBuilder::new().insert("avatar", image).build(); /// /// let edited = rest::edit_webhook_with_token(id, token, map) -/// .expect("err editing webhook"); +/// .expect("Error editing webhook"); /// ``` /// /// [`create_webhook`]: fn.create_webhook.html @@ -770,7 +768,7 @@ pub fn edit_webhook(webhook_id: u64, map: Value) -> Result<Webhook> { /// let map = ObjectBuilder::new().insert("name", "new name").build(); /// /// let edited = rest::edit_webhook_with_token(id, token, map) -/// .expect("err editing webhook"); +/// .expect("Error editing webhook"); /// ``` /// /// [`edit_webhook`]: fn.edit_webhook.html @@ -910,7 +908,7 @@ pub fn get_channel_invites(channel_id: u64) /// let channel_id = 81384788765712384; /// /// let webhooks = rest::get_channel_webhooks(channel_id) -/// .expect("err getting channel webhooks"); +/// .expect("Error getting channel webhooks"); /// ``` /// /// [`GuildChannel`]: ../../model/struct.GuildChannel.html @@ -1056,7 +1054,7 @@ pub fn get_guild_regions(guild_id: u64) -> Result<Vec<VoiceRegion>> { /// let guild_id = 81384788765712384; /// /// let webhooks = rest::get_guild_webhooks(guild_id) -/// .expect("err getting guild webhooks"); +/// .expect("Error getting guild webhooks"); /// ``` /// /// [`Guild`]: ../../model/struct.Guild.html @@ -1203,7 +1201,7 @@ pub fn get_voice_regions() -> Result<Vec<VoiceRegion>> { /// use serenity::client::rest; /// /// let id = 245037420704169985; -/// let webhook = rest::get_webhook(id).expect("err getting webhook"); +/// let webhook = rest::get_webhook(id).expect("Error getting webhook"); /// ``` /// /// [`get_webhook_with_token`]: fn.get_webhook_with_token.html @@ -1228,7 +1226,7 @@ pub fn get_webhook(webhook_id: u64) -> Result<Webhook> { /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV"; /// /// let webhook = rest::get_webhook_with_token(id, token) -/// .expect("err getting webhook"); +/// .expect("Error getting webhook"); /// ``` pub fn get_webhook_with_token(webhook_id: u64, token: &str) -> Result<Webhook> { let client = HyperClient::new(); diff --git a/src/ext/cache/mod.rs b/src/ext/cache/mod.rs index d07f7a6..0981cf3 100644 --- a/src/ext/cache/mod.rs +++ b/src/ext/cache/mod.rs @@ -325,7 +325,7 @@ impl Cache { /// Some(channel) => channel, /// None => { /// context.say("Could not find guild's channel data") - /// .map_err(|why| println!("Err sending message: {:?}", why)); + /// .map_err(|why| println!("Error sending message: {:?}", why)); /// /// return; /// }, @@ -373,8 +373,8 @@ impl Cache { /// let channel = match cache.get_guild_channel(message.channel_id) { /// Some(channel) => channel, /// None => { - /// if let Err(why) = context.say("Err finding channel data") { - /// println!("Err sending message: {:?}", why); + /// if let Err(why) = context.say("Error finding channel data") { + /// println!("Error sending message: {:?}", why); /// } /// }, /// }; @@ -382,8 +382,8 @@ impl Cache { /// match cache.get_member(channel.guild_id, message.author.id) { /// Some(member) => member, /// None => { - /// if let Err(why) = context.say("Err finding member data") { - /// println!("Err sending message: {:?}", why); + /// if let Err(why) = context.say("Error finding member data") { + /// println!("Error sending message: {:?}", why); /// } /// }, /// } @@ -392,7 +392,7 @@ impl Cache { /// let msg = format!("You have {} roles", member.roles.len()); /// /// if let Err(why) = context.say(&msg) { - /// println!("Err sending message: {:?}", why); + /// println!("Error sending message: {:?}", why); /// } /// ``` /// diff --git a/src/ext/voice/threading.rs b/src/ext/voice/threading.rs index 4110c5f..113c23d 100644 --- a/src/ext/voice/threading.rs +++ b/src/ext/voice/threading.rs @@ -13,7 +13,7 @@ pub fn start(target_id: Target, rx: MpscReceiver<Status>) { ThreadBuilder::new() .name(name) .spawn(move || runner(rx)) - .expect("Err starting voice"); + .expect("Error starting voice"); } fn runner(rx: MpscReceiver<Status>) { @@ -29,7 +29,7 @@ fn runner(rx: MpscReceiver<Status>) { connection = match Connection::new(info) { Ok(connection) => Some(connection), Err(why) => { - error!("Err connecting via voice: {:?}", why); + error!("Error connecting via voice: {:?}", why); None }, @@ -71,7 +71,7 @@ fn runner(rx: MpscReceiver<Status>) { match update { Ok(()) => false, Err(why) => { - error!("Err updating voice connection: {:?}", why); + error!("Error updating voice connection: {:?}", why); true }, diff --git a/src/model/channel.rs b/src/model/channel.rs index 9a3f9ea..a95b1f3 100644 --- a/src/model/channel.rs +++ b/src/model/channel.rs @@ -139,7 +139,7 @@ impl Attachment { /// /// // Make sure that the directory to store images in exists. /// fs::create_dir_all("./attachment_downloads") - /// .expect("err making directory"); + /// .expect("Error making directory"); /// /// let token = env::var("DISCORD_TOKEN").expect("token in environment"); /// let mut client = Client::login_bot(&token); @@ -820,6 +820,16 @@ impl GuildChannel { rest::broadcast_typing(self.id.0) } + /// Creates an invite leading to the given channel. + /// + /// # Examples + /// + /// Create an invite that can only be used 5 times: + /// + /// ```rust,ignore + /// let invite = channel.create_invite(|i| i + /// .max_uses(5)); + /// ``` #[cfg(feature = "methods")] pub fn create_invite<F>(&self, f: F) -> Result<RichInvite> where F: FnOnce(CreateInvite) -> CreateInvite { @@ -875,6 +885,19 @@ impl GuildChannel { rest::delete_channel(self.id.0) } + /// Modifies a channel's settings, such as its position or name. + /// + /// Refer to `EditChannel`s documentation for a full list of methods. + /// + /// # Examples + /// + /// Change a voice channels name and bitrate: + /// + /// ```rust,ignore + /// channel.edit(|c| c + /// .name("test") + /// .bitrate(71)); + /// ``` #[cfg(feature = "methods")] pub fn edit<F>(&mut self, f: F) -> Result<()> where F: FnOnce(EditChannel) -> EditChannel { @@ -919,6 +942,7 @@ impl GuildChannel { self.id.mention() } + /// Gets all channel's pins. #[cfg(feature = "methods")] pub fn pins(&self) -> Result<Vec<Message>> { rest::get_pins(self.id.0) diff --git a/src/model/gateway.rs b/src/model/gateway.rs index 101f050..30ed695 100644 --- a/src/model/gateway.rs +++ b/src/model/gateway.rs @@ -3,6 +3,7 @@ use super::*; use ::internal::prelude::*; impl Game { + /// Creates a `Game` struct that appears as a `**Playing** <name>` status. #[cfg(feature="methods")] pub fn playing(name: &str) -> Game { Game { @@ -12,6 +13,7 @@ impl Game { } } + /// Creates a `Game` struct that appears as a `**Streaming** <name>` status. #[cfg(feature="methods")] pub fn streaming(name: &str, url: &str) -> Game { Game { diff --git a/src/model/id.rs b/src/model/id.rs index cba72ae..5f534ec 100644 --- a/src/model/id.rs +++ b/src/model/id.rs @@ -50,6 +50,7 @@ impl ChannelId { } impl From<Channel> for ChannelId { + /// Gets the Id of a `Channel`. fn from(channel: Channel) -> ChannelId { match channel { Channel::Group(group) => group.channel_id, @@ -60,18 +61,21 @@ impl From<Channel> for ChannelId { } impl From<PrivateChannel> for ChannelId { + /// Gets the Id of a private channel. fn from(private_channel: PrivateChannel) -> ChannelId { private_channel.id } } impl From<GuildChannel> for ChannelId { + /// Gets the Id of a guild channel. fn from(public_channel: GuildChannel) -> ChannelId { public_channel.id } } impl From<Emoji> for EmojiId { + /// Gets the Id of an `Emoji`. fn from(emoji: Emoji) -> EmojiId { emoji.id } @@ -122,42 +126,49 @@ impl GuildId { } impl From<PartialGuild> for GuildId { + /// Gets the Id of a partial guild. fn from(guild: PartialGuild) -> GuildId { guild.id } } impl From<GuildInfo> for GuildId { + /// Gets the Id of Guild information struct. fn from(guild_info: GuildInfo) -> GuildId { guild_info.id } } impl From<InviteGuild> for GuildId { + /// Gets the Id of Invite Guild struct. fn from(invite_guild: InviteGuild) -> GuildId { invite_guild.id } } impl From<Guild> for GuildId { + /// Gets the Id of Guild. fn from(live_guild: Guild) -> GuildId { live_guild.id } } impl From<Integration> for IntegrationId { + /// Gets the Id of integration. fn from(integration: Integration) -> IntegrationId { integration.id } } impl From<Message> for MessageId { + /// Gets the Id of a `Message`. fn from(message: Message) -> MessageId { message.id } } impl From<Role> for RoleId { + /// Gets the Id of a `Role`. fn from(role: Role) -> RoleId { role.id } @@ -192,18 +203,21 @@ impl RoleId { } impl From<CurrentUser> for UserId { + /// Gets the Id of a `CurrentUser` struct. fn from(current_user: CurrentUser) -> UserId { current_user.id } } impl From<Member> for UserId { + /// Gets the Id of a `Member`. fn from(member: Member) -> UserId { member.user.id } } impl From<User> for UserId { + /// Gets the Id of a `User`. fn from(user: User) -> UserId { user.id } diff --git a/src/model/webhook.rs b/src/model/webhook.rs index 4553f30..9d3a393 100644 --- a/src/model/webhook.rs +++ b/src/model/webhook.rs @@ -41,7 +41,7 @@ impl Webhook { /// let mut webhook = rest::get_webhook_with_token(id, token) /// .expect("valid webhook"); /// - /// let _ = webhook.edit(Some("new name"), None).expect("err editing"); + /// let _ = webhook.edit(Some("new name"), None).expect("Error editing"); /// ``` /// /// Setting a webhook's avatar: @@ -56,9 +56,9 @@ impl Webhook { /// .expect("valid webhook"); /// /// let image = serenity::utils::read_image("./webhook_img.png") - /// .expect("err reading image"); + /// .expect("Error reading image"); /// - /// let _ = webhook.edit(None, Some(&image)).expect("err editing"); + /// let _ = webhook.edit(None, Some(&image)).expect("Error editing"); /// ``` /// /// [`rest::edit_webhook`]: ../client/rest/fn.edit_webhook.html @@ -114,7 +114,7 @@ impl Webhook { /// let mut webhook = rest::get_webhook_with_token(id, token) /// .expect("valid webhook"); /// - /// let _ = webhook.execute(|w| w.content("test")).expect("err executing"); + /// let _ = webhook.execute(|w| w.content("test")).expect("Error executing"); /// ``` /// /// Execute a webhook with message content of `test`, overriding the @@ -141,7 +141,7 @@ impl Webhook { /// .content("test") /// .username("serenity") /// .embeds(vec![embed])) - /// .expect("err executing"); + /// .expect("Error executing"); /// ``` #[cfg(feature="methods")] pub fn execute<F>(&self, f: F) -> Result<Message> diff --git a/src/utils/builder/edit_guild.rs b/src/utils/builder/edit_guild.rs index dd4ce84..43e93da 100644 --- a/src/utils/builder/edit_guild.rs +++ b/src/utils/builder/edit_guild.rs @@ -51,14 +51,8 @@ impl EditGuild { /// /// // assuming a `guild` has already been bound /// - /// let base64_icon = match utils::read_image("./guild_icon.png") { - /// Ok(base64_icon) => base64_icon, - /// Err(why) => { - /// println!("Error reading image: {:?}", why); - /// - /// return; - /// }, - /// }; + /// let base64_icon = utils::read_image("./guild_icon.png") + /// .expect("Failed to read image"); /// /// let _ = guild.edit(|g| g.icon(base64_icon)); /// ``` diff --git a/src/utils/builder/edit_profile.rs b/src/utils/builder/edit_profile.rs index 257a8e5..4517ae2 100644 --- a/src/utils/builder/edit_profile.rs +++ b/src/utils/builder/edit_profile.rs @@ -20,14 +20,8 @@ impl EditProfile { /// /// // assuming you are in a context /// - /// let base64 = match utils::read_image("./my_image.jpg") { - /// Ok(base64) => base64, - /// Err(why) => { - /// println!("Error reading image: {:?}", why); - /// - /// return; - /// }, - /// }; + /// let base64 = utils::read_image("./my_image.jpg") + /// .expect("Failed to read image"); /// /// let _ = context.edit_profile(|profile| { /// profile.avatar(Some(base64)) diff --git a/src/utils/message_builder.rs b/src/utils/message_builder.rs index ca1ac8d..0a78815 100644 --- a/src/utils/message_builder.rs +++ b/src/utils/message_builder.rs @@ -1,5 +1,5 @@ use std::default::Default; -use std::fmt; +use std::fmt::{self, Write}; use ::model::{ChannelId, Emoji, Mentionable, RoleId, UserId}; /// The Message Builder is an ergonomic utility to easily build a message, @@ -28,6 +28,28 @@ use ::model::{ChannelId, Emoji, Mentionable, RoleId, UserId}; /// [`build`]: #method.build /// [`emoji`]: #method.emoji /// [`user`]: #method.user + +fn normalize(text: &str) -> String { + // Remove everyone and here mentions + // This changes 'at' symbol to a full-width variation + text.replace("@everyone", "@everyone") + .replace("@here", "@here") + // Remove invite links and popular scam websites, mostly to prevent the + // current user from triggering various ad detectors + .replace("discord.gg", "discord․gg") + .replace("discord.me", "discord․me") + .replace("discordlist.net", "discordlist․net") + .replace("discordservers.com", "discordservers․com") + .replace("discordapp.com/invite", "discordapp․com/invite") + // Remove right-to-left and other similar overrides + .replace('\u{202E}', " ") // RTL + .replace('\u{200F}', " ") // RTL Mark + .replace('\u{202B}', " ") // RTL Embedding + .replace('\u{200B}', " ") // Zero-width space + .replace('\u{200D}', " ") // Zero-width joiner + .replace('\u{200C}', " ") // Zero-width non-joiner +} + pub struct MessageBuilder(pub String); impl MessageBuilder { @@ -65,7 +87,7 @@ impl MessageBuilder { /// [`GuildChannel`]: ../model/struct.GuildChannel.html /// [Display implementation]: ../model/struct.ChannelId.html#method.fmt-1 pub fn channel<C: Into<ChannelId>>(mut self, channel: C) -> Self { - self.0.push_str(&format!("{}", channel.into())); + write!(self.0, "{}", channel.into()); self } @@ -77,7 +99,7 @@ impl MessageBuilder { /// /// [Display implementation]: ../model/struct.Emoji.html#method.fmt pub fn emoji(mut self, emoji: Emoji) -> Self { - self.0.push_str(&format!("{}", emoji)); + write!(self.0, "{}", emoji); self } @@ -86,7 +108,7 @@ impl MessageBuilder { /// /// [`Mentionable`]: ../model/trait.Mentionable.html pub fn mention<M: Mentionable>(mut self, item: M) -> Self { - self.0.push_str(&item.mention()); + write!(self.0, "{}", item.mention()); self } @@ -112,6 +134,143 @@ impl MessageBuilder { self } + /// Pushes a code-block to your message, with optional syntax highlighting. + pub fn push_codeblock(mut self, content: &str, language: Option<&str>) -> Self { + self.0.push_str("```"); + + if let Some(language) = language { + self.0.push_str(language); + } + + self.0.push('\n'); + self.0.push_str(content); + self.0.push_str("\n```"); + + self + } + + /// Pushes an inline monospaced text to your message. + pub fn push_mono(mut self, content: &str) -> Self { + self.0.push('`'); + self.0.push_str(content); + self.0.push('`'); + + self + } + + /// Pushes an inline italicized text to your message. + pub fn push_italic(mut self, content: &str) -> Self { + self.0.push('_'); + self.0.push_str(content); + self.0.push('_'); + + self + } + + /// Pushes an inline bold text to your message. + pub fn push_bold(mut self, content: &str) -> Self { + self.0.push_str("**"); + self.0.push_str(content); + self.0.push_str("**"); + + self + } + + /// Pushes an underlined inline text to your message. + pub fn push_underline(mut self, content: &str) -> Self { + self.0.push_str("__"); + self.0.push_str(content); + self.0.push_str("__"); + + self + } + + /// Pushes a strikethrough inline text to your message. + pub fn push_strike(mut self, content: &str) -> Self { + self.0.push_str("~~"); + self.0.push_str(content); + self.0.push_str("~~"); + + self + } + + /// Pushes text to your message, but normalizing content - that means + /// ensuring that there's no unwanted formatting, mention spam etc. + pub fn push_safe(mut self, content: &str) -> Self { + let normalized = normalize(&content) + .replace('*', "\\*") + .replace('`', "\\`") + .replace('_', "\\_"); + + self.0.push_str(&normalized); + + self + } + + /// Pushes a code-block to your message normalizing content. + pub fn push_codeblock_safe(mut self, content: &str, language: Option<&str>) + -> Self { + let mut content = &normalize(&content) + .replace("```", "\u{201B}\u{201B}\u{201B}"); + + self.0.push_str("```"); + + if let Some(language) = language { + self.0.push_str(language); + } + + self.0.push('\n'); + self.0.push_str(content); + self.0.push_str("```"); + + self + } + + /// Pushes an inline monospaced text to your message normalizing content. + pub fn push_mono_safe(mut self, content: &str) -> Self { + self.0.push('`'); + self.0.push_str(&normalize(content).replace("`", "\u{201B}")); + self.0.push('`'); + + self + } + + /// Pushes an inline italicized text to your message normalizing content. + pub fn push_italic_safe(mut self, content: &str) -> Self { + self.0.push('_'); + self.0.push_str(&normalize(content).replace('_', "_")); + self.0.push('_'); + + self + } + + /// Pushes an inline bold text to your message normalizing content. + pub fn push_bold_safe(mut self, content: &str) -> Self { + self.0.push_str("**"); + self.0.push_str(&normalize(content).replace("**", "∗∗")); + self.0.push_str("**"); + + self + } + + /// Pushes an underlined inline text to your message normalizing content. + pub fn push_underline_safe(mut self, content: &str) -> Self { + self.0.push_str("__"); + self.0.push_str(&normalize(content).replace("__", "__")); + self.0.push_str("__"); + + self + } + + /// Pushes a strikethrough inline text to your message normalizing content. + pub fn push_strike_safe(mut self, content: &str) -> Self { + self.0.push_str("~~"); + self.0.push_str(&normalize(content).replace("~~", "∼∼")); + self.0.push_str("~~"); + + self + } + /// Mentions the [`Role`] in the built message. /// /// This accepts anything that converts _into_ a [`RoleId`]. Refer to @@ -124,7 +283,7 @@ impl MessageBuilder { /// [`RoleId`]: ../model/struct.RoleId.html /// [Display implementation]: ../model/struct.RoleId.html#method.fmt-1 pub fn role<R: Into<RoleId>>(mut self, role: R) -> Self { - self.0.push_str(&format!("{}", role.into())); + write!(self.0, "{}", role.into()); self } @@ -141,7 +300,7 @@ impl MessageBuilder { /// [`UserId`]: ../model/struct.UserId.html /// [Display implementation]: ../model/struct.UserId.html#method.fmt-1 pub fn user<U: Into<UserId>>(mut self, user: U) -> Self { - self.0.push_str(&format!("{}", user.into())); + write!(self.0, "{}", user.into()); self } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 2356ece..0c154dd 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -148,14 +148,8 @@ pub fn parse_invite(code: &str) -> &str { /// ```rust,no_run /// use serenity::utils; /// -/// let image = match utils::read_image("./cat.png") { -/// Ok(image) => image, -/// Err(why) => { -/// // properly handle the error -/// -/// return; -/// }, -/// }; +/// let image = utils::read_image("./cat.png") +/// .expect("Failed to read image"); /// ``` /// /// [`EditProfile::avatar`]: ../builder/struct.EditProfile.html#method.avatar |