Skip to content

Commit cef255f

Browse files
committed
fix(help): Check for unset commands, autogen help message
1 parent 162639f commit cef255f

File tree

5 files changed

+103
-40
lines changed

5 files changed

+103
-40
lines changed

src/modules/etc.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@ export class EtcModule extends Module {
2121
await msg.channel.send('pong. :ping_pong:');
2222
}
2323

24-
@command({ description: 'Sends a link to <https://dontasktoask.com>' })
24+
@command({
25+
description:
26+
'Sends a link to [dontasktoask.com](https://dontasktoask.com)',
27+
})
2528
async ask(msg: Message) {
2629
await msg.channel.send('https://dontasktoask.com/');
2730
}
2831

2932
@command({
3033
description:
31-
'Sends a link to <https://github.com/facebook/create-react-app/pull/8177#issue-353062710>',
34+
'Sends a link to [a pull request removing React.FC](https://github.com/facebook/create-react-app/pull/8177#issue-353062710)',
3235
})
3336
async reactfc(msg: Message) {
3437
await msg.channel.send(

src/modules/help.ts

+77-27
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,47 @@ import {
44
Module,
55
CommonInhibitors,
66
optional,
7+
Command,
78
} from 'cookiecord';
89
import { Message, MessageEmbed } from 'discord.js';
10+
import { sendWithMessageOwnership } from '../util/send';
11+
12+
function getCategoryHelp(cat: string, commands: Set<Command>) {
13+
const out: string[] = [];
14+
15+
for (const cmd of commands) {
16+
if (
17+
cmd.description &&
18+
splitCategoryDescription(cmd.description)[0] === cat
19+
) {
20+
out.push(
21+
`\`${cmd.triggers[0]}\` ► ${cmd.description.substr(
22+
cat.length + 2,
23+
)}`,
24+
);
25+
}
26+
}
27+
28+
return out.join('\n');
29+
}
30+
31+
function splitCategoryDescription(description: string): [string, string] {
32+
const split = description.split(': ', 2);
33+
if (split.length !== 2) {
34+
return ['Misc', description];
35+
}
36+
return split as [string, string];
37+
}
38+
39+
function getCommandCategories(commands: Set<Command>) {
40+
const categories = new Set<string>();
41+
42+
for (const cmd of commands) {
43+
categories.add(splitCategoryDescription(cmd.description ?? '')[0]);
44+
}
45+
46+
return [...categories].sort((a, b) => a.localeCompare(b));
47+
}
948

1049
export class HelpModule extends Module {
1150
constructor(client: CookiecordClient) {
@@ -21,47 +60,58 @@ export class HelpModule extends Module {
2160
if (!msg.guild) return;
2261

2362
if (!cmdTrigger) {
24-
let embed = new MessageEmbed()
63+
const embed = new MessageEmbed()
2564
.setAuthor(
2665
msg.guild.name,
2766
msg.guild.iconURL({ dynamic: true }) || undefined,
2867
)
2968
.setTitle('Bot Usage')
3069
.setDescription(
3170
`Hello ${msg.author.username}! Here is a list of all commands in me! To get detailed description on any specific command, do \`help <command>\``,
32-
)
33-
.addField(
34-
`**Misc Commands:**`,
35-
`\`help\` ► View a list of all commands!\n\`ping\` ► View the latency of the bot\n\`ask\` ► Sends a message with a link for [dontasktoask.com](https://dontasktoask.com)\n\`reactfc\` ► Sends a message with a link to a [pull request removing React.FC](https://github.com/facebook/create-react-app/pull/8177#issue-353062710)\n\`playground\` ► Just enter your code and get a link with TS playground!`,
36-
)
37-
.addField(
38-
`**Help Channel Commands:**`,
39-
`\`done\` ► Close a __ongoing__ help channel opened by you!`,
40-
)
41-
.addField(
42-
`**Reputation Commands**`,
43-
`\`rep\` ► Did somebody help you? Give them a reputation point!\n\`history\` ► Check the reputation history of a user!\n\`leaderboard\` ► See the reputation leaderboard!`,
44-
)
71+
);
72+
73+
for (const cat of getCommandCategories(
74+
this.client.commandManager.cmds,
75+
)) {
76+
embed.addField(
77+
`**${cat} Commands:**`,
78+
getCategoryHelp(cat, this.client.commandManager.cmds),
79+
);
80+
}
81+
82+
embed
4583
.setFooter(
4684
this.client.user?.username,
4785
this.client.user?.displayAvatarURL(),
4886
)
4987
.setTimestamp();
5088

51-
return await msg.channel.send(embed);
52-
} else {
53-
const cmd = this.client.commandManager.getByTrigger(cmdTrigger);
54-
await msg.channel.send(
55-
`Usage: \`${cmd?.triggers.join('|')}${
56-
cmd?.args.length ? ' ' : ''
57-
}${cmd?.args.map(arg =>
58-
arg.optional ? `[${arg.type.name}]` : `<${arg.type.name}>`,
59-
)}\`${
60-
cmd?.description
61-
? `\nDescription: *${cmd?.description}*`
62-
: ''
63-
}`,
89+
return await sendWithMessageOwnership(msg, { embed });
90+
}
91+
92+
const cmd = this.client.commandManager.getByTrigger(cmdTrigger);
93+
if (!cmd || !cmd.description) {
94+
await sendWithMessageOwnership(
95+
msg,
96+
`:x: Command "${cmdTrigger}" not found`,
97+
);
98+
return;
99+
}
100+
101+
const embed = new MessageEmbed().setTitle(`\`${cmdTrigger}\` Usage`);
102+
// Get rid of duplicates, this can happen if someone adds the method name as an alias
103+
const triggers = new Set(cmd.triggers);
104+
if (triggers.size > 1) {
105+
embed.addField(
106+
'Aliases',
107+
Array.from(triggers, t => `\`${t}\``).join(', '),
64108
);
65109
}
110+
embed.addField(
111+
'Description',
112+
`*${splitCategoryDescription(cmd.description ?? '')[1]}*`,
113+
);
114+
115+
await sendWithMessageOwnership(msg, { embed });
66116
}
67117
}

src/modules/helpchan.ts

+11-4
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,8 @@ export class HelpChanModule extends Module {
199199
}
200200

201201
@command({
202-
aliases: ['resolve', 'done', 'close'],
203-
description: 'Marks this channel as resolved',
202+
aliases: ['close', 'resolve', 'done'],
203+
description: 'Help Channel: Marks this channel as resolved',
204204
})
205205
async resolved(msg: Message) {
206206
if (
@@ -329,7 +329,11 @@ export class HelpChanModule extends Module {
329329
await helpUser.save();
330330
}
331331

332-
@command({ inhibitors: [CommonInhibitors.guildsOnly] })
332+
@command({
333+
inhibitors: [CommonInhibitors.guildsOnly],
334+
aliases: ['claimed'],
335+
description: 'Help Channel: Check if a user has an open help channel',
336+
})
333337
async cooldown(msg: Message, @optional member?: GuildMember) {
334338
const guildTarget = await msg.guild!.members.fetch(
335339
member ?? msg.author,
@@ -360,7 +364,10 @@ export class HelpChanModule extends Module {
360364
);
361365
}
362366

363-
@command({ inhibitors: [isTrustedMember] })
367+
@command({
368+
inhibitors: [isTrustedMember],
369+
description: "Help Channel: Claim a help channel for a user's question",
370+
})
364371
async claim(msg: Message, member: GuildMember) {
365372
const helpUser = await HelpUser.findOne({
366373
userId: member.id,

src/modules/rep.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ export class RepModule extends Module {
7575
}
7676

7777
@command({
78-
description: 'See how many reputation points you have left to send',
78+
description:
79+
'Reputation: See how many reputation points you have left to send',
7980
})
8081
async remaining(msg: Message) {
8182
const USED = '✅';
@@ -91,7 +92,9 @@ export class RepModule extends Module {
9192
);
9293
}
9394

94-
@command({ description: 'Give a different user some reputation points' })
95+
@command({
96+
description: 'Reputation: Give a different user some reputation points',
97+
})
9598
async rep(msg: Message, targetMember: GuildMember) {
9699
if (targetMember.id === msg.member?.id)
97100
return msg.channel.send(`:x: you cannot send rep to yourself`);
@@ -118,7 +121,7 @@ export class RepModule extends Module {
118121

119122
@command({
120123
aliases: ['history'],
121-
description: "View a user's reputation history",
124+
description: "Reputation: View a user's reputation history",
122125
})
123126
async getrep(msg: Message, @optional user?: User) {
124127
if (!user) user = msg.author;
@@ -153,8 +156,8 @@ export class RepModule extends Module {
153156
}
154157

155158
@command({
156-
aliases: ['lb'],
157-
description: 'See who has the most reputation',
159+
aliases: ['leaderboard', 'lb'],
160+
description: 'Reputation: See who has the most reputation',
158161
})
159162
async leaderboard(msg: Message) {
160163
const topEmojis = [':first_place:', ':second_place:', ':third_place:'];

src/modules/twoslash.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export class TwoslashModule extends Module {
2323
@command({
2424
single: true,
2525
description:
26-
'Search for a symbol and get the type of it in the latest codeblock',
26+
'Twoslash: Search for a symbol and get the type of it in the latest codeblock',
2727
})
2828
async ts(msg: Message, content: string) {
2929
const match = /^[_$a-zA-Z][_$0-9a-zA-Z]*/.exec(content);
@@ -66,7 +66,7 @@ export class TwoslashModule extends Module {
6666

6767
@command({
6868
description:
69-
'Run twoslash on the latest codeblock, returning compiler errors and queries',
69+
'Twoslash: Run twoslash on the latest codeblock, returning compiler errors and queries',
7070
})
7171
async twoslash(msg: Message) {
7272
const code = await findCodeFromChannel(msg.channel as TextChannel);

0 commit comments

Comments
 (0)