|
| 1 | +from typing import Mapping, Optional, Union |
| 2 | + |
| 3 | +from nextcord import Embed, Message |
| 4 | +from nextcord.ext import commands |
| 5 | + |
| 6 | + |
| 7 | +class EmbeddedHelpCommand(commands.HelpCommand): |
| 8 | + """A help command implementation using embeds. |
| 9 | + This inherits from :class:`HelpCommand`. |
| 10 | + It extends it with the following attributes. |
| 11 | +
|
| 12 | + Attributes |
| 13 | + ------------ |
| 14 | + dm_help: :class:`bool` |
| 15 | + A bool that indicates if the output should only be sent via DM instead of the channel. |
| 16 | + Defaults to False. |
| 17 | + default_color: :class:`int` |
| 18 | + The default color of all embeds. |
| 19 | + Defaults to 0xFFFFFF (White). |
| 20 | + main_embed_title: :class:`str` |
| 21 | + The title for the embed which gets sent by invoking `help`. |
| 22 | + Defaults to "Overview about Cogs, Groups and Commands". |
| 23 | + main_embed_description: Optional[:class:`str`] |
| 24 | + The description for the embed which gets sent by invoking `help`. |
| 25 | + main_embed_color: Optional[:class:`int`] |
| 26 | + The color for the embed which gets sent by invoking `help`. |
| 27 | + Defaults to default_color. |
| 28 | + command_embed_title: :class:`str` |
| 29 | + The title for the embed which gets sent by `help <command>`. |
| 30 | + Defaults to "Command help". |
| 31 | + command_embed_description: :class:`str` |
| 32 | + The description for the embed which gets sent by invoking `help <command>`. |
| 33 | + Defaults to "If a parameter is surrounded by `<>`, it is a required parameter\\\\nIf a parameter is surrounded by `[]`, it is an optional parameter." |
| 34 | + command_embed_color: Optional[:class:`int`] |
| 35 | + The color for the embed which gets sent by invoking `help <command>`. |
| 36 | + Defaults to default_color. |
| 37 | + group_embed_title: :class:`str` |
| 38 | + The title for the embed which gets sent by invoking `help <group>`. |
| 39 | + Defaults to "Group help". |
| 40 | + group_embed_description: Optional[:class:`str`] |
| 41 | + The description for the embed which gets sent by invoking `help <group>`. |
| 42 | + group_embed_color: Optional[:class:`int`] |
| 43 | + The color for the embed which gets sent by invoking `help <group>`. |
| 44 | + Defaults to default_color. |
| 45 | + cog_embed_title: :class:`str` |
| 46 | + The title for the embed which gets sent by invoking `help <cog>`. |
| 47 | + Defaults to "Cog help". |
| 48 | + cog_embed_description: Optional[:class:`str`] |
| 49 | + The description for the embed which gets sent by invoking `help <cog>`. |
| 50 | + cog_embed_color: Optional[:class:`int`] |
| 51 | + The color for the embed which gets sent by invoking `help <cog>`. |
| 52 | + Defaults to default_color. |
| 53 | + """ |
| 54 | + |
| 55 | + def __init__( |
| 56 | + self, |
| 57 | + *, |
| 58 | + dm_help: bool = False, |
| 59 | + default_color: int = 0xFFFFFF, |
| 60 | + main_embed_title: str = "Overview about Cogs, Groups and Commands", |
| 61 | + main_embed_description: Optional[str] = None, |
| 62 | + main_embed_color: Optional[int] = None, |
| 63 | + command_embed_title: str = "Command help", |
| 64 | + command_embed_description: str = "If a parameter is surrounded by `<>`, it is a required parameter. \nIf a parameter is surrounded by `[]`, it is an optional parameter.", |
| 65 | + command_embed_color: Optional[int] = None, |
| 66 | + group_embed_title: str = "Group help", |
| 67 | + group_embed_description: Optional[str] = None, |
| 68 | + group_embed_color: Optional[int] = None, |
| 69 | + cog_embed_title: str = "Cog help", |
| 70 | + cog_embed_description: Optional[str] = None, |
| 71 | + cog_embed_color: Optional[int] = None, |
| 72 | + ): |
| 73 | + |
| 74 | + self.dm_help = dm_help |
| 75 | + self.default_color = default_color |
| 76 | + |
| 77 | + self.main_embed_title = main_embed_title |
| 78 | + self.main_embed_description = main_embed_description |
| 79 | + self.main_embed_color = main_embed_color or self.default_color |
| 80 | + |
| 81 | + self.command_embed_title = command_embed_title |
| 82 | + self.command_embed_description = command_embed_description |
| 83 | + self.command_embed_color = command_embed_color or self.default_color |
| 84 | + |
| 85 | + self.group_embed_title = group_embed_title |
| 86 | + self.group_embed_description = group_embed_description |
| 87 | + self.group_embed_color = group_embed_color or self.default_color |
| 88 | + |
| 89 | + self.cog_embed_title = cog_embed_title |
| 90 | + self.cog_embed_description = cog_embed_description |
| 91 | + self.cog_embed_color = cog_embed_color or self.default_color |
| 92 | + |
| 93 | + super().__init__() |
| 94 | + |
| 95 | + @staticmethod |
| 96 | + def determine_group_or_command(obj: Union[commands.Command, commands.Group]): |
| 97 | + return f"`{obj.name}[group]`" if isinstance(obj, commands.Group) else f"`{obj.name}`" |
| 98 | + |
| 99 | + async def send_embed(self, emb: Embed): |
| 100 | + if self.dm_help: |
| 101 | + return await self.context.author.send(embed=emb) |
| 102 | + return await self.context.send(embed=emb) |
| 103 | + |
| 104 | + # help |
| 105 | + async def send_bot_help(self, mapping: Mapping) -> Message: |
| 106 | + total_command_count = len(self.context.bot.commands) |
| 107 | + main_embed = Embed( |
| 108 | + title=self.main_embed_title, |
| 109 | + description=self.main_embed_description, |
| 110 | + color=self.main_embed_color, |
| 111 | + ) |
| 112 | + |
| 113 | + bare_cmd_list = " ".join( |
| 114 | + self.determine_group_or_command(bare_cmd) |
| 115 | + for bare_cmd in self.context.bot.commands |
| 116 | + if not bare_cmd.cog |
| 117 | + ) |
| 118 | + if bare_cmd_list: |
| 119 | + bare_cmd_count = len( |
| 120 | + [bare_cmd.name for bare_cmd in self.context.bot.commands if not bare_cmd.cog] |
| 121 | + ) |
| 122 | + main_embed.add_field(name=f"Bare [{bare_cmd_count}]", value=bare_cmd_list, inline=False) |
| 123 | + |
| 124 | + for cog in self.context.bot.cogs: |
| 125 | + cog = self.context.bot.get_cog(cog) |
| 126 | + cog_cmds = cog.get_commands() |
| 127 | + cog_cmd_list = " ".join(self.determine_group_or_command(cmd) for cmd in cog_cmds) |
| 128 | + if cog_cmd_list: |
| 129 | + main_embed.add_field( |
| 130 | + name=f"**{cog.qualified_name} Commands [{len(cog_cmds)}]:**", |
| 131 | + value=cog_cmd_list, |
| 132 | + inline=False, |
| 133 | + ) |
| 134 | + main_embed.set_footer(text=f"{total_command_count} Commands") |
| 135 | + return await self.send_embed(main_embed) |
| 136 | + |
| 137 | + # help <command> |
| 138 | + async def send_command_help(self, command: commands.Command) -> Message: |
| 139 | + syntax = f"{self.context.clean_prefix}{command.qualified_name} {command.signature}" |
| 140 | + command_embed = Embed( |
| 141 | + title=self.command_embed_title, |
| 142 | + description=self.command_embed_description, |
| 143 | + color=self.command_embed_color, |
| 144 | + ) |
| 145 | + command_embed.add_field( |
| 146 | + name=syntax, |
| 147 | + value=f"`{command.help or command.brief or 'No description provided.'}`", |
| 148 | + inline=False, |
| 149 | + ) |
| 150 | + |
| 151 | + return await self.send_embed(command_embed) |
| 152 | + |
| 153 | + # help <group> |
| 154 | + async def send_group_help(self, group: commands.Group) -> Message: |
| 155 | + group_embed = Embed( |
| 156 | + title=self.group_embed_title, |
| 157 | + description=self.group_embed_description, |
| 158 | + color=self.group_embed_color, |
| 159 | + ) |
| 160 | + |
| 161 | + for sub_command in group.walk_commands(): |
| 162 | + syntax = f"{self.context.clean_prefix}{group.qualified_name} {sub_command.name} {sub_command.signature}" |
| 163 | + group_embed.add_field( |
| 164 | + name=syntax, |
| 165 | + value=f"`{sub_command.help or sub_command.brief or 'No description provided.'}`", |
| 166 | + inline=False, |
| 167 | + ) |
| 168 | + group_embed.set_footer(text=f"{len(group.commands)} subcommands") |
| 169 | + return await self.send_embed(group_embed) |
| 170 | + |
| 171 | + # help <cog> |
| 172 | + async def send_cog_help(self, cog: commands.Cog) -> Message: |
| 173 | + cog_embed = Embed( |
| 174 | + title=self.cog_embed_title, |
| 175 | + description=self.cog_embed_description, |
| 176 | + color=self.cog_embed_color, |
| 177 | + ) |
| 178 | + |
| 179 | + cog_cmds = cog.get_commands() |
| 180 | + for command in cog.walk_commands(): |
| 181 | + if not command.parent: |
| 182 | + syntax = f"{self.context.clean_prefix}{command.qualified_name} {command.signature}" |
| 183 | + cog_embed.add_field( |
| 184 | + name=syntax, |
| 185 | + value=f"`{command.help or command.brief or 'No description provided.'}`", |
| 186 | + inline=False, |
| 187 | + ) |
| 188 | + |
| 189 | + cog_embed.set_footer(text=f"{len(cog_cmds)} commands") |
| 190 | + return await self.send_embed(cog_embed) |
0 commit comments