Skip to content

Commit a315045

Browse files
committed
refactor(commands): add 'command' argument to help command
1 parent c8ca64e commit a315045

6 files changed

Lines changed: 177 additions & 46 deletions

File tree

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use crate::commands::CommandRegistry;
2+
use crate::config::Config;
3+
use crate::errors::{CommandError, ModmailError, ModmailResult};
4+
use crate::i18n::get_translated_message;
5+
use crate::utils::message::message_builder::MessageBuilder;
6+
use serenity::all::{CommandInteraction, Context, Message};
7+
use std::sync::Arc;
8+
9+
pub async fn display_commands_list(
10+
ctx: &Context,
11+
config: &Config,
12+
registry: Arc<CommandRegistry>,
13+
msg: Option<&Message>,
14+
command: Option<&CommandInteraction>,
15+
) -> ModmailResult<()> {
16+
let mut docs_message = String::new();
17+
18+
let welcome_msg = get_translated_message(&config, "help.message", None, None, None, None).await;
19+
docs_message.push_str(&welcome_msg);
20+
21+
for (name, _) in &registry.commands {
22+
docs_message.push_str(&format!("- **{}**\n", name))
23+
}
24+
25+
if let Some(msg) = msg {
26+
let _ = MessageBuilder::system_message(&ctx, config)
27+
.content(docs_message)
28+
.to_channel(msg.channel_id)
29+
.send(true)
30+
.await;
31+
32+
return Ok(());
33+
}
34+
35+
if let Some(command) = command {
36+
let response = MessageBuilder::system_message(&ctx, config)
37+
.content(docs_message)
38+
.to_channel(command.channel_id)
39+
.build_interaction_message_followup()
40+
.await;
41+
42+
command.create_followup(&ctx.http, response).await?;
43+
44+
return Ok(());
45+
}
46+
47+
println!("No valid message or command interaction provided.");
48+
Ok(())
49+
}
50+
51+
pub async fn display_command_help(
52+
ctx: &Context,
53+
config: &Config,
54+
registry: Arc<CommandRegistry>,
55+
msg: Option<&Message>,
56+
command: Option<&CommandInteraction>,
57+
command_name: &str,
58+
) -> ModmailResult<()> {
59+
if let Some(cmd) = registry.commands.get(command_name) {
60+
let command_doc = cmd.doc(config).await;
61+
let mut docs_message = String::new();
62+
docs_message.push_str(&format!("**{}**\n\n", command_name));
63+
docs_message.push_str(&command_doc);
64+
65+
if let Some(msg) = msg {
66+
let _ = MessageBuilder::system_message(&ctx, config)
67+
.content(docs_message)
68+
.to_channel(msg.channel_id)
69+
.send(true)
70+
.await;
71+
72+
return Ok(());
73+
}
74+
75+
if let Some(command) = command {
76+
let response = MessageBuilder::system_message(&ctx, config)
77+
.content(docs_message)
78+
.to_channel(command.channel_id)
79+
.build_interaction_message_followup()
80+
.await;
81+
82+
command.create_followup(&ctx.http, response).await?;
83+
return Ok(());
84+
}
85+
86+
println!("No valid message or command interaction provided.");
87+
Ok(())
88+
} else {
89+
Err(ModmailError::Command(CommandError::UnknownCommand(
90+
format!("{}", command_name),
91+
)))
92+
}
93+
}

rustmail/src/commands/help/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
pub mod common;
12
pub mod slash_command;
23
pub mod text_command;

rustmail/src/commands/help/slash_command/help.rs

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1+
use crate::commands::help::common::{display_command_help, display_commands_list};
12
use crate::commands::{BoxFuture, RegistrableCommand};
23
use crate::config::Config;
34
use crate::errors::ModmailResult;
45
use crate::handlers::guild_interaction_handler::InteractionHandler;
56
use crate::i18n::get_translated_message;
67
use crate::utils::command::defer_response::defer_response;
7-
use crate::utils::message::message_builder::MessageBuilder;
8+
use serenity::all::{
9+
CommandDataOptionValue, CommandInteraction, CommandOptionType, Context, CreateCommand,
10+
CreateCommandOption, ResolvedOption,
11+
};
812
use serenity::FutureExt;
9-
use serenity::all::{CommandInteraction, Context, CreateCommand, ResolvedOption};
10-
use serenity::futures::future::join_all;
11-
use std::collections::HashMap;
12-
use std::error::Error;
1313
use std::sync::Arc;
1414

