async def format_cog_help(self, ctx: Context, obj: commands.Cog, help_settings: HelpSettings): coms = await self.get_cog_help_mapping(ctx, obj, help_settings=help_settings) if not (coms or help_settings.verify_exists): return description = obj.format_help_for_context(ctx) tagline = (help_settings.tagline) or self.get_default_tagline(ctx) if await ctx.embed_requested(): emb = { "embed": {"title": "", "description": ""}, "footer": {"text": ""}, "fields": [], } emb["footer"]["text"] = tagline if description: splitted = description.split("\n\n") name = splitted[0] value = "\n\n".join(splitted[1:]) if not value: value = EMPTY_STRING field = EmbedField(f"{name[:252]}", value[:1024], False) emb["fields"].append(field) if coms: def shorten_line(a_line: str) -> str: if len(a_line) < 70: # embed max width needs to be lower return a_line return a_line[:67] + "..." spacing = len(max(coms.keys(), key=len)) command_text = "\n".join( shorten_line(f"`{name:<{spacing}}:`{command.format_shortdoc_for_context(ctx)}") for name, command in sorted(coms.items()) ) for i, page in enumerate(pagify(command_text, page_length=500, shorten_by=0)): if i == 0: title = _("**__Commands:__**") else: title = _("**__Commands:__** (continued)") field = EmbedField(title, page, False) emb["fields"].append(field) pages = await self.make_embeds(ctx, emb, help_settings=help_settings) await self.send_pages(ctx, pages, embed=True, help_settings=help_settings) else: await ctx.send("Enable embeds pls")
async def format_bot_help(self, ctx: Context, help_settings: HelpSettings, get_pages: bool = False): if await ctx.embed_requested(): emb = await self.embed_template(help_settings, ctx, ctx.bot.description) filtered_categories = await self.filter_categories( ctx, GLOBAL_CATEGORIES) for i in pagify( "\n".join( f"{str(cat.reaction) if cat.reaction else ''} `{ctx.clean_prefix}help {cat.name:<10}:`**{cat.desc}**\n" for cat in filtered_categories if cat.cogs), page_length=1018, ): emb["fields"].append(EmbedField("Categories:", i, False)) pages = await self.make_embeds(ctx, emb, help_settings=help_settings) if get_pages: return pages else: await self.send_pages( ctx, pages, embed=True, help_settings=help_settings, add_emojis=((await self.config.settings())["react"]) and True, emoji_mapping=filtered_categories, ) else: await ctx.send(_("You need to enable embeds to use the help menu"))
async def format_command_help(self, ctx: Context, obj: commands.Command, help_settings: HelpSettings): send = help_settings.verify_exists if not send: async for __ in self.help_filter_func(ctx, (obj, ), bypass_hidden=True, help_settings=help_settings): send = True if not send: return command = obj description = command.description or "" signature = _( "`Syntax: {ctx.clean_prefix}{command.qualified_name} {command.signature}`" ).format(ctx=ctx, command=command) subcommands = None if hasattr(command, "all_commands"): grp = cast(commands.Group, command) subcommands = await self.get_group_help_mapping( ctx, grp, help_settings=help_settings) if await ctx.embed_requested(): emb = await self.embed_template(help_settings, ctx) if description: emb["embed"]["title"] = f"{description[:250]}" emb["embed"]["description"] = signature command_help = command.format_help_for_context(ctx) if command_help: splitted = command_help.split("\n\n") name = splitted[0] value = "\n\n".join(splitted[1:]) if not value: value = EMPTY_STRING field = EmbedField("Description", name[:250] + "\n" + value[:1024], False) emb["fields"].append(field) if alias := get_aliases(command, ctx.invoked_with): emb["fields"].append( EmbedField("Aliases", ",".join(alias), False)) if final_perms := get_perms(command): emb["fields"].append( EmbedField("Permissions", final_perms, False)) if cooldowns := get_cooldowns(command): emb["fields"].append( EmbedField("Cooldowns", "\n".join(cooldowns), False))
async def format_cog_help(self, ctx: Context, obj: commands.Cog, help_settings: HelpSettings): coms = await self.get_cog_help_mapping(ctx, obj, help_settings=help_settings) if not (coms or help_settings.verify_exists): return if await ctx.embed_requested(): emb = await self.embed_template(help_settings, ctx, obj.format_help_for_context(ctx)) if coms: spacing = len(max(coms.keys(), key=len)) command_text = "\n".join( shorten_line( f"`{name:<{spacing}}:`{command.format_shortdoc_for_context(ctx)}" ) for name, command in sorted(coms.items())) for i, page in enumerate( pagify(command_text, page_length=500, shorten_by=0)): if i == 0: title = _("**__Commands:__**") else: title = _("**__Commands:__** (continued)") field = EmbedField(title, page, False) emb["fields"].append(field) pages = await self.make_embeds(ctx, emb, help_settings=help_settings) await self.send_pages(ctx, pages, embed=True, help_settings=help_settings) else: await ctx.send(_("You need to enable embeds to use the help menu"))
async def send_pages( self, ctx: Context, pages: List[Union[str, discord.Embed]], embed: bool = True, help_settings: HelpSettings = None, add_emojis: bool = False, ): """ Sends pages based on settings. """ # save on config calls channel_permissions = ctx.channel.permissions_for(ctx.me) if not (channel_permissions.add_reactions and help_settings.use_menus): max_pages_in_guild = help_settings.max_pages_in_guild use_DMs = len(pages) > max_pages_in_guild destination = ctx.author if use_DMs else ctx.channel delete_delay = help_settings.delete_delay messages: List[discord.Message] = [] for page in pages: try: if embed: msg = await destination.send(embed=page) else: msg = await destination.send(page) except discord.Forbidden: return await ctx.send( _( "I couldn't send the help message to you in DM. " "Either you blocked me or you disabled DMs in this server." ) ) else: messages.append(msg) if use_DMs and help_settings.use_tick: await ctx.tick() # The if statement takes into account that 'destination' will be # the context channel in non-DM context, reusing 'channel_permissions' to avoid # computing the permissions twice. if ( not use_DMs # we're not in DMs and delete_delay > 0 # delete delay is enabled and channel_permissions.manage_messages # we can manage messages here ): # We need to wrap this in a task to not block after-sending-help interactions. # The channel has to be TextChannel as we can't bulk-delete from DMs async def _delete_delay_help( channel: discord.TextChannel, messages: List[discord.Message], delay: int, ): await asyncio.sleep(delay) await mass_purge(messages, channel) asyncio.create_task(_delete_delay_help(destination, messages, delete_delay)) else: # Specifically ensuring the menu's message is sent prior to returning # m = await (ctx.send(embed=pages[0]) if embed else ctx.send(pages[0])) trans = { "left": prev_page, "cross": close_menu, "right": next_page, } final_menu = get_menu()(ListPages(pages)) for thing in trans: final_menu.add_button(trans[thing](ARROWS[thing])) # TODO important! if add_emojis: # Adding additional category emojis , regex from dpy server for cat in GLOBAL_CATEGORIES: if cat.reaction: if await self.blacklist(ctx, cat.name): final_menu.add_button( await react_page(ctx, cat.reaction, help_settings) ) final_menu.add_button(await home_page(ctx, ARROWS["home"], help_settings)) await final_menu.start(ctx)
async def make_embeds( self, ctx, embed_dict: dict, help_settings: HelpSettings, ): """Returns Embed pages (Really copy paste from core)""" pages = [] thumbnail_url = await self.config.settings.thumbnail() page_char_limit = help_settings.page_char_limit page_char_limit = min(page_char_limit, 5500) author_info = { "name": _("{ctx.me.display_name} Help Menu").format(ctx=ctx), "icon_url": ctx.me.avatar_url, } offset = len(author_info["name"]) + 20 foot_text = embed_dict["footer"]["text"] if foot_text: offset += len(foot_text) offset += len(embed_dict["embed"]["description"]) offset += len(embed_dict["embed"]["title"]) if page_char_limit + offset > 5500: page_char_limit = 5500 - offset elif page_char_limit < 250: page_char_limit = 250 field_groups = self.group_embed_fields(embed_dict["fields"], page_char_limit) color = await ctx.embed_color() page_count = len(field_groups) if not field_groups: # This can happen on single command without a docstring embed = discord.Embed(color=color, **embed_dict["embed"]) embed.set_author(**author_info) embed.set_footer(**embed_dict["footer"]) if thumbnail_url: embed.set_thumbnail(url=thumbnail_url) pages.append(embed) for i, group in enumerate(field_groups, 1): embed = discord.Embed(color=color, **embed_dict["embed"]) if page_count > 1: description = _("*Page {page_num} of {page_count}*\n{content_description}").format( content_description=embed.description, page_num=i, page_count=page_count, ) embed.description = description embed.set_author(**author_info) for field in group: embed.add_field(**field._asdict()) embed.set_footer(**embed_dict["footer"]) if thumbnail_url: embed.set_thumbnail(url=thumbnail_url) pages.append(embed) return pages
async def format_command_help( self, ctx: Context, obj: commands.Command, help_settings: HelpSettings ): send = help_settings.verify_exists if not send: async for __ in self.help_filter_func( ctx, (obj,), bypass_hidden=True, help_settings=help_settings ): send = True if not send: return command = obj description = command.description or "" tagline = (help_settings.tagline) or self.get_default_tagline(ctx) signature = _( "`Syntax: {ctx.clean_prefix}{command.qualified_name} {command.signature}`" ).format(ctx=ctx, command=command) subcommands = None if hasattr(command, "all_commands"): grp = cast(commands.Group, command) subcommands = await self.get_group_help_mapping(ctx, grp, help_settings=help_settings) if await ctx.embed_requested(): emb = { "embed": {"title": "", "description": ""}, "footer": {"text": ""}, "fields": [], } if description: emb["embed"]["title"] = f"*{description[:250]}*" emb["footer"]["text"] = tagline emb["embed"]["description"] = signature command_help = command.format_help_for_context(ctx) if command_help: splitted = command_help.split("\n\n") name = splitted[0] value = "\n\n".join(splitted[1:]) if not value: value = EMPTY_STRING field = EmbedField("Description", name[:250] + "\n" + value[:1024], False) emb["fields"].append(field) # Add aliases if alias := command.aliases: if ctx.invoked_with in alias: alias.remove(ctx.invoked_with) alias.append(command.name) emb["fields"].append(EmbedField("Aliases", ",".join(alias), False)) # Add permissions get_list = ["user_perms", "bot_perms"] final_perms = [] neat_format = lambda x: " ".join( i.capitalize() for i in x.replace("_", " ").split() ) for thing in get_list: if perms := getattr(command.requires, thing): perms_list = [ neat_format(i) for i, j in perms if j ] # TODO pls learn more to fix this if perms_list: final_perms += perms_list if perms := command.requires.privilege_level: if perms.name != "NONE": final_perms.append(neat_format(perms.name))
if subcommands: def shorten_line(a_line: str) -> str: if len(a_line) < 70: # embed max width needs to be lower return a_line return a_line[:67] + ".." spacing = len(max(subcommands.keys(), key=len)) subtext = "\n" + "\n".join( shorten_line(f"`{name:<{spacing}}:`{command.format_shortdoc_for_context(ctx)}") for name, command in sorted(subcommands.items()) ) for i, page in enumerate(pagify(subtext, page_length=500, shorten_by=0)): if i == 0: title = _("**__Subcommands:__**") else: title = EMPTY_STRING field = EmbedField(title, page, False) emb["fields"].append(field) pages = await self.make_embeds(ctx, emb, help_settings=help_settings) await self.send_pages(ctx, pages, embed=True, help_settings=help_settings) else: await ctx.send("Enable embeds pls") async def format_bot_help( self, ctx: Context, help_settings: HelpSettings, get_pages: bool = False ): description = ctx.bot.description or "" tagline = (help_settings.tagline) or self.get_default_tagline(ctx) if not await ctx.embed_requested(): # Maybe redirect to non-embed minimal format
field = EmbedField(title, page, False) emb["fields"].append(field) title = EMPTY_STRING pages = await self.make_embeds(ctx, emb, help_settings=help_settings) if get_pages: return pages else: await self.send_pages(ctx, pages, embed=True, help_settings=help_settings) else: await ctx.send(_("You need to enable embeds to use the help menu")) async def format_cog_help(self, ctx: Context, obj: commands.Cog, help_settings: HelpSettings): coms = await self.get_cog_help_mapping(ctx, obj, help_settings=help_settings) if not (coms or help_settings.verify_exists): return if await ctx.embed_requested(): emb = await self.embed_template(help_settings, ctx, obj.format_help_for_context(ctx)) if coms: spacing = len(max(coms.keys(), key=len))