Browse Source

[commands] Refactor pagination into its own class.

This change allows users to more easily create their own formatters
without having to reinvent the pagination logic themselves. Hopefully
this makes it less of a pain for people to create custom help pages.
pull/265/head
Rapptz 9 years ago
parent
commit
166d8257ec
  1. 2
      discord/ext/commands/__init__.py
  2. 118
      discord/ext/commands/formatter.py

2
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 *

118
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

Loading…
Cancel
Save