|
1
|
|
|
from discord.ext import commands
|
|
2
|
|
|
from utils import checks
|
|
3
|
|
|
from utils.paginator import Pages
|
|
4
|
|
|
import discord
|
|
5
|
|
|
from collections import OrderedDict, deque, Counter
|
|
6
|
|
|
import os, datetime
|
|
7
|
|
|
import asyncio
|
|
8
|
|
|
import copy
|
|
9
|
|
|
import unicodedata
|
|
10
|
|
|
import inspect
|
|
11
|
|
|
import itertools
|
|
12
|
|
|
from typing import Union
|
|
13
|
|
|
|
|
14
|
|
|
|
|
15
|
|
|
class HelpPaginator(Pages):
|
|
16
|
|
|
def __init__(self, help_command, ctx, entries, *, per_page=4):
|
|
17
|
|
|
super().__init__(ctx, entries=entries, per_page=per_page)
|
|
18
|
|
|
self.reaction_emojis.append(("\N{WHITE QUESTION MARK ORNAMENT}", self.show_bot_help))
|
|
19
|
|
|
self.total = len(entries)
|
|
20
|
|
|
self.help_command = help_command
|
|
21
|
|
|
self.prefix = help_command.clean_prefix
|
|
22
|
|
|
self.is_bot = False
|
|
23
|
|
|
|
|
24
|
|
|
def get_bot_page(self, page):
|
|
25
|
|
|
cog, description, commands = self.entries[page - 1]
|
|
26
|
|
|
self.title = f"{cog} Commands"
|
|
27
|
|
|
self.description = description
|
|
28
|
|
|
return commands
|
|
29
|
|
|
|
|
30
|
|
|
def prepare_embed(self, entries, page, *, first=False):
|
|
31
|
|
|
self.embed.clear_fields()
|
|
32
|
|
|
self.embed.description = self.description
|
|
33
|
|
|
self.embed.title = self.title
|
|
34
|
|
|
|
|
35
|
|
|
if self.is_bot:
|
|
36
|
|
|
value = "For more help, please contact External72#6969"
|
|
37
|
|
|
self.embed.add_field(name="Support", value=value, inline=False)
|
|
38
|
|
|
|
|
39
|
|
|
self.embed.set_footer(text=f'Use "{self.prefix}help command" for more info on a command.')
|
|
40
|
|
|
|
|
41
|
|
|
for entry in entries:
|
|
42
|
|
|
signature = f"{entry.qualified_name} {entry.signature}"
|
|
43
|
|
|
self.embed.add_field(name=signature, value=entry.short_doc or "No help given", inline=False)
|
|
44
|
|
|
|
|
45
|
|
|
if self.maximum_pages:
|
|
46
|
|
|
self.embed.set_author(name=f"Page {page}/{self.maximum_pages} ({self.total} commands)")
|
|
47
|
|
|
|
|
48
|
|
View Code Duplication |
async def show_help(self):
|
|
49
|
|
|
"""shows this message"""
|
|
50
|
|
|
|
|
51
|
|
|
self.embed.title = "Paginator help"
|
|
52
|
|
|
self.embed.description = "Hello! Welcome to the help page."
|
|
53
|
|
|
|
|
54
|
|
|
messages = [f"{emoji} {func.__doc__}" for emoji, func in self.reaction_emojis]
|
|
55
|
|
|
self.embed.clear_fields()
|
|
56
|
|
|
self.embed.add_field(name="What are these reactions for?", value="\n".join(messages), inline=False)
|
|
57
|
|
|
|
|
58
|
|
|
self.embed.set_footer(text=f"We were on page {self.current_page} before this message.")
|
|
59
|
|
|
await self.message.edit(embed=self.embed)
|
|
60
|
|
|
|
|
61
|
|
|
async def go_back_to_current_page():
|
|
62
|
|
|
await asyncio.sleep(30.0)
|
|
63
|
|
|
await self.show_current_page()
|
|
64
|
|
|
|
|
65
|
|
|
self.bot.loop.create_task(go_back_to_current_page())
|
|
66
|
|
|
|
|
67
|
|
View Code Duplication |
async def show_bot_help(self):
|
|
68
|
|
|
"""shows how to use the bot"""
|
|
69
|
|
|
|
|
70
|
|
|
self.embed.title = "Using the bot"
|
|
71
|
|
|
self.embed.description = "Hello! Welcome to the help page."
|
|
72
|
|
|
self.embed.clear_fields()
|
|
73
|
|
|
|
|
74
|
|
|
entries = (
|
|
75
|
|
|
("<argument>", "This means the argument is __**required**__."),
|
|
76
|
|
|
("[argument]", "This means the argument is __**optional**__."),
|
|
77
|
|
|
("[A|B]", "This means the it can be __**either A or B**__."),
|
|
78
|
|
|
(
|
|
79
|
|
|
"[argument...]",
|
|
80
|
|
|
"This means you can have multiple arguments.\n"
|
|
81
|
|
|
"Now that you know the basics, it should be noted that...\n"
|
|
82
|
|
|
"__**You do not type in the brackets!**__",
|
|
83
|
|
|
),
|
|
84
|
|
|
)
|
|
85
|
|
|
|
|
86
|
|
|
self.embed.add_field(name="How do I use this bot?", value="Reading the bot signature is pretty simple.")
|
|
87
|
|
|
|
|
88
|
|
|
for name, value in entries:
|
|
89
|
|
|
self.embed.add_field(name=name, value=value, inline=False)
|
|
90
|
|
|
|
|
91
|
|
|
self.embed.set_footer(text=f"We were on page {self.current_page} before this message.")
|
|
92
|
|
|
await self.message.edit(embed=self.embed)
|
|
93
|
|
|
|
|
94
|
|
|
async def go_back_to_current_page():
|
|
95
|
|
|
await asyncio.sleep(30.0)
|
|
96
|
|
|
await self.show_current_page()
|
|
97
|
|
|
|
|
98
|
|
|
self.bot.loop.create_task(go_back_to_current_page())
|
|
99
|
|
|
|
|
100
|
|
|
|
|
101
|
|
|
class PaginatedHelpCommand(commands.HelpCommand):
|
|
102
|
|
|
def __init__(self):
|
|
103
|
|
|
super().__init__(
|
|
104
|
|
|
command_attrs={
|
|
105
|
|
|
"cooldown": commands.Cooldown(1, 3.0, commands.BucketType.member),
|
|
106
|
|
|
"help": "Shows help about the bot, a command, or a category",
|
|
107
|
|
|
}
|
|
108
|
|
|
)
|
|
109
|
|
|
|
|
110
|
|
|
async def on_help_command_error(self, ctx, error):
|
|
111
|
|
|
if isinstance(error, commands.CommandInvokeError):
|
|
112
|
|
|
await ctx.send(str(error.original))
|
|
113
|
|
|
|
|
114
|
|
|
def get_command_signature(self, command):
|
|
115
|
|
|
parent = command.full_parent_name
|
|
116
|
|
|
if len(command.aliases) > 0:
|
|
117
|
|
|
aliases = "|".join(command.aliases)
|
|
118
|
|
|
fmt = f"[{command.name}|{aliases}]"
|
|
119
|
|
|
if parent:
|
|
120
|
|
|
fmt = f"{parent} {fmt}"
|
|
121
|
|
|
alias = fmt
|
|
122
|
|
|
else:
|
|
123
|
|
|
alias = command.name if not parent else f"{parent} {command.name}"
|
|
124
|
|
|
return f"{alias} {command.signature}"
|
|
125
|
|
|
|
|
126
|
|
|
async def send_bot_help(self, mapping):
|
|
127
|
|
|
def key(c):
|
|
128
|
|
|
return c.cog_name or "\u200bNo Category"
|
|
129
|
|
|
|
|
130
|
|
|
bot = self.context.bot
|
|
131
|
|
|
entries = await self.filter_commands(bot.commands, sort=True, key=key)
|
|
132
|
|
|
nested_pages = []
|
|
133
|
|
|
per_page = 9
|
|
134
|
|
|
total = 0
|
|
135
|
|
|
|
|
136
|
|
|
for cog, commands in itertools.groupby(entries, key=key):
|
|
137
|
|
|
commands = sorted(commands, key=lambda c: c.name)
|
|
138
|
|
|
if len(commands) == 0:
|
|
139
|
|
|
continue
|
|
140
|
|
|
|
|
141
|
|
|
total += len(commands)
|
|
142
|
|
|
actual_cog = bot.get_cog(cog)
|
|
143
|
|
|
# get the description if it exists (and the cog is valid) or return Empty embed.
|
|
144
|
|
|
description = (actual_cog and actual_cog.description) or discord.Embed.Empty
|
|
145
|
|
|
nested_pages.extend(
|
|
146
|
|
|
(cog, description, commands[i : i + per_page]) for i in range(0, len(commands), per_page)
|
|
147
|
|
|
)
|
|
148
|
|
|
|
|
149
|
|
|
# a value of 1 forces the pagination session
|
|
150
|
|
|
pages = HelpPaginator(self, self.context, nested_pages, per_page=1)
|
|
151
|
|
|
|
|
152
|
|
|
# swap the get_page implementation to work with our nested pages.
|
|
153
|
|
|
pages.get_page = pages.get_bot_page
|
|
154
|
|
|
pages.is_bot = True
|
|
155
|
|
|
pages.total = total
|
|
156
|
|
|
await pages.paginate()
|
|
157
|
|
|
|
|
158
|
|
|
async def send_cog_help(self, cog):
|
|
159
|
|
|
entries = await self.filter_commands(cog.get_commands(), sort=True)
|
|
160
|
|
|
pages = HelpPaginator(self, self.context, entries)
|
|
161
|
|
|
pages.title = f"{cog.qualified_name} Commands"
|
|
162
|
|
|
pages.description = cog.description
|
|
163
|
|
|
|
|
164
|
|
|
await pages.paginate()
|
|
165
|
|
|
|
|
166
|
|
|
def common_command_formatting(self, page_or_embed, command):
|
|
167
|
|
|
page_or_embed.title = self.get_command_signature(command)
|
|
168
|
|
|
if command.description:
|
|
169
|
|
|
page_or_embed.description = f"{command.description}\n\n{command.help}"
|
|
170
|
|
|
else:
|
|
171
|
|
|
page_or_embed.description = command.help or "No help found..."
|
|
172
|
|
|
|
|
173
|
|
|
async def send_command_help(self, command):
|
|
174
|
|
|
# No pagination necessary for a single command.
|
|
175
|
|
|
embed = discord.Embed(colour=discord.Colour.blurple())
|
|
176
|
|
|
self.common_command_formatting(embed, command)
|
|
177
|
|
|
await self.context.send(embed=embed)
|
|
178
|
|
|
|
|
179
|
|
|
async def send_group_help(self, group):
|
|
180
|
|
|
subcommands = group.commands
|
|
181
|
|
|
if len(subcommands) == 0:
|
|
182
|
|
|
return await self.send_command_help(group)
|
|
183
|
|
|
|
|
184
|
|
|
entries = await self.filter_commands(subcommands, sort=True)
|
|
185
|
|
|
pages = HelpPaginator(self, self.context, entries)
|
|
186
|
|
|
self.common_command_formatting(pages, group)
|
|
187
|
|
|
|
|
188
|
|
|
await pages.paginate()
|
|
189
|
|
|
|
|
190
|
|
|
|
|
191
|
|
|
class Help(commands.Cog):
|
|
192
|
|
|
def __init__(self, bot):
|
|
193
|
|
|
self.bot = bot
|
|
194
|
|
|
self.old_help_command = bot.help_command
|
|
195
|
|
|
bot.help_command = PaginatedHelpCommand()
|
|
196
|
|
|
bot.help_command.cog = self
|
|
197
|
|
|
|
|
198
|
|
|
def cog_unload(self):
|
|
199
|
|
|
self.bot.help_command = self.old_help_command
|
|
200
|
|
|
|
|
201
|
|
|
|
|
202
|
|
|
def setup(bot):
|
|
203
|
|
|
bot.add_cog(Help(bot))
|
|
204
|
|
|
|