diff options
Diffstat (limited to 'src/framework/help_commands.rs')
| -rw-r--r-- | src/framework/help_commands.rs | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/src/framework/help_commands.rs b/src/framework/help_commands.rs new file mode 100644 index 0000000..1f38bd5 --- /dev/null +++ b/src/framework/help_commands.rs @@ -0,0 +1,285 @@ +//! A collection of default help commands for the framework. +//! +//! # Example +//! +//! Using the [`with_embeds`] function to have the framework's help message use +//! embeds: +//! +//! ```rs,no_run +//! use serenity::ext::framework::help_commands; +//! use serenity::Client; +//! use std::env; +//! +//! let mut client = Client::login(&env::var("DISCORD_TOKEN").unwrap()); +//! client.with_framework(|f| f +//! .command("help", |c| c.exec_help(help_commands::with_embeds))); +//! ``` +//! +//! The same can be accomplished with no embeds by substituting `with_embeds` +//! with the [`plain`] function. +//! +//! [`plain`]: fn.plain.html +//! [`with_embeds`]: fn.with_embeds.html + +use std::collections::HashMap; +use std::sync::Arc; +use std::fmt::Write; +use super::command::InternalCommand; +use super::{Command, CommandGroup, CommandOrAlias}; +use ::client::Context; +use ::model::Message; +use ::utils::Colour; + +fn error_embed(ctx: &mut Context, input: &str) { + let _ = ctx.channel_id + .unwrap() + .send_message(|m| m + .embed(|e| e + .colour(Colour::dark_red()) + .description(input))); +} + +fn remove_aliases(cmds: &HashMap<String, CommandOrAlias>) -> HashMap<&String, &InternalCommand> { + let mut result = HashMap::new(); + + for (n, v) in cmds { + if let CommandOrAlias::Command(ref cmd) = *v { + result.insert(n, cmd); + } + } + + result +} + +pub fn with_embeds(ctx: &mut Context, + _: &Message, + groups: HashMap<String, Arc<CommandGroup>>, + args: &[String]) -> Result<(), String> { + if !args.is_empty() { + let name = args.join(" "); + + for (group_name, group) in groups { + let mut found: Option<(&String, &InternalCommand)> = None; + + for (command_name, command) in &group.commands { + let with_prefix = if let Some(ref prefix) = group.prefix { + format!("{} {}", prefix, command_name) + } else { + command_name.to_owned() + }; + + if name == with_prefix || name == *command_name { + match *command { + CommandOrAlias::Command(ref cmd) => { + found = Some((command_name, cmd)); + }, + CommandOrAlias::Alias(ref name) => { + error_embed(ctx, &format!("Did you mean \"{}\"?", name)); + return Ok(()); + } + } + } + } + + if let Some((command_name, command)) = found { + if !command.help_available { + error_embed(ctx, "**Error**: No help available."); + + return Ok(()); + } + + let _ = ctx.channel_id.unwrap().send_message(|m| { + m.embed(|e| { + let mut embed = e.colour(Colour::rosewater()) + .title(command_name); + if let Some(ref desc) = command.desc { + embed = embed.description(desc); + } + + if let Some(ref usage) = command.usage { + embed = embed.field(|f| f + .name("Usage") + .value(&format!("`{} {}`", command_name, usage))); + } + + if let Some(ref example) = command.example { + embed = embed.field(|f| f + .name("Sample usage") + .value(&format!("`{} {}`", command_name, example))); + } + + if group_name != "Ungrouped" { + embed = embed.field(|f| f + .name("Group") + .value(&group_name)); + } + + let available = if command.dm_only { + "Only in DM" + } else if command.guild_only { + "Only in guilds" + } else { + "In DM and guilds" + }; + + embed = embed.field(|f| f + .name("Available") + .value(available)); + + embed + }) + }); + + return Ok(()); + } + } + + let error_msg = format!("**Error**: Command `{}` not found.", name); + error_embed(ctx, &error_msg); + + return Ok(()); + } + + let _ = ctx.channel_id.unwrap().send_message(|m| m + .embed(|mut e| { + e = e.colour(Colour::rosewater()) + .description("To get help with an individual command, pass its \ + name as an argument to this command."); + + for (group_name, group) in groups { + let mut desc = String::new(); + + if let Some(ref x) = group.prefix { + let _ = write!(desc, "Prefix: {}\n", x); + } + + let mut no_commands = true; + + for (n, cmd) in remove_aliases(&group.commands) { + if cmd.help_available { + let _ = write!(desc, "`{}`\n", n); + + no_commands = false; + } + } + + if no_commands { + let _ = write!(desc, "*[No commands]*"); + } + + e = e.field(|f| f.name(&group_name).value(&desc)); + } + + e + })); + + Ok(()) +} + +pub fn plain(ctx: &mut Context, + _: &Message, + groups: HashMap<String, Arc<CommandGroup>>, + args: &[String]) -> Result<(), String> { + if !args.is_empty() { + let name = args.join(" "); + + for (group_name, group) in groups { + let mut found: Option<(&String, &Command)> = None; + + for (command_name, command) in &group.commands { + let with_prefix = if let Some(ref prefix) = group.prefix { + format!("{} {}", prefix, command_name) + } else { + command_name.to_owned() + }; + + if name == with_prefix || name == *command_name { + match *command { + CommandOrAlias::Command(ref cmd) => { + found = Some((command_name, cmd)); + }, + CommandOrAlias::Alias(ref name) => { + let _ = ctx.channel_id.unwrap().say(&format!("Did you mean {:?}?", name)); + return Ok(()); + } + } + } + } + + if let Some((command_name, command)) = found { + if !command.help_available { + let _ = ctx.channel_id.unwrap().say("**Error**: No help available."); + return Ok(()); + } + + let mut result = format!("**{}**\n", command_name); + + if let Some(ref desc) = command.desc { + let _ = write!(result, "**Description:** {}\n", desc); + } + + if let Some(ref usage) = command.usage { + let _ = write!(result, "**Usage:** `{} {}`\n", command_name, usage); + } + + if let Some(ref example) = command.example { + let _ = write!(result, "**Sample usage:** `{} {}`\n", command_name, example); + } + + if group_name != "Ungrouped" { + let _ = write!(result, "**Group:** {}\n", group_name); + } + + result.push_str("**Available:** "); + result.push_str(if command.dm_only { + "Only in DM" + } else if command.guild_only { + "Only in guilds" + } else { + "In DM and guilds" + }); + result.push_str("\n"); + + let _ = ctx.channel_id.unwrap().say(&result); + + return Ok(()); + } + } + + let _ = ctx.channel_id.unwrap().say(&format!("**Error**: Command `{}` not found.", name)); + + return Ok(()); + } + + let mut result = "**Commands**\nTo get help with an individual command, pass its \ + name as an argument to this command.\n\n" + .to_string(); + + for (group_name, group) in groups { + let _ = write!(result, "**{}:** ", group_name); + + if let Some(ref x) = group.prefix { + let _ = write!(result, "(prefix: `{}`): ", x); + } + + let mut no_commands = true; + + for (n, cmd) in remove_aliases(&group.commands) { + if cmd.help_available { + let _ = write!(result, "`{}` ", n); + + no_commands = false; + } + } + + if no_commands { + result.push_str("*[No Commands]*"); + } + + result.push('\n'); + } + + let _ = ctx.channel_id.unwrap().say(&result); + + Ok(()) +} |