Create help command implementation

pull/132/head
stijndcl 2022-09-19 01:28:18 +02:00
parent bf28611ddc
commit c5317b5d27
3 changed files with 139 additions and 22 deletions

View File

@ -25,7 +25,7 @@ class Currency(commands.Cog):
super().__init__()
self.client = client
@commands.command(name="Award")
@commands.command(name="award")
@commands.check(is_owner)
async def award(
self,
@ -38,11 +38,11 @@ class Currency(commands.Cog):
await crud.add_dinks(session, user.id, amount)
plural = pluralize("Didier Dink", amount)
await ctx.reply(
f"**{ctx.author.display_name}** heeft **{user.display_name}** **{amount}** {plural} geschonken.",
f"**{ctx.author.display_name}** has awarded **{user.display_name}** **{amount}** {plural}.",
mention_author=False,
)
@commands.group(name="bank", aliases=["B"], case_insensitive=True, invoke_without_command=True)
@commands.group(name="bank", aliases=["b"], case_insensitive=True, invoke_without_command=True)
async def bank(self, ctx: commands.Context):
"""Show your Didier Bank information"""
async with self.client.postgres_session as session:
@ -57,7 +57,7 @@ class Currency(commands.Cog):
await ctx.reply(embed=embed, mention_author=False)
@bank.group(name="Upgrade", aliases=["U", "Upgrades"], case_insensitive=True, invoke_without_command=True)
@bank.group(name="upgrade", aliases=["u", "upgrades"], case_insensitive=True, invoke_without_command=True)
async def bank_upgrades(self, ctx: commands.Context):
"""List the upgrades you can buy & their prices"""
async with self.client.postgres_session as session:
@ -77,7 +77,7 @@ class Currency(commands.Cog):
await ctx.reply(embed=embed, mention_author=False)
@bank_upgrades.command(name="Capacity", aliases=["C"])
@bank_upgrades.command(name="capacity", aliases=["c"])
async def bank_upgrade_capacity(self, ctx: commands.Context):
"""Upgrade the capacity level of your bank"""
async with self.client.postgres_session as session:
@ -88,7 +88,7 @@ class Currency(commands.Cog):
await ctx.reply("You don't have enough Didier Dinks to do this.", mention_author=False)
await self.client.reject_message(ctx.message)
@bank_upgrades.command(name="Interest", aliases=["I"])
@bank_upgrades.command(name="interest", aliases=["i"])
async def bank_upgrade_interest(self, ctx: commands.Context):
"""Upgrade the interest level of your bank"""
async with self.client.postgres_session as session:
@ -99,7 +99,7 @@ class Currency(commands.Cog):
await ctx.reply("You don't have enough Didier Dinks to do this.", mention_author=False)
await self.client.reject_message(ctx.message)
@bank_upgrades.command(name="Rob", aliases=["R"])
@bank_upgrades.command(name="rob", aliases=["r"])
async def bank_upgrade_rob(self, ctx: commands.Context):
"""Upgrade the rob level of your bank"""
async with self.client.postgres_session as session:
@ -118,7 +118,7 @@ class Currency(commands.Cog):
plural = pluralize("Didier Dink", bank.dinks)
await ctx.reply(f"**{ctx.author.display_name}** has **{bank.dinks}** {plural}.", mention_author=False)
@commands.command(name="Invest", aliases=["Deposit", "Dep"])
@commands.command(name="invest", aliases=["deposit", "dep"])
async def invest(self, ctx: commands.Context, amount: typing.Annotated[typing.Union[str, int], abbreviated_number]):
"""Invest a given amount of Didier Dinks"""
async with self.client.postgres_session as session:

View File

@ -1,10 +1,11 @@
from typing import List, Mapping, Optional
from typing import Mapping, Optional
import discord
from discord.ext import commands
from overrides import overrides
from didier import Didier
from didier.utils.discord.colours import error_red
class CustomHelpCommand(commands.MinimalHelpCommand):
@ -13,32 +14,146 @@ class CustomHelpCommand(commands.MinimalHelpCommand):
The default is ugly as hell, so we do some fiddling with it
"""
@overrides
async def command_callback(self, ctx: commands.Context, /, *, command: Optional[str] = None):
"""Slightly modify the original command_callback to better suit my needs"""
# No argument provided: send a list of all cogs
if command is None:
mapping = self.get_bot_mapping()
return await self.send_bot_help(mapping)
command = command.lower()
# Hide cogs the user is not allowed to see
cogs = list(ctx.bot.cogs.values())
cogs = await self._filter_cogs(cogs)
# Allow fetching cogs case-insensitively
cog = self._get_cog(cogs, command)
if cog is not None:
return await self.send_cog_help(cog)
# Traverse tree of commands
keys = command.split(" ")
current_command = ctx.bot.all_commands.get(keys[0])
# No command found
if current_command is None:
return await self.send_error_message(self.command_not_found(keys[0]))
# Look for subcommands
for key in keys[1:]:
try:
found = current_command.all_commands.get(key) # type: ignore
except AttributeError:
return await self.send_error_message(self.subcommand_not_found(current_command, key))
else:
if found is None:
return await self.send_error_message(self.subcommand_not_found(current_command, key))
current_command = found
if isinstance(current_command, commands.Group):
return await self.send_group_help(current_command)
else:
return await self.send_command_help(current_command)
@overrides
def command_not_found(self, string: str, /) -> str:
return f"Found no command named `{string}`."
@overrides
async def send_bot_help(self, mapping: Mapping[Optional[commands.Cog], list[commands.Command]], /):
embed = self._help_embed_base("Categories")
filtered_cogs = await self._filter_cogs(list(mapping.keys()))
embed.description = "\n".join(list(map(lambda cog: cog.qualified_name, filtered_cogs)))
await self.context.reply(embed=embed, mention_author=False)
@overrides
async def send_cog_help(self, cog: commands.Cog, /):
embed = self._help_embed_base(cog.qualified_name)
embed.description = cog.description
commands_names = list(map(lambda c: c.qualified_name, cog.get_commands()))
commands_names.sort()
embed.add_field(name="Commands", value=", ".join(commands_names), inline=False)
return await self.context.reply(embed=embed, mention_author=False)
@overrides
async def send_command_help(self, command: commands.Command, /):
embed = self._help_embed_base(command.qualified_name)
self._add_command_help(embed, command)
return await self.context.reply(embed=embed, mention_author=False)
@overrides
async def send_group_help(self, group: commands.Group, /):
embed = self._help_embed_base(group.qualified_name)
if group.invoke_without_command:
self._add_command_help(embed, group)
subcommand_names = list(map(lambda c: c.name, group.commands))
subcommand_names.sort()
embed.add_field(name="Subcommands", value=", ".join(subcommand_names))
return await self.context.reply(embed=embed, mention_author=False)
@overrides
async def send_error_message(self, error: str, /):
embed = discord.Embed(colour=error_red(), title="Help", description=error)
return await self.context.reply(embed=embed, mention_author=False)
@overrides
def subcommand_not_found(self, command: commands.Command, string: str, /) -> str:
return f"Found no subcommand named `{string}` for command `{command.qualified_name}`."
def _help_embed_base(self, title: str) -> discord.Embed:
"""Create the base structure for the embeds that get sent with the Help commands"""
embed = discord.Embed(title=title, colour=discord.Colour.blue())
embed.set_footer(text="Syntax: Didier Help [Categorie] of Didier Help [Commando]")
embed = discord.Embed(title=title.title(), colour=discord.Colour.blue())
return embed
async def _filter_cogs(self, cogs: List[commands.Cog]) -> List[commands.Cog]:
def _add_command_help(self, embed: discord.Embed, command: commands.Command):
"""Add command-related information to an embed
This allows re-using this logic for Group commands that can be invoked by themselves.
"""
embed.description = command.help
if command.usage:
embed.add_field(name="Signature", value=f"{command.name} {command.usage}", inline=False)
if command.aliases:
embed.add_field(name="Aliases", value=", ".join(command.aliases), inline=False)
def _get_cog(self, cogs: list[commands.Cog], name: str) -> Optional[commands.Cog]:
"""Try to find a cog, case-insensitively"""
for cog in cogs:
if cog.qualified_name.lower() == name:
return cog
return None
async def _filter_cogs(self, cogs: list[commands.Cog]) -> list[commands.Cog]:
"""Filter the list of cogs down to all those that the user can see"""
# Remove cogs that we never want to see in the help page because they
# don't contain commands
filtered_cogs = list(filter(lambda cog: cog is not None and cog.qualified_name.lower() not in ("tasks",), cogs))
filtered_cogs = list(
filter(lambda cog: cog is not None and cog.qualified_name.lower() not in ("tasks", "debugcog"), cogs)
)
# Remove owner-only cogs
# Remove owner-only cogs for people that shouldn't see them
if not await self.context.bot.is_owner(self.context.author):
filtered_cogs = list(filter(lambda cog: cog.qualified_name.lower() not in ("owner",), filtered_cogs))
return list(sorted(filtered_cogs, key=lambda cog: cog.qualified_name))
@overrides
async def send_bot_help(self, mapping: Mapping[Optional[commands.Cog], List[commands.Command]], /):
embed = self._help_embed_base("Categorieën")
filtered_cogs = await self._filter_cogs(list(mapping.keys()))
embed.description = "\n".join(list(map(lambda cog: cog.qualified_name, filtered_cogs)))
await self.get_destination().send(embed=embed)
async def setup(client: Didier):
"""Load the cog"""
client.help_command = CustomHelpCommand()
attributes = {"aliases": ["h", "man"]}
client.help_command = CustomHelpCommand(command_attrs=attributes)

View File

@ -190,8 +190,10 @@ class Tasks(commands.Cog):
await self.client.wait_until_ready()
@check_birthdays.error
@pull_schedules.error
@pull_ufora_announcements.error
@remove_old_ufora_announcements.error
@reset_wordle_word.error
async def _on_tasks_error(self, error: BaseException):
"""Error handler for all tasks"""
print("".join(traceback.format_exception(type(error), error, error.__traceback__)))