1515
pub struct HelpCommand;
@@ -38,8 +38,22 @@ impl RegistrableCommand for HelpCommand {
3838
None,
3939
)
4040
.await;
41+
let cmd_arg_desc = get_translated_message(
42+
&config,
43+
"slash_command.help_command_argument_desc",
44+
None,
45+
None,
46+
None,
47+
None,
48+
)
49+
.await;
4150

42-
vec![CreateCommand::new("help").description(cmd_desc)]
51+
vec![
52+
CreateCommand::new("help").description(cmd_desc).add_option(
53+
CreateCommandOption::new(CommandOptionType::String, "command", cmd_arg_desc)
54+
.required(false),
55+
),
56+
]
4357
})
4458
}
4559

@@ -56,33 +70,41 @@ impl RegistrableCommand for HelpCommand {
5670
let config = config.clone();
5771

5872
Box::pin(async move {
59-
let mut docs_message = String::new();
60-
61-
let welcome_msg =
62-
get_translated_message(&config, "help.message", None, None, None, None).await;
63-
docs_message.push_str(&welcome_msg);
64-
65-
let futures = handler.registry.commands.iter().map(|(name, command)| {
66-
let config = config.clone();
67-
68-
async move {
69-
let doc = command.doc(&config).await;
70-
format!("**{}** — {}\n\n", name, doc)
71-
}
72-
});
73-
74-
let results = join_all(futures).await;
75-
docs_message.push_str(&results.join(""));
76-
7773
defer_response(&ctx, &command).await?;
7874

79-
let response = MessageBuilder::system_message(&ctx, &config)
80-
.content(docs_message)
81-
.to_channel(command.channel_id)
82-
.build_interaction_message_followup()
83-
.await;
75+
let mut command_name: Option<String> = None;
8476

85-
let _ = command.create_followup(&ctx.http, response).await;
77+
for option in &command.data.options {
78+
match option.name.as_str() {
79+
"command" => {
80+
if let CommandDataOptionValue::String(val) = &option.value {
81+
command_name.replace(val.clone());
82+
}
83+
}
84+
_ => {}
85+
}
86+
}
87+
88+
if let Some(cmd_name) = command_name {
89+
display_command_help(
90+
&ctx,
91+
&config,
92+
handler.registry.clone(),
93+
None,
94+
Some(&command),
95+
&cmd_name,
96+
)
97+
.await?;
98+
} else {
99+
display_commands_list(
100+
&ctx,
101+
&config,
102+
handler.registry.clone(),
103+
None,
104+
Some(&command),
105+
)
106+
.await?;
107+
}
86108

87109
Ok(())
88110
})
Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,36 @@
1+
use crate::commands::help::common::{display_command_help, display_commands_list};
12
use crate::config::Config;
23
use crate::errors::ModmailResult;
34
use crate::handlers::guild_messages_handler::GuildMessagesHandler;
4-
use crate::utils::message::message_builder::MessageBuilder;
55
use serenity::all::{Context, Message};
66
use std::sync::Arc;
77

8+
fn extract_request_command_name(command: &str) -> &str {
9+
let parts: Vec<&str> = command.trim().split_whitespace().collect();
10+
if parts.len() > 1 { parts[1] } else { "" }
11+
}
12+
813
pub async fn help(
914
ctx: Context,
1015
msg: Message,
1116
config: &Config,
1217
handler: Arc<GuildMessagesHandler>,
1318
) -> ModmailResult<()> {
14-
let mut docs_message = String::new();
15-
16-
for (name, command) in &handler.registry.commands {
17-
let doc = command.doc(&config).await;
19+
let command_name = extract_request_command_name(&msg.content);
1820

19-
docs_message.push_str(&format!("**{}** — {}\n\n", name, doc))
20-
}
21-
22-
MessageBuilder::system_message(&ctx, config)
23-
.content(docs_message)
24-
.to_channel(msg.channel_id)
25-
.send(true)
21+
if command_name.is_empty() {
22+
display_commands_list(&ctx, config, handler.registry.clone(), Some(&msg), None).await?;
23+
} else {
24+
display_command_help(
25+
&ctx,
26+
config,
27+
handler.registry.clone(),
28+
Some(&msg),
29+
None,
30+
command_name,
31+
)
2632
.await?;
33+
}
2734

2835
Ok(())
2936
}

rustmail/src/i18n/language/en.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,7 @@ pub fn load_english_messages(dict: &mut ErrorDictionary) {
835835
);
836836
dict.messages.insert(
837837
"help.help".to_string(),
838-
DictionaryMessage::new("Displays a list of all available commands with a short description. To view the help message, use `!help`."),
838+
DictionaryMessage::new("Displays a list of all available commands with a short description. To view the help message, use `!help`. If you want help with a specific command, type `!help <command_name>`."),
839839
);
840840
dict.messages.insert(
841841
"help.id".to_string(),
@@ -871,7 +871,7 @@ pub fn load_english_messages(dict: &mut ErrorDictionary) {
871871
);
872872
dict.messages.insert(
873873
"help.message".to_string(),
874-
DictionaryMessage::new("## Commands:\n\n**All commands** are also available as **__slash commands__** with the **__same name__**.\n\n"),
874+
DictionaryMessage::new("## Commands:\n\n**All commands** are also available as **__slash commands__** with the **__same name__**.\n\nIf you want help with a specific command, type `!help <command_name>`.\n\n"),
875875
);
876876
dict.messages.insert(
877877
"help.take".to_string(),
@@ -922,4 +922,8 @@ pub fn load_english_messages(dict: &mut ErrorDictionary) {
922922
"release.confirmation".to_string(),
923923
DictionaryMessage::new("The ticket has been released by {staff}."),
924924
);
925+
dict.messages.insert(
926+
"slash_command.help_command_argument_desc".to_string(),
927+
DictionaryMessage::new("The command to get help with"),
928+
);
925929
}

rustmail/src/i18n/language/fr.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -859,7 +859,7 @@ pub fn load_french_messages(dict: &mut ErrorDictionary) {
859859
);
860860
dict.messages.insert(
861861
"help.help".to_string(),
862-
DictionaryMessage::new("Affiche une liste de toutes les commandes disponibles avec une brève description. Pour afficher le message d'aide, faites `!help`."),
862+
DictionaryMessage::new("Affiche une liste de toutes les commandes disponibles avec une brève description. Pour afficher le message d'aide, faites `!help`. Si vous souhaitez obtenir de l'aide sur une commande spécifique, faites `!help <nom_de_la_commande>`."),
863863
);
864864
dict.messages.insert(
865865
"help.id".to_string(),
@@ -895,7 +895,7 @@ pub fn load_french_messages(dict: &mut ErrorDictionary) {
895895
);
896896
dict.messages.insert(
897897
"help.message".to_string(),
898-
DictionaryMessage::new("## Commandes :\n\n**Toutes les commandes** disponibles sont également utilisables via des **__commandes slash__** portant le __même nom__.\n\n"),
898+
DictionaryMessage::new("## Commandes :\n\n**Toutes les commandes** disponibles sont également utilisables via des **__commandes slash__** portant le __même nom__.\n\nSi vous souhaitez obtenir de l'aide sur une commande spécifique, faites `!help <nom_de_la_commande>`.\n\n")
899899
);
900900
dict.messages.insert(
901901
"help.take".to_string(),
@@ -937,4 +937,8 @@ pub fn load_french_messages(dict: &mut ErrorDictionary) {
937937
"release.confirmation".to_string(),
938938
DictionaryMessage::new("Le ticket n'est plus pris en charge par {staff}."),
939939
);
940+
dict.messages.insert(
941+
"slash_command.help_command_argument_desc".to_string(),
942+
DictionaryMessage::new("Le nom de la commande pour laquelle vous souhaitez de l'aide"),
943+
);
940944
}

0 commit comments

Comments
 (0)