import discord from utils.lib import prop_tabulate from utils import interactive, ctx_addons # noqa from wards import is_guild_admin from .module import module # Set the command groups to appear in the help group_hints = { 'Productivity': "*Various productivity tools.*", 'Statistics': "*StudyLion leaderboards and study statistics.*", 'Personal Settings': "*Tell me about yourself!*", 'Guild Configuration': "*Control how I behave in your server.*", 'Meta': "*Information about me!*" } standard_group_order = ( ('Productivity', 'Statistics', 'Personal Settings', 'Meta') ) mod_group_order = ( ('Moderation', 'Meta'), ('Productivity', 'Statistics', 'Personal Settings') ) admin_group_order = ( ('Guild Configuration', 'Moderation', 'Meta'), ('Productivity', 'Statistics', 'Personal Settings') ) # Help embed format # TODO: Add config fields for this title = "LionBot Command List" header = """ For more detailed information about each command use `{ctx.best_prefix}help `. """ @module.cmd("help", group="Meta", desc="LionBot command list.") async def cmd_help(ctx): """ Usage``: {prefix}help [cmdname] Description: When used with no arguments, displays a list of commands with brief descriptions. Otherwise, shows documentation for the provided command. Examples: {prefix}help {prefix}help top {prefix}help timezone """ if ctx.arg_str: # Attempt to fetch the command command = ctx.client.cmd_names.get(ctx.arg_str.strip(), None) if command is None: return await ctx.error_reply( ("Command `{}` not found!\n" "Write `{}help` to see a list of commands.").format(ctx.args, ctx.best_prefix) ) smart_help = getattr(command, 'smart_help', None) if smart_help is not None: return await smart_help(ctx) help_fields = command.long_help.copy() help_map = {field_name: i for i, (field_name, _) in enumerate(help_fields)} if not help_map: await ctx.reply("No documentation has been written for this command yet!") for name, pos in help_map.items(): if name.endswith("``"): # Handle codeline help fields help_fields[pos] = ( name.strip("`"), "`{}`".format('`\n`'.join(help_fields[pos][1].splitlines())) ) elif name.endswith(":"): # Handle property/value help fields lines = help_fields[pos][1].splitlines() names = [] values = [] for line in lines: split = line.split(":", 1) names.append(split[0] if len(split) > 1 else "") values.append(split[-1]) help_fields[pos] = ( name.strip(':'), prop_tabulate(names, values) ) elif name == "Related": # Handle the related field names = [cmd_name.strip() for cmd_name in help_fields[pos][1].split(',')] names.sort(key=len) values = [ (getattr(ctx.client.cmd_names.get(cmd_name, None), 'desc', '') or '').format(ctx=ctx) for cmd_name in names ] help_fields[pos] = ( name, prop_tabulate(names, values) ) aliases = getattr(command, 'aliases', []) alias_str = "(Aliases `{}`.)".format("`, `".join(aliases)) if aliases else "" # Build the embed embed = discord.Embed( title="`{}` command documentation. {}".format(command.name, alias_str), colour=discord.Colour(0x9b59b6) ) for fieldname, fieldvalue in help_fields: embed.add_field( name=fieldname, value=fieldvalue.format(ctx=ctx, prefix=ctx.best_prefix), inline=False ) embed.set_footer( text="[optional] and denote optional and required arguments, respectively." ) # Post the embed await ctx.reply(embed=embed) else: # Build the command groups cmd_groups = {} for command in ctx.client.cmds: # Get the command group group = getattr(command, 'group', "Misc") cmd_group = cmd_groups.get(group, []) if not cmd_group: cmd_groups[group] = cmd_group # Add the command name and description to the group cmd_group.append((command.name, getattr(command, 'desc', ''))) # Add any required aliases for alias, desc in getattr(command, 'help_aliases', {}).items(): cmd_group.append((alias, desc)) # Turn the command groups into strings stringy_cmd_groups = {} for group_name, cmd_group in cmd_groups.items(): cmd_group.sort(key=lambda tup: len(tup[0])) stringy_cmd_groups[group_name] = prop_tabulate(*zip(*cmd_group)) # Now put everything into a bunch of embeds if ctx.guild and is_guild_admin(ctx.author): group_order = admin_group_order else: group_order = standard_group_order help_embeds = [] for page_groups in group_order: embed = discord.Embed( description=header.format(ctx=ctx), colour=discord.Colour(0x9b59b6), title=title ) for group in page_groups: group_hint = group_hints.get(group, '').format(ctx=ctx) group_str = stringy_cmd_groups.get(group, None) if group_str: embed.add_field( name=group, value="{}\n{}".format(group_hint, group_str).format(ctx=ctx), inline=False ) help_embeds.append(embed) # Add the page numbers for i, embed in enumerate(help_embeds): embed.set_footer(text="Page {}/{}".format(i+1, len(help_embeds))) # Send the embeds if help_embeds: await ctx.pager(help_embeds) else: await ctx.reply( embed=discord.Embed(description=header, colour=discord.Colour(0x9b59b6)) )