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 .context import Context
from .core import * from .core import *
from .errors import * from .errors import *
from .formatter import HelpFormatter from .formatter import HelpFormatter, Paginator
from .converter import * 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. # Type <prefix>help command for more info on a command.
# You can also type <prefix>help category for more info on a category. # 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: class HelpFormatter:
"""The default base implementation that handles formatting of the help """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() iterator = self.command.commands.items() if not self.is_cog() else self.context.bot.commands.items()
return filter(predicate, iterator) 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): def _add_subcommands_to_page(self, max_width, commands):
for name, command in commands: for name, command in commands:
if name in command.aliases: if name in command.aliases:
@ -210,10 +256,7 @@ class HelpFormatter:
entry = ' {0:<{width}} {1}'.format(name, command.short_doc, width=max_width) entry = ' {0:<{width}} {1}'.format(name, command.short_doc, width=max_width)
shortened = self.shorten(entry) shortened = self.shorten(entry)
self._count += len(shortened) self._paginator.add_line(shortened)
if self._check_new_page():
self._count += len(shortened)
self._current_page.append(shortened)
def format_help_for(self, context, command_or_bot): def format_help_for(self, context, command_or_bot):
"""Formats the help page and handles the actual heavy lifting of how """Formats the help page and handles the actual heavy lifting of how
@ -246,9 +289,7 @@ class HelpFormatter:
list list
A paginated output of the help command. A paginated output of the help command.
""" """
self._pages = [] self._paginator = Paginator()
self._count = 4 # ``` + '\n'
self._current_page = ['```']
# we need a padding of ~80 or so # we need a padding of ~80 or so
@ -256,30 +297,21 @@ class HelpFormatter:
if description: if description:
# <description> portion # <description> portion
self._current_page.append(description) self._paginator.add_line(description, empty=True)
self._current_page.append('')
self._count += len(description)
if isinstance(self.command, Command): if isinstance(self.command, Command):
# <signature portion> # <signature portion>
signature = self.get_command_signature() signature = self.get_command_signature()
self._count += 2 + len(signature) # '\n' sig '\n' self._paginator.add_line(signature, empty=True)
self._current_page.append(signature)
self._current_page.append('')
# <long doc> section # <long doc> section
if self.command.help: if self.command.help:
self._count += 2 + len(self.command.help) self._paginator.add_line(self.command.help, empty=True)
self._current_page.append(self.command.help)
self._current_page.append('')
self._check_new_page()
# end it here if it's just a regular command # end it here if it's just a regular command
if not self.has_subcommands(): if not self.has_subcommands():
self._current_page.append('```') self._paginator.close_page()
self._pages.append('\n'.join(self._current_page)) return self._paginator.pages
return self._pages
max_width = self.max_name_size max_width = self.max_name_size
@ -295,25 +327,15 @@ class HelpFormatter:
# there simply is no prettier way of doing this. # there simply is no prettier way of doing this.
commands = list(commands) commands = list(commands)
if len(commands) > 0: if len(commands) > 0:
self._current_page.append(category) self._paginator.add_line(category)
self._count += len(category)
self._check_new_page()
self._add_subcommands_to_page(max_width, commands) self._add_subcommands_to_page(max_width, commands)
else: else:
self._current_page.append('Commands:') self._paginator.add_line('Commands:')
self._count += 1 + len(self._current_page[-1])
self._add_subcommands_to_page(max_width, self.filter_command_list()) self._add_subcommands_to_page(max_width, self.filter_command_list())
# add the ending note # add the ending note
self._current_page.append('') self._paginator.add_line()
ending_note = self.get_ending_note() ending_note = self.get_ending_note()
self._count += len(ending_note) self._paginator.add_line(ending_note)
self._check_new_page() return self._paginator.pages
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

Loading…
Cancel
Save