Passed
Push — master ( 839c29...0f7e53 )
by Vinay
01:09
created

cogs.help.PaginatedHelpCommand.send_cog_help()   A

Complexity

Conditions 1

Size

Total Lines 7
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 1
nop 2
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