Skip to content
Merged
4 changes: 3 additions & 1 deletion bot/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from discord import Game
from discord.ext.commands import AutoShardedBot, when_mentioned_or

from bot.formatter import Formatter
from bot.utils import CaseInsensitiveDict

bot = AutoShardedBot(
Expand All @@ -14,7 +15,8 @@
">>>", ">>", ">"
), # Order matters (and so do commas)
game=Game(name="Help: bot.help()"),
help_attrs={"aliases": ["help()"]}
help_attrs={"aliases": ["help()"]},
formatter=Formatter()
)

bot.cogs = CaseInsensitiveDict()
Expand Down
2 changes: 2 additions & 0 deletions bot/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@
MODERATOR_ROLE = 267629731250176001
VERIFIED_ROLE = 352427296948486144
OWNER_ROLE = 267627879762755584

HELP_PREFIX = "bot."
102 changes: 102 additions & 0 deletions bot/formatter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# coding=utf-8

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this blank line is, I believe, against the law

"""
Credit to Rapptz's script used as an example:
https://github.com/Rapptz/discord.py/blob/rewrite/discord/ext/commands/formatter.py
Which falls under The MIT License.
"""

import itertools
from inspect import formatargspec, getfullargspec

from discord.ext.commands import Command, HelpFormatter, Paginator

from bot.constants import HELP_PREFIX


class Formatter(HelpFormatter):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def _add_subcommands_to_page(self, max_width: int, commands: list):
"""
basically the same function from d.py but changed:
- to make the helptext appear as a comment
- to change the indentation to the PEP8 standard: 4 spaces
"""
for name, command in commands:
if name in command.aliases:
# skip aliases
continue

entry = " {0}{1:<{width}} # {2}".format(HELP_PREFIX, name, command.short_doc, width=max_width)
shortened = self.shorten(entry)
self._paginator.add_line(shortened)

async def format(self):
"""
rewritten help command to make it more python-y

example of specific command:
async def <command>(ctx, <args>):
\"""
<help text>
\"""
await do_<command>(ctx, <args>)

example of standard help page:
class <cog1>:
bot.<command1>() # <command1 help>
class <cog2>:
bot.<command2>() # <command2 help>

# <ending help note>
"""
self._paginator = Paginator(prefix="```py")

if isinstance(self.command, Command):
# strip the command of bot. and ()
stripped_command = self.command.name.replace(HELP_PREFIX, "").replace("()", "")

# get the args using the handy inspect module
argspec = getfullargspec(self.command.callback)
arguments = formatargspec(*argspec)
args_no_type_hints = ", ".join(argspec[0])

# remove self from the args
arguments = arguments.replace("self, ", "")
args_no_type_hints = args_no_type_hints.replace("self, ", "")

# prepare the different sections of the help output, and add them to the paginator
definition = f"async def {stripped_command}{arguments}:"
docstring = f" \"\"\"\n {self.command.help}\n \"\"\""
invocation = f" await do_{stripped_command}({args_no_type_hints})"
self._paginator.add_line(definition)
self._paginator.add_line(docstring)
self._paginator.add_line(invocation)

return self._paginator.pages

max_width = self.max_name_size

def category_check(tup):
cog = tup[1].cog_name
# zero width character to make it appear last when put in alphabetical order
return cog if cog is not None else "\u200bNoCategory"

command_list = await self.filter_command_list()
data = sorted(command_list, key=category_check)

for category, commands in itertools.groupby(data, key=category_check):
commands = sorted(commands)
if len(commands) > 0:
self._paginator.add_line(f"class {category}:")
self._add_subcommands_to_page(max_width, commands)

self._paginator.add_line()
ending_note = self.get_ending_note()
# make the ending note appear as comments
ending_note = "# "+ending_note.replace("\n", "\n# ")
self._paginator.add_line(ending_note)

return self._paginator.pages