aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--discord/ext/commands/__init__.py2
-rw-r--r--discord/ext/commands/formatter.py118
2 files changed, 71 insertions, 49 deletions
diff --git a/discord/ext/commands/__init__.py b/discord/ext/commands/__init__.py
index 6d82962d..ed28b6a0 100644
--- a/discord/ext/commands/__init__.py
+++ b/discord/ext/commands/__init__.py
@@ -14,5 +14,5 @@ from .bot import Bot, when_mentioned, when_mentioned_or
from .context import Context
from .core import *
from .errors import *
-from .formatter import HelpFormatter
+from .formatter import HelpFormatter, Paginator
from .converter import *
diff --git a/discord/ext/commands/formatter.py b/discord/ext/commands/formatter.py
index d20d6579..452fd40e 100644
--- a/discord/ext/commands/formatter.py
+++ b/discord/ext/commands/formatter.py
@@ -51,6 +51,64 @@ from .errors import CommandError
# Type <prefix>help command for more info on a command.
# You can also type <prefix>help category for more info on a category.
+class Paginator:
+ """A class that aids in paginating code blocks for Discord messages.
+
+ Attributes
+ -----------
+ prefix: str
+ The prefix inserted to every page. e.g. three backticks.
+ suffix: str
+ The suffix appended at the end of every page. e.g. three backticks.
+ max_size: int
+ The maximum amount of codepoints allowed in a page.
+ """
+ def __init__(self, prefix='```', suffix='```', max_size=2000):
+ self.prefix = prefix
+ self.suffix = suffix
+ self.max_size = max_size - len(suffix)
+ self._current_page = [prefix]
+ self._count = len(prefix) + 1 # prefix + newline
+ self._pages = []
+
+ def add_line(self, line='', *, empty=False):
+ """Adds a line to the current page.
+
+ Parameters
+ -----------
+ line: str
+ The line to add.
+ empty: bool
+ Indicates if another empty line should be added.
+ """
+ if self._count + len(line) + 1 > self.max_size:
+ self.close_page()
+
+ self._count += len(line) + 1
+ self._current_page.append(line)
+
+ if empty:
+ self._current_page.append('')
+ self._count += 1
+
+ def close_page(self):
+ """Prematurely terminate a page."""
+ self._current_page.append(self.suffix)
+ self._pages.append('\n'.join(self._current_page))
+ self._current_page = [self.prefix]
+ self._count = len(self.prefix) + 1 # prefix + newline
+
+ @property
+ def pages(self):
+ """Returns the rendered list of pages."""
+ # we have more than just the prefix in our current page
+ if len(self._current_page) > 1:
+ self.close_page()
+ return self._pages
+
+ def __repr__(self):
+ fmt = '<Paginator prefix: {0.prefix} suffix: {0.suffix} max_size: {0.max_size} count: {0._count}>'
+ return fmt.format(self)
class HelpFormatter:
"""The default base implementation that handles formatting of the help
@@ -190,18 +248,6 @@ class HelpFormatter:
iterator = self.command.commands.items() if not self.is_cog() else self.context.bot.commands.items()
return filter(predicate, iterator)
- def _check_new_page(self):
- # be a little on the safe side
- # we're adding 1 extra newline per page
- if self._count + len(self._current_page) >= 1980:
- # add the page
- self._current_page.append('```')
- self._pages.append('\n'.join(self._current_page))
- self._current_page = ['```']
- self._count = 4
- return True
- return False
-
def _add_subcommands_to_page(self, max_width, commands):
for name, command in commands:
if name in command.aliases:
@@ -210,10 +256,7 @@ class HelpFormatter:
entry = ' {0:<{width}} {1}'.format(name, command.short_doc, width=max_width)
shortened = self.shorten(entry)
- self._count += len(shortened)
- if self._check_new_page():
- self._count += len(shortened)
- self._current_page.append(shortened)
+ self._paginator.add_line(shortened)
def format_help_for(self, context, command_or_bot):
"""Formats the help page and handles the actual heavy lifting of how
@@ -246,9 +289,7 @@ class HelpFormatter:
list
A paginated output of the help command.
"""
- self._pages = []
- self._count = 4 # ``` + '\n'
- self._current_page = ['```']
+ self._paginator = Paginator()
# we need a padding of ~80 or so
@@ -256,30 +297,21 @@ class HelpFormatter:
if description:
# <description> portion
- self._current_page.append(description)
- self._current_page.append('')
- self._count += len(description)
+ self._paginator.add_line(description, empty=True)
if isinstance(self.command, Command):
# <signature portion>
signature = self.get_command_signature()
- self._count += 2 + len(signature) # '\n' sig '\n'
- self._current_page.append(signature)
- self._current_page.append('')
+ self._paginator.add_line(signature, empty=True)
# <long doc> section
if self.command.help:
- self._count += 2 + len(self.command.help)
- self._current_page.append(self.command.help)
- self._current_page.append('')
- self._check_new_page()
+ self._paginator.add_line(self.command.help, empty=True)
# end it here if it's just a regular command
if not self.has_subcommands():
- self._current_page.append('```')
- self._pages.append('\n'.join(self._current_page))
- return self._pages
-
+ self._paginator.close_page()
+ return self._paginator.pages
max_width = self.max_name_size
@@ -295,25 +327,15 @@ class HelpFormatter:
# there simply is no prettier way of doing this.
commands = list(commands)
if len(commands) > 0:
- self._current_page.append(category)
- self._count += len(category)
- self._check_new_page()
+ self._paginator.add_line(category)
self._add_subcommands_to_page(max_width, commands)
else:
- self._current_page.append('Commands:')
- self._count += 1 + len(self._current_page[-1])
+ self._paginator.add_line('Commands:')
self._add_subcommands_to_page(max_width, self.filter_command_list())
# add the ending note
- self._current_page.append('')
+ self._paginator.add_line()
ending_note = self.get_ending_note()
- self._count += len(ending_note)
- self._check_new_page()
- self._current_page.append(ending_note)
-
- if len(self._current_page) > 1:
- self._current_page.append('```')
- self._pages.append('\n'.join(self._current_page))
-
- return self._pages
+ self._paginator.add_line(ending_note)
+ return self._paginator.pages