aboutsummaryrefslogtreecommitdiff
path: root/src/framework
diff options
context:
space:
mode:
Diffstat (limited to 'src/framework')
-rw-r--r--src/framework/standard/command.rs118
-rw-r--r--src/framework/standard/create_command.rs8
-rw-r--r--src/framework/standard/create_group.rs9
-rw-r--r--src/framework/standard/create_help_command.rs213
-rw-r--r--src/framework/standard/help_commands.rs125
-rw-r--r--src/framework/standard/mod.rs70
6 files changed, 467 insertions, 76 deletions
diff --git a/src/framework/standard/command.rs b/src/framework/standard/command.rs
index 7697b3b..ec18766 100644
--- a/src/framework/standard/command.rs
+++ b/src/framework/standard/command.rs
@@ -4,17 +4,18 @@ use std::collections::HashMap;
use std::fmt;
use std::fmt::{Debug, Formatter};
use std::sync::Arc;
-use super::{Args, Configuration};
+use utils::Colour;
+use super::{Args, Configuration, HelpBehaviour};
pub type Check = Fn(&mut Context, &Message, &mut Args, &CommandOptions) -> bool
+ Send
+ Sync
+ 'static;
-pub type HelpFunction = fn(&mut Context, &Message, HashMap<String, Arc<CommandGroup>>, Args)
+pub type HelpFunction = fn(&mut Context, &Message, &HelpOptions, HashMap<String, Arc<CommandGroup>>, Args)
-> Result<(), Error>;
-pub struct Help(pub HelpFunction);
+pub struct Help(pub HelpFunction, pub Arc<HelpOptions>);
impl Debug for Help {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
@@ -22,6 +23,12 @@ impl Debug for Help {
}
}
+impl HelpCommand for Help {
+ fn execute(&self, c: &mut Context, m: &Message, ho: &HelpOptions,hm: HashMap<String, Arc<CommandGroup>>, a: Args) -> Result<(), Error> {
+ (self.0)(c, m, ho, hm, a)
+ }
+}
+
pub type BeforeHook = Fn(&mut Context, &Message, &str) -> bool + Send + Sync + 'static;
pub type AfterHook = Fn(&mut Context, &Message, &str, Result<(), Error>) + Send + Sync + 'static;
pub(crate) type InternalCommand = Arc<Command>;
@@ -116,6 +123,101 @@ pub struct CommandOptions {
pub aliases: Vec<String>,
}
+#[derive(Debug)]
+pub struct HelpOptions {
+ /// Suggests a command's name.
+ pub suggestion_text: String,
+ /// If no help is available, this text will be displayed.
+ pub no_help_available_text: String,
+ /// How to use a command, `{usage_label}: {command_name} {args}`
+ pub usage_label: String,
+ /// Actual sample label, `{usage_sample_label}: {command_name} {args}`
+ pub usage_sample_label: String,
+ /// Text labeling ungrouped commands, `{ungrouped_label}: ...`
+ pub ungrouped_label: String,
+ /// Text labeling the start of the description.
+ pub description_label: String,
+ /// Text labeling grouped commands, `{grouped_label} {group_name}: ...`
+ pub grouped_label: String,
+ /// Text labeling a command's alternative names (aliases).
+ pub aliases_label: String,
+ /// Text specifying that a command is only usable in a guild.
+ pub guild_only_text: String,
+ /// Text specifying that a command is only usable in via DM.
+ pub dm_only_text: String,
+ /// Text specifying that a command can be used via DM and in guilds.
+ pub dm_and_guild_text: String,
+ /// Text expressing that a command is available.
+ pub available_text: String,
+ /// Error-message once a command could not be found.
+ /// Output-example (without whitespace between both substitutions: `{command_not_found_text}{command_name}`
+ /// `{command_name}` describes user's input as in: `{prefix}help {command_name}`.
+ pub command_not_found_text: String,
+ /// Explains the user on how to use access a single command's details.
+ pub individual_command_tip: String,
+ /// Explains reasoning behind striked commands, see fields requiring `HelpBehaviour` for further information.
+ /// If `HelpBehaviour::Strike` is unused, this field will evaluate to `None` during creation
+ /// inside of `CreateHelpCommand`.
+ pub striked_commands_tip: Option<String>,
+ /// Announcing a group's prefix as in: {group_prefix} {prefix}.
+ pub group_prefix: String,
+ /// If a user lacks required roles, this will treat how these commands will be displayed.
+ pub lacking_role: HelpBehaviour,
+ /// If a user lacks permissions, this will treat how these commands will be displayed.
+ pub lacking_permissions: HelpBehaviour,
+ /// If a user is using the help-command in a channel where a command is not available,
+ /// this behaviour will be executed.
+ pub wrong_channel: HelpBehaviour,
+ /// Colour help-embed will use upon encountering an error.
+ pub embed_error_colour: Colour,
+ /// Colour help-embed will use if no error occured.
+ pub embed_success_colour: Colour,
+}
+
+pub trait HelpCommand: Send + Sync + 'static {
+ fn execute(&self, &mut Context, &Message, &HelpOptions, HashMap<String, Arc<CommandGroup>>, Args) -> Result<(), Error>;
+
+ fn options(&self) -> Arc<CommandOptions> {
+ Arc::clone(&DEFAULT_OPTIONS)
+ }
+}
+
+impl HelpCommand for Arc<HelpCommand> {
+ fn execute(&self, c: &mut Context, m: &Message, ho: &HelpOptions, hm: HashMap<String, Arc<CommandGroup>>, a: Args) -> Result<(), Error> {
+ (**self).execute(c, m, ho, hm, a)
+ }
+}
+
+impl Default for HelpOptions {
+ fn default() -> HelpOptions {
+ HelpOptions {
+ suggestion_text: "Did you mean {}?".to_string(),
+ no_help_available_text: "**Error**: No help available.".to_string(),
+ usage_label: "Usage".to_string(),
+ usage_sample_label: "Sample usage".to_string(),
+ ungrouped_label: "Ungrouped".to_string(),
+ grouped_label: "Group".to_string(),
+ aliases_label: "Aliases".to_string(),
+ description_label: "Description".to_string(),
+ guild_only_text: "Only in guilds".to_string(),
+ dm_only_text: "Only in DM".to_string(),
+ dm_and_guild_text: "In DM and guilds".to_string(),
+ available_text: "Available".to_string(),
+ command_not_found_text: "**Error**: Command `{}` not found.".to_string(),
+ individual_command_tip: "To get help with an individual command, pass its \
+ name as an argument to this command.".to_string(),
+ group_prefix: "Prefix".to_string(),
+ striked_commands_tip: Some(String::new()),
+ lacking_role: HelpBehaviour::Strike,
+ lacking_permissions: HelpBehaviour::Strike,
+ wrong_channel: HelpBehaviour::Strike,
+ embed_error_colour: Colour::dark_red(),
+ embed_success_colour: Colour::rosewater(),
+ }
+ }
+}
+
+
lazy_static! {
static ref DEFAULT_OPTIONS: Arc<CommandOptions> = Arc::new(CommandOptions::default());
}
@@ -151,7 +253,7 @@ impl Command for Arc<Command> {
(**self).init()
}
- fn before(&self, c: &mut Context, m: &Message) -> bool {
+ fn before(&self, c: &mut Context, m: &Message) -> bool {
(**self).before(c, m)
}
@@ -173,7 +275,7 @@ impl Command for Box<Command> {
(**self).init()
}
- fn before(&self, c: &mut Context, m: &Message) -> bool {
+ fn before(&self, c: &mut Context, m: &Message) -> bool {
(**self).before(c, m)
}
@@ -182,9 +284,9 @@ impl Command for Box<Command> {
}
}
-impl<F> Command for F where F: Fn(&mut Context, &Message, Args) -> Result<(), Error>
- + Send
- + Sync
+impl<F> Command for F where F: Fn(&mut Context, &Message, Args) -> Result<(), Error>
+ + Send
+ + Sync
+ ?Sized
+ 'static {
fn execute(&self, c: &mut Context, m: &Message, a: Args) -> Result<(), Error> {
diff --git a/src/framework/standard/create_command.rs b/src/framework/standard/create_command.rs
index 44e9988..0df649d 100644
--- a/src/framework/standard/create_command.rs
+++ b/src/framework/standard/create_command.rs
@@ -114,22 +114,22 @@ impl CreateCommand {
self
}
-
+
/// Like [`exec`] but accepts a `Command` directly.
///
/// [`exec`]: #method.exec
pub fn cmd<C: Command + 'static>(mut self, c: C) -> Self {
self.1 = FnOrCommand::Command(Arc::new(c));
-
+
self
}
-
+
/// Like [`cmd`] but says to the builder to use this command's options instead of its own.
///
/// [`cmd`]: #method.cmd
pub fn cmd_with_options<C: Command + 'static>(mut self, c: C) -> Self {
self.1 = FnOrCommand::CommandWithOptions(Arc::new(c));
-
+
self
}
diff --git a/src/framework/standard/create_group.rs b/src/framework/standard/create_group.rs
index 25279ca..77fb348 100644
--- a/src/framework/standard/create_group.rs
+++ b/src/framework/standard/create_group.rs
@@ -1,6 +1,6 @@
pub use super::command::{Command, CommandGroup, CommandOptions, Error as CommandError};
pub(crate) use super::command::CommandOrAlias;
-pub(crate) use super::command::{Help, HelpFunction};
+pub use super::create_help_command::{CreateHelpCommand};
pub use super::create_command::{CreateCommand, FnOrCommand};
pub use super::Args;
@@ -90,13 +90,6 @@ impl CreateGroup {
self
}
- /// Sets what code should be execute when a user requests for `(prefix)help`.
- pub fn help(mut self, f: HelpFunction) -> Self {
- self.0.help = Some(Arc::new(Help(f)));
-
- self
- }
-
/// If prefix is set, it will be required before all command names.
/// For example, if bot prefix is "~" and group prefix is "image"
/// we'd call a subcommand named "hibiki" by sending "~image hibiki".
diff --git a/src/framework/standard/create_help_command.rs b/src/framework/standard/create_help_command.rs
new file mode 100644
index 0000000..08cc6b4
--- /dev/null
+++ b/src/framework/standard/create_help_command.rs
@@ -0,0 +1,213 @@
+use super::command::{Help, HelpOptions, HelpFunction};
+pub use super::{Args, CommandGroup, CommandOptions, CommandError, HelpBehaviour};
+
+use utils::Colour;
+use std::fmt::Write;
+use std::sync::Arc;
+
+pub struct CreateHelpCommand(pub HelpOptions, pub HelpFunction);
+
+impl CreateHelpCommand {
+
+ /// Sets a message displaying if input could not be found
+ /// but a similar command is available.
+ ///
+ /// **Note**: `{}` will be substituted with the actual suggested command-name.
+ /// Hence no `{}` results in no command-name.
+ pub fn suggestion_text(mut self, text: &str) -> Self {
+ self.0.suggestion_text = text.to_string();
+
+ self
+ }
+
+ /// Sets a message displaying if there is no help available.
+ pub fn no_help_available_text(mut self, text: &str) -> Self {
+ self.0.no_help_available_text = text.to_string();
+
+ self
+ }
+
+ /// Sets a label for usage of a command.
+ pub fn usage_label(mut self, text: &str) -> Self {
+ self.0.usage_label = text.to_string();
+
+ self
+ }
+
+ /// Sets a label for the usage examples of a command.
+ pub fn usage_sample_label(mut self, text: &str) -> Self {
+ self.0.usage_sample_label = text.to_string();
+
+ self
+ }
+
+ /// Sets a label for ungrouped-commands
+ pub fn ungrouped_label(mut self, text: &str) -> Self {
+ self.0.ungrouped_label = text.to_string();
+
+ self
+ }
+
+ /// Sets a label for grouped-commands.
+ pub fn grouped_label(mut self, text: &str) -> Self {
+ self.0.grouped_label = text.to_string();
+
+ self
+ }
+
+ /// Sets a label for aliases.
+ pub fn aliases_label(mut self, text: &str) -> Self {
+ self.0.aliases_label = text.to_string();
+
+ self
+ }
+
+ /// Sets a message displaying if a command is only available
+ /// in guilds.
+ pub fn guild_only_text(mut self, text: &str) -> Self {
+ self.0.guild_only_text = text.to_string();
+
+ self
+ }
+
+ /// Sets a message displaying if a command is only available
+ /// in direct messages (DMs);
+ pub fn dm_only_text(mut self, text: &str) -> Self {
+ self.0.dm_only_text = text.to_string();
+
+ self
+ }
+
+ /// Sets a message displaying if a command is available in
+ /// guilds and DMs.
+ pub fn dm_and_guilds_text(mut self, text: &str) -> Self {
+ self.0.dm_and_guild_text = text.to_string();
+
+ self
+ }
+
+ /// Sets a message displaying if a command is available to use.
+ pub fn available_text(mut self, text: &str) -> Self {
+ self.0.available_text = text.to_string();
+
+ self
+ }
+
+ /// Sets a message that will appear upon failing to find
+ /// an individual command.
+ /// As in: `{prefix}help {command_name}`, but a command or
+ /// alias like `{command_name}` does not exist.
+ ///
+ /// **Note**: `{}` will be substituted with the actual suggested command-name.
+ /// Hence no `{}` results in no command-name.
+ pub fn command_not_found_text(mut self, text: &str) -> Self {
+ self.0.command_not_found_text = text.to_string();
+
+ self
+ }
+
+ /// Sets the message on top of the help-menu, informing the
+ /// user how to obtain more information about a single command.
+ pub fn individual_command_tip(mut self, text: &str) -> Self {
+ self.0.individual_command_tip = text.to_string();
+
+ self
+ }
+
+ /// Sets how the group-prexix shall be labeled.
+ pub fn group_prefix(mut self, text: &str) -> Self {
+ self.0.group_prefix = text.to_string();
+
+ self
+ }
+
+ /// Sets how a command requiring roles, that a user is lacking,
+ /// shall appear in the help-menu.
+ pub fn lacking_role(mut self, behaviour: HelpBehaviour) -> Self {
+ self.0.lacking_role = behaviour;
+
+ self
+ }
+
+ /// Sets how a command requiring permission, that a user is lacking,
+ /// shall be appear in the help-menu.
+ pub fn lacking_permissions(mut self, behaviour: HelpBehaviour) -> Self {
+ self.0.lacking_permissions = behaviour;
+
+ self
+ }
+
+ /// Sets how a command requiring to be sent in either via DM
+ /// or a guild should be treated in the help-menu.
+ pub fn wrong_channel(mut self, behaviour: HelpBehaviour) -> Self {
+ self.0.wrong_channel = behaviour;
+
+ self
+ }
+
+ /// Sets the tip (or legend) explaining why some commands are striked.
+ /// By default this is `Some(String)` and the `String` is empty resulting
+ /// in an automated substitution based on your `HelpBehaviour`-settings.
+ /// If set to `None`, no tip will be given nor will it be substituted.
+ /// If set to a non-empty `Some(String)`, the `String` will be displayed as tip.
+ pub fn striked_commands_tip(mut self, text: Option<String>) -> Self {
+ self.0.striked_commands_tip = text;
+
+ self
+ }
+
+ /// Sets the colour for the embed if an error occured.
+ pub fn embed_success_colour(mut self, colour: Colour) -> Self {
+ self.0.embed_success_colour = colour;
+
+ self
+ }
+
+ /// Sets the colour for the embed if no error occured.
+ pub fn embed_error_colour(mut self, colour: Colour) -> Self {
+ self.0.embed_error_colour = colour;
+
+ self
+ }
+
+ /// Finishes the creation of a help-command, returning `Help`.
+ /// If `Some(String)` was set as `striked_commands_tip` and the `String` is empty,
+ /// the creator will substitute content based on the `HelpBehaviour`-settings.
+ pub(crate) fn finish(self) -> Arc<Help> {
+ if self.0.striked_commands_tip == Some(String::new()) {
+ let mut strike_text = String::from("~~`Striked commands`~~ are unavailable because they");
+ let mut concat_with_comma = false;
+
+ if self.0.lacking_permissions == HelpBehaviour::Strike {
+ let _ = write!(strike_text, "require permissions");
+ concat_with_comma = true;
+ }
+
+ if self.0.lacking_role == HelpBehaviour::Strike {
+
+ if concat_with_comma {
+ let _ = write!(strike_text, ", require a specific role");
+ } else {
+ let _ = write!(strike_text, " require a specific role");
+ concat_with_comma = true;
+ }
+ }
+
+ if self.0.wrong_channel == HelpBehaviour::Strike {
+
+ if concat_with_comma {
+ let _ = write!(strike_text, " and are limited to DM/guilds");
+ } else {
+ let _ = write!(strike_text, " are limited to DM/guilds");
+ }
+ }
+
+ let _ = write!(strike_text, ".");
+ let CreateHelpCommand(options, function) = self.striked_commands_tip(Some(strike_text));
+ return Arc::new(Help(function, Arc::new(options)))
+ }
+ let CreateHelpCommand(options, function) = self;
+
+ Arc::new(Help(function, Arc::new(options)))
+ }
+} \ No newline at end of file
diff --git a/src/framework/standard/help_commands.rs b/src/framework/standard/help_commands.rs
index 8111cea..b2fc9f5 100644
--- a/src/framework/standard/help_commands.rs
+++ b/src/framework/standard/help_commands.rs
@@ -29,13 +29,13 @@ use model::{ChannelId, Message};
use std::collections::HashMap;
use std::sync::Arc;
use std::fmt::Write;
-use super::command::InternalCommand;
-use super::{Args, CommandGroup, CommandOrAlias, CommandOptions, CommandError};
+use super::command::{InternalCommand};
+use super::{Args, CommandGroup, CommandOrAlias, HelpOptions, CommandOptions, CommandError, HelpBehaviour};
use utils::Colour;
-fn error_embed(channel_id: &ChannelId, input: &str) {
+fn error_embed(channel_id: &ChannelId, input: &str, colour: Colour) {
let _ = channel_id.send_message(|m| {
- m.embed(|e| e.colour(Colour::dark_red()).description(input))
+ m.embed(|e| e.colour(colour).description(input))
});
}
@@ -92,6 +92,7 @@ pub fn has_all_requirements(cmd: &Arc<CommandOptions>, msg: &Message) -> bool {
/// ```
pub fn with_embeds(_: &mut Context,
msg: &Message,
+ help_options: &HelpOptions,
groups: HashMap<String, Arc<CommandGroup>>,
args: Args)
-> Result<(), CommandError> {
@@ -130,7 +131,7 @@ pub fn with_embeds(_: &mut Context,
},
CommandOrAlias::Alias(ref name) => {
- let _ = msg.channel_id.say(&format!("Did you mean {:?}?", name));
+ let _ = msg.channel_id.say(help_options.suggestion_text.replace("{}", name));
return Ok(());
},
}
@@ -142,50 +143,50 @@ pub fn with_embeds(_: &mut Context,
if let Some((command_name, command)) = found {
let command = command.options();
if !command.help_available {
- error_embed(&msg.channel_id, "**Error**: No help available.");
+ error_embed(&msg.channel_id, &help_options.no_help_available_text, help_options.embed_error_colour);
return Ok(());
}
let _ = msg.channel_id.send_message(|m| {
m.embed(|e| {
- let mut embed = e.colour(Colour::rosewater()).title(command_name);
+ let mut embed = e.colour(help_options.embed_success_colour.clone()).title(command_name.clone());
if let Some(ref desc) = command.desc {
embed = embed.description(desc);
}
if let Some(ref usage) = command.usage {
- let value = format!("`{} {}`", command_name, usage);
+ let value = format!("`{} {}`", command_name.clone(), usage);
- embed = embed.field("Usage", value, true);
+ embed = embed.field(&help_options.usage_label, value, true);
}
if let Some(ref example) = command.example {
- let value = format!("`{} {}`", command_name, example);
+ let value = format!("`{} {}`", command_name.clone(), example);
- embed = embed.field("Sample usage", value, true);
+ embed = embed.field(&help_options.usage_sample_label, value, true);
}
if group_name != "Ungrouped" {
- embed = embed.field("Group", group_name, true);
+ embed = embed.field(&help_options.grouped_label, group_name, true);
}
if !command.aliases.is_empty() {
let aliases = command.aliases.join(", ");
- embed = embed.field("Aliases", aliases, true);
+ embed = embed.field(&help_options.aliases_label, aliases, true);
}
let available = if command.dm_only {
- "Only in DM"
+ &help_options.dm_only_text
} else if command.guild_only {
- "Only in guilds"
+ &help_options.guild_only_text
} else {
- "In DM and guilds"
+ &help_options.dm_and_guild_text
};
- embed = embed.field("Available", available, true);
+ embed = embed.field(&help_options.available_text, available, true);
embed
})
@@ -195,18 +196,24 @@ pub fn with_embeds(_: &mut Context,
}
}
- let error_msg = format!("**Error**: Command `{}` not found.", name);
- error_embed(&msg.channel_id, &error_msg);
+ let error_msg = help_options.command_not_found_text.replace("{}", &name);
+ error_embed(&msg.channel_id, &error_msg, help_options.embed_error_colour);
return Ok(());
}
let _ = msg.channel_id.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.",
- );
+
+ if let Some(striked_command_text) = help_options.striked_commands_tip.clone() {
+ e = e.colour(help_options.embed_success_colour).description(
+ format!("{}\n{}", &help_options.individual_command_tip, &striked_command_text),
+ );
+ } else {
+ e = e.colour(help_options.embed_success_colour).description(
+ &help_options.individual_command_tip,
+ );
+ }
let mut group_names = groups.keys().collect::<Vec<_>>();
group_names.sort();
@@ -216,7 +223,7 @@ pub fn with_embeds(_: &mut Context,
let mut desc = String::new();
if let Some(ref x) = group.prefix {
- let _ = write!(desc, "Prefix: {}\n", x);
+ let _ = write!(desc, "{}: `{}`\n", &help_options.group_prefix, x);
}
let mut has_commands = false;
@@ -229,9 +236,41 @@ pub fn with_embeds(_: &mut Context,
let cmd = &commands[name];
let cmd = cmd.options();
- if cmd.help_available && has_all_requirements(&cmd, msg) {
- let _ = write!(desc, "`{}`\n", name);
- has_commands = true;
+ if !cmd.dm_only && !cmd.guild_only || cmd.dm_only && msg.is_private() || cmd.guild_only && !msg.is_private() {
+ if cmd.help_available && has_correct_permissions(&cmd, msg) {
+ let _ = write!(desc, "`{}`\n", name);
+ has_commands = true;
+ } else {
+ match help_options.lacking_permissions {
+ HelpBehaviour::Strike => {
+ let name = format!("~~`{}`~~", &name);
+ let _ = write!(desc, "{}\n", name);
+ has_commands = true;
+ },
+ HelpBehaviour::Nothing => {
+ let _ = write!(desc, "`{}`\n", name);
+ has_commands = true;
+ },
+ HelpBehaviour::Hide => {
+ continue;
+ },
+ }
+ }
+ } else {
+ match help_options.wrong_channel {
+ HelpBehaviour::Strike => {
+ let name = format!("~~`{}`~~", &name);
+ let _ = write!(desc, "{}\n", name);
+ has_commands = true;
+ },
+ HelpBehaviour::Nothing => {
+ let _ = write!(desc, "`{}`\n", name);
+ has_commands = true;
+ },
+ HelpBehaviour::Hide => {
+ continue;
+ },
+ }
}
}
@@ -266,6 +305,7 @@ pub fn with_embeds(_: &mut Context,
/// ```
pub fn plain(_: &mut Context,
msg: &Message,
+ help_options: &HelpOptions,
groups: HashMap<String, Arc<CommandGroup>>,
args: Args)
-> Result<(), CommandError> {
@@ -306,7 +346,7 @@ pub fn plain(_: &mut Context,
},
CommandOrAlias::Alias(ref name) => {
- let _ = msg.channel_id.say(&format!("Did you mean {:?}?", name));
+ let _ = msg.channel_id.say(help_options.suggestion_text.replace("{}", name));
return Ok(());
},
}
@@ -319,7 +359,7 @@ pub fn plain(_: &mut Context,
let command = command.options();
if !command.help_available {
- let _ = msg.channel_id.say("**Error**: No help available.");
+ let _ = msg.channel_id.say(&help_options.no_help_available_text);
return Ok(());
}
@@ -327,36 +367,36 @@ pub fn plain(_: &mut Context,
if !command.aliases.is_empty() {
let aliases = command.aliases.join("`, `");
- let _ = write!(result, "**Aliases:** `{}`\n", aliases);
+ let _ = write!(result, "**{}:** `{}`\n", help_options.aliases_label, aliases);
}
if let Some(ref desc) = command.desc {
- let _ = write!(result, "**Description:** {}\n", desc);
+ let _ = write!(result, "**{}:** {}\n", help_options.description_label, desc);
}
if let Some(ref usage) = command.usage {
- let _ = write!(result, "**Usage:** `{} {}`\n", command_name, usage);
+ let _ = write!(result, "**{}:** `{} {}`\n", help_options.usage_label, command_name, usage);
}
if let Some(ref example) = command.example {
- let _ = write!(result, "**Sample usage:** `{} {}`\n", command_name, example);
+ let _ = write!(result, "**{}:** `{} {}`\n", help_options.usage_sample_label, command_name, example);
}
if group_name != "Ungrouped" {
- let _ = write!(result, "**Group:** {}\n", group_name);
+ let _ = write!(result, "**{}:** {}\n", help_options.grouped_label, group_name);
}
let only = if command.dm_only {
- "Only in DM"
+ &help_options.dm_only_text
} else if command.guild_only {
- "Only in guilds"
+ &help_options.guild_only_text
} else {
- "In DM and guilds"
+ &help_options.dm_and_guild_text
};
- result.push_str("**Available:** ");
+ result.push_str(&format!("**{}:** ", &help_options.available_text));
result.push_str(only);
- result.push_str("\n");
+ result.push_str(".\n");
let _ = msg.channel_id.say(&result);
@@ -365,13 +405,12 @@ pub fn plain(_: &mut Context,
}
let _ = msg.channel_id
- .say(&format!("**Error**: Command `{}` not found.", name));
+ .say(&help_options.suggestion_text.replace("{}", &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"
+ let mut result = format!("**Commands**\n{}\n\n", help_options.individual_command_tip)
.to_string();
let mut group_names = groups.keys().collect::<Vec<_>>();
@@ -398,7 +437,7 @@ pub fn plain(_: &mut Context,
let _ = write!(result, "**{}:** ", group_name);
if let Some(ref x) = group.prefix {
- let _ = write!(result, "(prefix: `{}`): ", x);
+ let _ = write!(result, "({}: `{}`): ", help_options.group_prefix, x);
}
result.push_str(&group_help);
diff --git a/src/framework/standard/mod.rs b/src/framework/standard/mod.rs
index 95e0028..6f7e180 100644
--- a/src/framework/standard/mod.rs
+++ b/src/framework/standard/mod.rs
@@ -4,16 +4,18 @@ pub mod help_commands;
mod command;
mod configuration;
mod create_command;
+mod create_help_command;
mod create_group;
mod buckets;
mod args;
pub use self::args::{Args, Iter, FromStrZc, Error as ArgError};
pub(crate) use self::buckets::{Bucket, Ratelimit};
-pub(crate) use self::command::{Help, HelpFunction};
-pub use self::command::{Command, CommandGroup, CommandOptions, Error as CommandError};
+pub(crate) use self::command::{Help};
+pub use self::command::{HelpFunction, HelpOptions, Command, CommandGroup, CommandOptions, Error as CommandError};
pub use self::command::CommandOrAlias;
pub use self::configuration::Configuration;
+pub use self::create_help_command::CreateHelpCommand;
pub use self::create_command::{CreateCommand, FnOrCommand};
pub use self::create_group::CreateGroup;
@@ -653,7 +655,7 @@ impl StandardFramework {
group
.commands
.insert(name.to_string(), CommandOrAlias::Command(Arc::clone(&cmd)));
-
+
cmd.init();
}
}
@@ -703,7 +705,7 @@ impl StandardFramework {
group
.commands
.insert(name, CommandOrAlias::Command(Arc::clone(&cmd)));
-
+
cmd.init();
}
}
@@ -713,13 +715,6 @@ impl StandardFramework {
self
}
- /// Sets what code should be execute when a user requests for `(prefix)help`.
- pub fn help(mut self, f: HelpFunction) -> Self {
- self.help = Some(Arc::new(Help(f)));
-
- self
- }
-
/// Adds a group which can organize several related commands.
/// Groups are taken into account when using
/// `serenity::framework::standard::help_commands`.
@@ -881,6 +876,27 @@ impl StandardFramework {
self
}
+
+ /// Sets what code should be executed when a user sends `(prefix)help`.
+ pub fn help(mut self, f: HelpFunction) -> Self {
+ let a = CreateHelpCommand(HelpOptions::default(), f).finish();
+
+ self.help = Some(a);
+
+ self
+ }
+
+ /// Sets what code should be executed when sends `(prefix)help`.
+ /// Additionally takes a closure with a `CreateHelpCommand` in order
+ /// to alter help-commands.
+ pub fn customised_help<F>(mut self, f: HelpFunction, c: F) -> Self
+ where F: FnOnce(CreateHelpCommand) -> CreateHelpCommand {
+ let a = c(CreateHelpCommand(HelpOptions::default(), f));
+
+ self.help = Some(a.finish());
+
+ self
+ }
}
impl Framework for StandardFramework {
@@ -964,16 +980,19 @@ impl Framework for StandardFramework {
// This is a special case.
if to_check == "help" {
let help = self.help.clone();
+
if let Some(help) = help {
let groups = self.groups.clone();
threadpool.execute(move || {
+
if let Some(before) = before {
+
if !(before)(&mut context, &message, &built) {
return;
}
}
- let result = (help.0)(&mut context, &message, groups, args);
+ let result = (help.0)(&mut context, &message, &help.1, groups, args);
if let Some(after) = after {
(after)(&mut context, &message, &built, result);
@@ -1016,7 +1035,7 @@ impl Framework for StandardFramework {
let result = command.execute(&mut context, &message, args);
command.after(&mut context, &message, &result);
-
+
if let Some(after) = after {
(after)(&mut context, &message, &built, result);
}
@@ -1055,3 +1074,28 @@ pub fn has_correct_roles(cmd: &Arc<CommandOptions>, guild: &Guild, member: &Memb
.flat_map(|r| guild.role_by_name(r))
.any(|g| member.roles.contains(&g.id))
}
+
+/// Describes the behaviour the help-command shall execute once it encounters
+/// a command which the user or command fails to meet following criteria :
+/// Lacking required permissions to execute the command.
+/// Lacking required roles to execute the command.
+/// The command can't be used in the current channel (as in `DM only` or `guild only`).
+#[derive(PartialEq, Debug)]
+pub enum HelpBehaviour {
+ /// Strikes a command by applying `~~{comand_name}~~`.
+ Strike,
+ /// Does not list a command in the help-menu.
+ Hide,
+ /// The command will be displayed, hence nothing will be done.
+ Nothing
+}
+
+impl fmt::Display for HelpBehaviour {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ HelpBehaviour::Strike => write!(f, "HelpBehaviour::Strike"),
+ HelpBehaviour::Hide => write!(f, "HelpBehaviour::Hide"),
+ HelpBehaviour::Nothing => write!(f, "HelBehaviour::Nothing"),
+ }
+ }
+} \ No newline at end of file