예제 #1
0
 async def show_off(self, ctx: CommandContext, name: str):
     paginator = Paginator(prefix="```py")
     for line in inspect.getsource(
             self.bot.get_command(name).callback).split('\n'):
         paginator.add_line(line.replace("`", "`\u200B"))
     for page in paginator.pages:
         await ctx.send(page)
예제 #2
0
    def __init__(self, ctx, text, *, prefix='```', suffix='```', max_size=2000):
        paginator = CommandPaginator(
            prefix=prefix, suffix=suffix, max_size=max_size - 200)
        for line in text.split('\n'):
            paginator.add_line(line)

        super().__init__(ctx, entries=paginator.pages, per_page=1, show_entry_count=False)
예제 #3
0
    async def reload(self, ctx: Context):
        """Reloads all cogs."""

        # make a copy of the extension list, because we will be iterating over it and modifying it due to the
        # load and unload calls
        extensions = self.bot.extensions.copy()

        log = Paginator()

        # unload and load everything
        for extension_name, _module in extensions.items():
            try:
                self.log.info('reloading "%s"', extension_name)
                self.bot.unload_extension(extension_name)
                self.bot.load_extension(extension_name)
            except Exception:
                self.log.exception('failed extension load (%s):',
                                   extension_name)
                log.add_line(
                    f'\N{CROSS MARK} Failed to reload extension `{extension_name}`.'
                )

        if not log.pages:
            await ctx.send('\N{OK HAND SIGN}')
        else:
            for page in log.pages:
                await ctx.send(page)
예제 #4
0
    async def source(self, ctx: Context, *, command_name: str) -> None:
        """Get the source code of a command."""
        command = self.bot.get_command(command_name)

        if not command:
            await ctx.send(f"No command named `{command_name}` found.")
            return

        try:
            source_lines, _ = inspect.getsourcelines(command.callback)
        except (TypeError, OSError):
            await ctx.send(
                f"I was unable to retrieve the source for `{command_name}` for some reason."
            )
            return

        source_lines = textwrap.dedent("".join(source_lines).replace(
            "```", f"`{ZWS}`{ZWS}`")).split("\n")
        paginator = Paginator(
            prefix="```py",
            suffix="```",
            max_size=2048,
        )

        for line in source_lines:
            paginator.add_line(line)

        pages = menus.MenuPages(
            source=SauceSource(
                paginator.pages,
                per_page=1,
            ),
            clear_reactions_after=True,
        )
        await pages.start(ctx)
예제 #5
0
파일: owner.py 프로젝트: AkiraSama/novelty
    async def eval(self, ctx: Context, *, code: str):
        """Owner evaluation.

        With great power comes great responsibility."""

        bot = self.bot  # noqa: F841
        eval_paginator = Paginator(prefix='```\n')

        try:
            out = str(eval(code))

            if not out:
                await ctx.send('\u200b')
                return

            for line in itertools.zip_longest(*([iter(out)] *
                                                self.MAX_LINE_SIZE)):
                eval_paginator.add_line(''.join(c for c in line if c).replace(
                    '```', '\\`\\`\\`'))

        except Exception as exception:
            eval_paginator.add_line(f"{type(exception).__name__}: {exception}")

        for page in eval_paginator.pages:
            await ctx.send(page)
예제 #6
0
    def __init__(self, text, *, prefix="```", suffix="```", max_size=2000):
        pages = CommandPaginator(prefix=prefix,
                                 suffix=suffix,
                                 max_size=max_size - 200)
        for line in text.split("\n"):
            pages.add_line(line)

        super().__init__(entries=pages, per_page=1)
예제 #7
0
    async def roles(self, ctx: CommandContext):
        guild: Guild = ctx.guild
        paginator = Paginator()
        for role in guild.roles:
            paginator.add_line(role.name + ' ' + str(role.id))

        for page in paginator.pages:
            await ctx.send(embed=Embed(color=Color.blurple(), description=page)
                           )
예제 #8
0
    async def ext_list(self, ctx: Context):
        """List all loaded extensions."""

        paginator = Paginator(prefix='```\n')

        for name in sorted(self.bot.extensions):
            paginator.add_line(name)

        for page in paginator.pages:
            await ctx.send(page)
    def __init__(self, entries: typing.List[str], *, per_page=None):
        self.initial_page = True

        if per_page is None:
            pages = CommandPaginator(prefix="", suffix="", max_size=1800)
            for line in entries:
                pages.add_line(line)

            super().__init__(pages.pages, per_page=1)

        else:
            super().__init__(entries, per_page=per_page)
예제 #10
0
async def paginate(message: str,
                   pag: disextc.Paginator = None) -> disextc.Paginator:
    """ Helper to use the Paginator.

    Given a line of text it will format it and return the paginator to add
    more lines.

    :param message -> str type with message to send
    :param pag -> Pagenator to add to, or none to create a new.
    :return -> Paginator containing line of text.
    """
    if pag is None:
        pag = disextc.Paginator()
    pag.add_line(message)
    return pag
예제 #11
0
def paginate_to_embeds(
        description: str,
        title: Optional[str] = None,
        max_size: int = 2000,
        prefix: Optional[str] = "",
        suffix: Optional[str] = "",
        color: Union[discord.Color, int, None] = None) -> List[Embed]:
    """
    Facilitates sequential embed menus.
    Returned embeds share title, have description split at :max_length: and are added index/pages at footer to keep
    track of pages.

    Parameters
    ----------
    description: :class:`str`
        String to be split at :max_length: per embed.
    title: :class:`str`
        Shared by all embeds
    max_size: :class:`int`
        Maximum amount of characters per embed. Discord's limit is 2000.
    prefix: :class:`str`
        Defaults to "" it will be appended at the start of the description of each embed.
        Useful for codeblocks (use triple back quotes).
    suffix: :class:`str`
        Same as :prefix: but at the end of the text.
    color: :class:`Union[discord.Color, int, None]`
        color to use for the embed. Accepts int (decimal or hex) or discord.Color/discord.Colour.

    Returns
    -------
    The rendered list of embeds :class:`List[Embed]`
    """
    embeds = []
    to_list = description.split("\n")
    paginator = Paginator(prefix=prefix, suffix=suffix, max_size=max_size)
    for line in to_list:
        paginator.add_line(line)
    for i, page in enumerate(paginator.pages):
        embed = Embed(description=page).set_footer(
            text=f"page: {i + 1}/{len(paginator.pages)}")
        d = {'title': title, 'colour': color}
        for attr in d:
            if value := d[attr]:
                setattr(embed, attr, value)

        embeds.append(embed)
예제 #12
0
async def _dm_me_error(*, bot, cog, ctx, error, event_method):
    embed = discord.Embed(
        title=f"An error occurred: `{type(error).__qualname__}`",
        description=f'Supplied error message: `{error or "—"}`',
        colour=0xFF0000,
    )

    trace = traceback.format_tb(error.__traceback__)
    trace = "".join(trace)
    should_pag = len(trace) > 1010

    if not should_pag:
        trace = f"```\n{trace}\n```"
        embed.add_field(name="Traceback", value=trace, inline=False)

    if ctx:
        whom_info = (
            f"{ctx.command.qualified_name} invoked as {ctx.invoked_with}\n"
            f"Invoked by: {ctx.author} (`{ctx.author.id}`)\n"
            f'{"Guild: " + str(ctx.guild) if ctx.guild else "in DMs"}\n'
            f"Channel: #{ctx.channel}\n"
            f"When: {ctx.message.created_at}"
        )
        body = ctx.message.content
        body = body.replace("`", "’")
        if len(body) > 1000:
            body = f"{body[:997]}..."
        body = f"```\n{body}\n```"
        embed.add_field(name="Command info", value=whom_info)
        embed.add_field(name="Command body", value=body)
    if cog:
        embed.add_field(name="Cog", value=str(cog))
    if event_method:
        embed.add_field(name="Event method", value=str(event_method))

    owner = bot.get_user(bot.owner_id)
    await owner.send(embed=embed)

    if should_pag:
        p = Paginator()
        for line in trace.split("\n"):
            p.add_line(line)
        for page in p.pages:
            # Send the last 15 only. Prevents a hell of a lot
            # of spam if the bot hits a stack overflow.
            await owner.send(page[-15:])
예제 #13
0
    async def send_initial_message(self, ctx, channel):
        query = '''SELECT name
                   FROM tags
                   ORDER BY name
                '''
        res = await ctx.bot.db.fetch(query)
        if not res:
            await ctx.send('No tags found.')
            self.stop()

        paginator = Paginator(prefix=None, suffix=None, max_size=420)
        i = 1
        for name in [row['name'] for row in res]:
            paginator.add_line(f'**{i}.** {name}')
            i += 1
        self.pages = paginator.pages
        return await ctx.send(embed=self.embed)
예제 #14
0
    async def guild_role(self,
                         text: str,
                         check=lambda role: True,
                         list_ids=False) -> Role:
        async def converter(mes: Message):
            return discord.utils.get(self.guild.roles,
                                     id=int(
                                         mes.content.translate(digit_keeper)))

        if list_ids:
            guild: Guild = self.ctx.guild
            paginator = Paginator()
            for role in guild.roles:
                paginator.add_line(role.name + ' ' + str(role.id))

            for page in paginator.pages:
                await self.ctx.send(
                    embed=Embed(color=Color.blurple(), description=page))
        return await self.by_converter(text, check=check, converter=converter)
예제 #15
0
    async def code(self, ctx: Context) -> None:
        """Return stats about the bot's code."""
        total = 0
        file_amount = 0
        list_of_files = []

        for filepath, _, files in os.walk("bot"):
            for name in files:
                if name.endswith(".py"):
                    file_lines = 0
                    file_amount += 1
                    with codecs.open(
                            "./" + str(pathlib.PurePath(filepath, name)), "r",
                            "utf-8") as file:
                        for _, line in enumerate(file):
                            if line.strip().startswith("#") or len(
                                    line.strip()) == 0:
                                pass
                            else:
                                total += 1
                                file_lines += 1

                    final_path = filepath + os.path.sep + name
                    list_of_files.append(
                        final_path.split("." + os.path.sep)[-1] +
                        f" : {file_lines} lines")

        paginator = Paginator(max_size=2048, )

        for line in list_of_files:
            paginator.add_line(line)

        pages = menus.MenuPages(
            source=CodeInfoSource(
                f"{self.bot.user.name}'s structure",
                f"I am made of {total} lines of Python, spread across {file_amount} files !",
                paginator.pages,
                per_page=1,
            ),
            clear_reactions_after=True,
        )
        await pages.start(ctx)
예제 #16
0
파일: embeds.py 프로젝트: fuyu78/dpytools
def paginate_to_embeds(
        title: str,
        description: str,
        max_size: int = 2000,
        prefix: Optional[str] = "",
        suffix: Optional[str] = "",
        color: Union[discord.Color, int, None] = None) -> List[Embed]:
    """
    Facilitates sequential embed menus.
    Returned embeds share title, have description split at :max_length: and are added index/pages at footer to keep
    track of pages.

    Args:
        title: Shared by all embeds
        description: String to be split at :max_length: per embed.
        max_size: Maximum amount of characters per embed. Discord's limit is 2000.
        prefix: Defaults to "" it will be appended at the start of the description of each embed.
                Useful for codeblocks (use triple back quotes).
        suffix: Same as :prefix: but at the end of the text.
        color: color to use for the embed. Accepts int (decimal or hex) or discord.Color/discord.Colour.

    Returns:
        List[Embed]
    """
    embeds = []
    to_list = description.split("\n")
    paginator = Paginator(prefix=prefix, suffix=suffix, max_size=max_size)
    for line in to_list:
        paginator.add_line(line)
    for i, page in enumerate(paginator.pages):
        embeds.append(
            Embed(
                title=title,
                description=page,
                color=color,
            ).set_footer(text=f"page: {i + 1}/{len(paginator.pages)}"))
    return embeds
예제 #17
0
async def list_users(ctx: CommandContext, *, role: Role):
    author: Member = ctx.author
    roles: List[Role] = author.roles
    role_ids: Set[int] = set([role.id for role in roles])
    admin: bool = len(role_ids.intersection(config.admin_roles))
    if not admin and not check_is_mentor(author, role):
        return await ctx.send(
            embed=Embed(
                title='Missing permissions',
                color=Color.red(),
                description='You are neither an admin nor a mentor for this role.'))
    paginator = Paginator(prefix='', suffix='')
    for user in get_members_with_role(role):
        paginator.add_line(f'{user} - {user.mention}')
    for page in paginator.pages:
        await ctx.send(
            embed=Embed(
                title=f'Users with the role @{role.name}',
                description=page))
    if len(paginator.pages) == 0:
        await ctx.send(
            embed=Embed(
                title=f'Users with the role @{role.name}',
                description='No users found.'))
예제 #18
0
async def paginate(ctx,
                   i,
                   start='',
                   prefix='',
                   kprefix='`',
                   ksuffix='`\n',
                   eprefix='```\n',
                   ejoin=' ',
                   esuffix='\n```',
                   suffix='',
                   end=''):
    paginator = Paginator(prefix=prefix, suffix=suffix)
    messages = []
    i = copy.deepcopy(i)

    if start:
        paginator.add_line(start + ('' if type(i) is not dict else '\n'))

    if type(i) in (tuple, list, set):
        if not i:
            i = (' ')
        paginator.add_line(eprefix + f'{ejoin}'.join(sorted(i)) + esuffix)
    elif type(i) is dict:
        if not i:
            i = {' ': ' '}
        for k, e in sorted(i.items()):
            paginator.add_line(kprefix + k + ksuffix + eprefix +
                               f'{ejoin}'.join(e) + esuffix)

    if end:
        paginator.add_line(end)

    for page in paginator.pages:
        messages.append(await ctx.send(page))

    return messages
예제 #19
0
    async def invite(self, ctx):
        '''Posts invite links for Hawking, and its Discord server.'''
        
        self.dynamo_db.put(dynamo_manager.CommandItem(
            ctx, ctx.message.content, inspect.currentframe().f_code.co_name, True))

        paginator = Paginator()

        paginator.add_line('Add Hawking to your server with this link: https://discordapp.com/oauth2/authorize?client_id=334894709292007424&scope=bot&permissions=53803072')
        paginator.close_page()
        paginator.add_line('Also, join my Discord server via: https://discord.gg/JJqx8C4')
        paginator.add_line('- Help me test unstable versions of Hawking and my other bots')
        paginator.add_line('- Let me know if something\'s broken')
        paginator.add_line('- Post suggestions for improving Hawking and my other bots')
        paginator.add_line('- Got a funny phrase you want added? Suggest it in there!')
        paginator.close_page()

        await self.send_pages(ctx, paginator)
예제 #20
0
class MyHelpFormatter(HelpFormatter):
    def _add_subcommands_to_page(self, max_width, commands, mobile_format):
        for name, command in commands:
            if name in command.aliases:
                # skip aliases
                continue
            if mobile_format:
                entry = '  {0}'.format(name)
            else:
                entry = '  {0:<{width}} {1}'.format(name,
                                                    command.short_doc,
                                                    width=max_width)
            shortened = self.shorten(entry)
            self._paginator.add_line(shortened)

    def format_help_for(self, context, command_or_bot, mobileFormat):
        self.context = context
        self.command = command_or_bot
        return self.format(mobileFormat)

    def format(self, mobileFormat):
        """Handles the actual behaviour involved with formatting.
        To change the behaviour, this method should be overridden.
        Returns
        --------
        list
                        A paginated output of the help command.
        """
        self._paginator = Paginator()

        # we need a padding of ~80 or so

        description = self.command.description if not self.is_cog(
        ) else inspect.getdoc(self.command)

        if description:
            # <description> portion
            self._paginator.add_line(description, empty=True)

        if isinstance(self.command, Command):
            # <signature portion>
            signature = self.get_command_signature()
            self._paginator.add_line(signature, empty=True)

            # <long doc> section
            if self.command.help:
                self._paginator.add_line(self.command.help, empty=True)
            elif self.command.brief:
                self._paginator.add_line(self.command.brief, empty=True)

            # end it here if it's just a regular command
            if not self.has_subcommands():
                self._paginator.close_page()
                return self._paginator.pages

        max_width = self.max_name_size

        def category(tup):
            cog = tup[1].cog_name
            # we insert the zero width space there to give it approximate
            # last place sorting position.
            return cog + ':' if cog is not None else '\u200bNo Category:'

        if self.is_bot():
            data = sorted(self.filter_command_list(), key=category)
            for category, commands in itertools.groupby(data, key=category):
                # there simply is no prettier way of doing this.
                commands = list(commands)
                if len(commands) > 0:
                    self._paginator.add_line(category)

                self._add_subcommands_to_page(max_width, commands,
                                              mobileFormat)
        else:
            self._paginator.add_line('Commands:')
            self._add_subcommands_to_page(max_width,
                                          self.filter_command_list(),
                                          mobileFormat)

        if not mobileFormat:
            # add the ending note
            self._paginator.add_line()
            ending_note = self.get_ending_note()
            self._paginator.add_line(ending_note)
        return self._paginator.pages
예제 #21
0
 def assemblePage(self):
     p = Paginator()
     for line in self.grid:
         p.add_line(''.join(line))
     return p.pages
예제 #22
0
class ClipsterHelpCommand(commands.DefaultHelpCommand):
    @property
    def max_name_size(self):
        """
        int : Returns the largest name length of the bot's commands.
        """

        size = 0
        try:
            commands = self.context.bot.commands
            if commands:
                size = max(
                    map(
                        lambda c: len(c.name)
                        if self.show_hidden or not c.hidden else 0, commands))
        except AttributeError as e:
            size = 15

        return size + len(CONFIG_OPTIONS.get('activation_string', ''))

    def dump_header_boilerplate(self):
        """
        Adds the header boilerplate text (Description, Version, How to activate) to the paginator
        """
        self.paginator.add_line(CONFIG_OPTIONS.get("description"), empty=False)

        ## Append the version info into the help screen
        version_note = "Clipster version: {}".format(
            CONFIG_OPTIONS.get("version", "Beta"))
        self.paginator.add_line(version_note, empty=True)

        ## Append (additional) activation note
        activation_note = "Activate with the '{0}' character (ex. '{0}help')".format(
            self.clean_prefix)
        self.paginator.add_line(activation_note, empty=True)

    def dump_footer_boilerplate(self, categories):
        """
        Adds the footer boilerplate text (Using the help interface) to the paginator
        """
        # Ending note logic from HelpFormatter.format
        command_name = self.context.invoked_with
        ending_note = "Check out the other clip categories! Why not try '{0}{1} {2}'?".format(
            self.clean_prefix, command_name, random.choice(categories))
        self.paginator.add_line(ending_note)

    def dump_commands(self):
        """
        Adds information about the bot's available commands (unrelated to the clip commands) to the paginator
        """
        self.paginator.add_line("Basic Commands:")
        for command in sorted(self.context.bot.commands,
                              key=lambda cmd: cmd.name):
            if ((command.module != "clips" or command.name == 'random'
                 or command.name == 'find') and not command.hidden):
                entry = '  {0}{1:<{width}} {2}'.format(
                    CONFIG_OPTIONS.get('activation_string', ''),
                    command.name,
                    command.short_doc,
                    width=self.max_name_size)
                self.paginator.add_line(self.shorten_text(entry))
        self.paginator.add_line()

    def dump_clip_group(self, clip_group, width=None):
        """
        Adds information about the supplied clip group (Group name, tabbed list of clip commands) to the paginator
        """
        if (not width):
            width = self.max_name_size

        self.paginator.add_line(clip_group.name + ":")
        for name, clip in sorted(clip_group.clips.items(),
                                 key=lambda tup: tup[0]):
            entry = '  {0}{1:<{width}} {2}'.format(CONFIG_OPTIONS.get(
                'activation_string', ''),
                                                   name,
                                                   clip.kwargs.get("help"),
                                                   width=width)
            self.paginator.add_line(self.shorten_text(entry))
        self.paginator.add_line()

    def dump_clip_categories(self, clip_groups, width=None):
        """
        Adds information about the bot's clip categories, that the user can drill down into with the help interface,
        to the paginator
        """
        if (not width):
            width = self.max_name_size

        help_string = '{}help '.format(
            CONFIG_OPTIONS.get('activation_string', ''))
        width += len(help_string)

        self.paginator.add_line('Clip Category Help:')
        for name, group in sorted(clip_groups.items(), key=lambda tup: tup[0]):
            ## Don't insert empty groups
            if (len(group.clips) > 0):
                entry = '  {0}{1:<{width}} {2}'.format(help_string,
                                                       group.key,
                                                       group.description,
                                                       width=width)
                self.paginator.add_line(self.shorten_text(entry))
        self.paginator.add_line()

    async def send_clip_category_help(self, command):
        '''Sends help information for a given command representing a Clip Category'''

        ## Initial setup
        max_width = self.max_name_size
        clip_groups = self.context.bot.get_cog("Clips").clip_groups

        self.dump_header_boilerplate()
        # self.dump_commands()
        self.dump_clip_group(clip_groups[command.name], max_width)
        self.dump_clip_categories(clip_groups, max_width)
        self.dump_footer_boilerplate(list(clip_groups.keys()))

        self.paginator.close_page()
        await self.send_pages()

    async def send_bot_help(self, mapping):
        '''The main bot help command (overridden)'''

        ## Initial setup
        self.paginator = Paginator()
        clip_groups = self.context.bot.get_cog("Clips").clip_groups

        self.dump_header_boilerplate()

        ## Dump the non-clip commands
        self.dump_commands()

        ## Dump the base clip commands
        clips_group = clip_groups["internet"]
        if (clips_group):
            self.dump_clip_group(clips_group)

        ## Dump the names of the additional clips. Don't print their commands because that's too much info.
        ## This is a help interface, not a CVS receipt
        self.dump_clip_categories(clip_groups)

        self.dump_footer_boilerplate(list(clip_groups.keys()))

        await self.send_pages()

    async def send_command_help(self, command):
        '''Help interface for the commands themselves (Overridden)'''

        ## Initial setup
        self.paginator = Paginator()
        clip_groups = self.context.bot.get_cog("Clips").clip_groups

        ## Is the help command a category? If so only dump the relv
        command_str = command.__str__()
        if (command.name in clip_groups):
            await self.send_clip_category_help(command)
            return

        # <signature> section
        signature = self.get_command_signature(command)
        self.paginator.add_line(signature, empty=True)

        # <long doc> section
        help_section = command.help
        if help_section:
            if (len(help_section) > self.paginator.max_size):
                for line in help_section.splitlines():
                    self.paginator.add_line(line)
            else:
                self.paginator.add_line(help_section, empty=True)

        self.paginator.close_page()
        await self.send_pages()
예제 #23
0
class Formatter(HelpFormatter):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def _add_subcommands_to_page(self, max_width: int, commands: list):
        """
        basically the same function from d.py but changed:
        - to make the helptext appear as a comment
        - to change the indentation to the PEP8 standard: 4 spaces
        """

        for name, command in commands:
            if name in command.aliases:
                # skip aliases
                continue

            entry = "    {0}{1:<{width}} # {2}".format(HELP_PREFIX, name, command.short_doc, width=max_width)
            shortened = self.shorten(entry)
            self._paginator.add_line(shortened)

    async def format(self):
        """
        rewritten help command to make it more python-y

        example of specific command:
        async def <command>(ctx, <args>):
            \"""
            <help text>
            \"""
            await do_<command>(ctx, <args>)

        example of standard help page:
        class <cog1>:
            bot.<command1>() # <command1 help>
        class <cog2>:
            bot.<command2>() # <command2 help>

        # <ending help note>
        """

        self._paginator = Paginator(prefix="```py")

        if isinstance(self.command, Command):
            # strip the command off bot. and ()
            stripped_command = self.command.name.replace(HELP_PREFIX, "").replace("()", "")

            # get the args using the handy inspect module
            argspec = getfullargspec(self.command.callback)
            arguments = formatargspec(*argspec)
            for arg, annotation in argspec.annotations.items():
                # remove module name to only show class name
                # discord.ext.commands.context.Context -> Context
                arguments = arguments.replace(f"{annotation.__module__}.", "")

            # manipulate the argspec to make it valid python when 'calling' the do_<command>
            args_no_type_hints = argspec.args
            for kwarg in argspec.kwonlyargs:
                args_no_type_hints.append("{0}={0}".format(kwarg))
            args_no_type_hints = "({0})".format(", ".join(args_no_type_hints))

            # remove self from the args
            arguments = arguments.replace("self, ", "")
            args_no_type_hints = args_no_type_hints.replace("self, ", "")

            # indent every line in the help message
            helptext = "\n    ".join(self.command.help.split("\n"))

            # prepare the different sections of the help output, and add them to the paginator
            definition = f"async def {stripped_command}{arguments}:"
            doc_elems = [
                '"""',
                helptext,
                '"""'
            ]

            docstring = ""
            for elem in doc_elems:
                docstring += f'    {elem}\n'

            invocation = f"    await do_{stripped_command}{args_no_type_hints}"
            self._paginator.add_line(definition)
            self._paginator.add_line(docstring)
            self._paginator.add_line(invocation)

            return self._paginator.pages

        max_width = self.max_name_size

        def category_check(tup):
            cog = tup[1].cog_name
            # zero width character to make it appear last when put in alphabetical order
            return cog if cog is not None else "\u200bNoCategory"

        command_list = await self.filter_command_list()
        data = sorted(command_list, key=category_check)

        for category, commands in itertools.groupby(data, key=category_check):
            commands = sorted(commands)
            if len(commands) > 0:
                self._paginator.add_line(f"class {category}:")
                self._add_subcommands_to_page(max_width, commands)

        self._paginator.add_line()
        ending_note = self.get_ending_note()
        # make the ending note appear as comments
        ending_note = "# "+ending_note.replace("\n", "\n# ")
        self._paginator.add_line(ending_note)

        return self._paginator.pages
예제 #24
0
파일: over.py 프로젝트: EJH2/Bot
class HelpFormatter(HelpF):
    """Custom override for the default help command"""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._paginator = None

    async def format(self):
        """Handles the actual behaviour involved with formatting.

        To change the behaviour, this method should be overridden.

        Returns
        --------
        list
            A paginated output of the help command.
        """
        self._paginator = Paginator()

        # we need a padding of ~80 or so

        description = self.command.description if not self.is_cog() else inspect.getdoc(self.command)

        if description:
            # <description> portion
            self._paginator.add_line(description, empty=True)

        if isinstance(self.command, Command):
            # <signature portion>
            if self.command.params.get("args", None) and type(self.command.params['args'].annotation) == ArgPC:
                self.command.usage = create_help(self.command, self.command.params['args'].annotation.parser)
            signature = self.get_command_signature()
            self._paginator.add_line(signature, empty=True)

            # <long doc> section
            if self.command.help:
                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._paginator.close_page()
                return self._paginator.pages

        max_width = self.max_name_size

        def category(tup):
            """Splits the help command into categories for easier readability"""
            cog = tup[1].cog_name
            # we insert the zero width space there to give it approximate
            # last place sorting position.
            return cog + ':' if cog is not None else '\u200bNo Category:'

        filtered = await self.filter_command_list()
        if self.is_bot():
            data = sorted(filtered, key=category)
            for category, commands in itertools.groupby(data, key=category):
                # there simply is no prettier way of doing this.
                commands = sorted(commands)
                if len(commands) > 0:
                    self._paginator.add_line(category)

                self._add_subcommands_to_page(max_width, commands)
        else:
            filtered = sorted(filtered)
            if filtered:
                self._paginator.add_line('Commands:')
                self._add_subcommands_to_page(max_width, filtered)

        # add the ending note
        self._paginator.add_line()
        ending_note = self.get_ending_note()
        self._paginator.add_line(ending_note)
        return self._paginator.pages
예제 #25
0
class HuskyHelpFormatter(DefaultHelpCommand):
    """
    A modified help formatter that does some things differently.
    """
    def __init__(self, **options):
        self.asciidoc_prefix = "```asciidoc"
        self.paginator = Paginator(prefix=self.asciidoc_prefix)
        self.commands_heading = "Commands\n--------"

        super().__init__(paginator=self.paginator,
                         commands_heading=self.commands_heading,
                         **options)

    def get_command_signature(self, command):
        parent = command.full_parent_name
        alias = command.name if not parent else parent + ' ' + command.name
        signature = command.signature + " " if command.signature else ""

        return '%s%s %s:: **%s**' % (self.clean_prefix, alias, signature,
                                     command.brief)

    def add_indented_commands(self, commands, *, heading, max_size=None):
        if not commands:
            return

        self.paginator.add_line(heading)
        max_size = max_size or self.get_max_size(commands)

        # noinspection PyProtectedMember
        get_width = discord.utils._string_width

        for command in commands:
            name = command.name
            width = max_size - (get_width(name) - len(name))
            entry = '{0}{1:<{width}} :: {2}'.format(self.indent * ' ',
                                                    name,
                                                    command.short_doc,
                                                    width=width)
            self.paginator.add_line(self.shorten_text(entry))

    async def prepare_help_command(self, ctx, command):
        # The more upstream changes break my help formatter, the more I think I'm insane for making
        # the help formatter so terrible.
        #
        # Oh well.
        self.context = ctx
        await super().prepare_help_command(ctx, command)

    async def send_bot_help(self, mapping):
        ctx = self.context
        bot = ctx.bot

        if bot.description:
            # <description> portion
            self.paginator.add_line(bot.description, empty=True)

        no_category = '\u200b{0.no_category}:'.format(self)

        def get_category(command):
            cog = command.cog
            name = cog.qualified_name if cog is not None else no_category
            return name + "\n" + "-" * len(name)

        filtered = await self.filter_commands(bot.commands,
                                              sort=True,
                                              key=get_category)
        max_size = self.get_max_size(filtered)
        to_iterate = itertools.groupby(filtered, key=get_category)

        # Now we can add the commands to the page.
        for category, commands in to_iterate:
            commands = sorted(
                commands,
                key=lambda c: c.name) if self.sort_commands else list(commands)
            self.add_indented_commands(commands,
                                       heading=category,
                                       max_size=max_size)

        note = self.get_ending_note()
        if note:
            self.paginator.add_line()
            self.paginator.add_line(note)

        await self.send_pages()

    def add_command_formatting(self, command):
        """A utility function to format the non-indented block of commands and groups.

        Parameters
        ------------
        command: :class:`Command`
            The command to format.
        """

        if command.description:
            self.paginator.add_line(command.description, empty=True)

        signature = self.get_command_signature(command)
        self.paginator.add_line(signature, empty=True)

        if command.help:
            for line in command.help.splitlines():
                if "<!nodoc>" in line:
                    continue
                self.paginator.add_line(line)
            self.paginator.add_line()
예제 #26
0
class DogbotHelpFormatter(HelpFormatter):
    def get_ending_note(self):
        if self.context.bot.is_private:
            return super().get_ending_note()

        note = super().get_ending_note()
        invite = self.context.bot.cfg['bot']['woof']['invite']
        return note if not self.is_bot() else note + '\nNeed help? Visit the support server: ' + invite

    def format_help(self, description):
        # for each paragraph in the description, replace a newline with a space.
        return '\n\n'.join(para.replace('\n', ' ') for para in description.split('\n\n'))

    async def format(self):
        """ A modified copy of Discord.py rewrite's vanilla HelpFormatter.format(). """
        self._paginator = Paginator()

        # we need a padding of ~80 or so
        description = self.command.description if not self.is_cog() else inspect.getdoc(self.command)

        if description:
            # <description> portion
            self._paginator.add_line(description, empty=True)

        if isinstance(self.command, Command):
            # <signature portion>
            signature = self.get_command_signature()
            self._paginator.add_line(signature, empty=True)

            # <long doc> section
            if self.command.help:
                self._paginator.add_line(self.format_help(self.command.help), empty=True)

            # end it here if it's just a regular command
            if not self.has_subcommands():
                self._paginator.close_page()
                return self._paginator.pages

        max_width = self.max_name_size

        def category(tup):
            cog = tup[1].cog_name
            # we insert the zero width space there to give it approximate
            # last place sorting position.
            return cog + ':' if cog is not None else '\u200bCommands:'

        filtered = await self.filter_command_list()
        if self.is_bot():
            data = sorted(filtered, key=category)
            for category, commands in itertools.groupby(data, key=category):
                # there simply is no prettier way of doing this.
                commands = sorted(commands)
                if len(commands) > 0:
                    self._paginator.add_line(category)

                self._add_subcommands_to_page(max_width, commands)
        else:
            filtered = sorted(filtered)
            if filtered:
                self._paginator.add_line('Commands:')
                self._add_subcommands_to_page(max_width, filtered)

        # add the ending note
        self._paginator.add_line()
        ending_note = self.get_ending_note()
        self._paginator.add_line(ending_note)
        return self._paginator.pages
예제 #27
0
class NewHelpFormatter(commands.HelpFormatter):
    """
    Much of the code in the following functions has been taken from https://github.com/Rapptz/discord.py and modified to suit the purposes of this bot.
    """
    def get_max_alias_length(self):
        """Returns the longest list of aliases possible for formatting purposes."""
        max_len = 0

        def category(tup):
            cog = tup[1].cog_name
            # we insert the zero width space there to give it approximate
            # last place sorting position.
            return cog + ':' if cog is not None else '\u200bUncategorized:'

        if self.is_bot():
            data = sorted(self.filter_command_list(), key=category)
            for category, commands in itertools.groupby(data, key=category):
                commands = list(commands)
                if len(commands) > 0:
                    for name, command in commands:
                        aliases = '|'.join(command.aliases)
                        if len(aliases) > max_len:
                            max_len = len(aliases)

        return (max_len)

    def _add_subcommands_to_page(self, max_width, max_alias_width, commands):
        """An overridden function that changes up the formatting of commands that are to be added to a paginator."""
        for name, command in commands:
            if name in command.aliases:
                # skip aliases
                continue

            aliases = '|'.join(command.aliases)

            if len(aliases) > 0:
                entry = '  {0:<{width}} [{2:<{alias_width}} {1}'.format(
                    name,
                    command.short_doc,
                    aliases + "]",
                    width=max_width,
                    alias_width=max_alias_width + 3)
            else:
                entry = '  {0:<{width}} {2:<{alias_width}} {1}'.format(
                    name,
                    command.short_doc,
                    " ",
                    width=max_width,
                    alias_width=max_alias_width + 4)

            shortened = self.shorten(entry)
            self._paginator.add_line(shortened)

    def format(self):
        """An overridden function that adds a few little aesthetic changes to the default help commands"""
        self._paginator = Paginator()

        description = self.command.description if not self.is_cog(
        ) else inspect.getdoc(self.command)

        if description:
            # <description> portion
            self._paginator.add_line(description, empty=True)

        if isinstance(self.command, Command):
            # <signature portion>
            signature = self.get_command_signature()
            self._paginator.add_line(signature, empty=True)

            # <long doc> section
            if self.command.help:
                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._paginator.close_page()
                return self._paginator.pages

        max_width = self.max_name_size

        def category(tup):
            cog = tup[1].cog_name
            # we insert the zero width space there to give it approximate
            # last place sorting position.
            return cog + ':' if cog is not None else '\u200bUncategorized:'

        max_alias_length = self.get_max_alias_length()

        key_line = '  {0:<{width}} {2:<{alias_width}} {1}'.format(
            "Command",
            "Description",
            "Aliases",
            width=max_width,
            alias_width=max_alias_length + 4)
        self._paginator.add_line(key_line)
        bar_line = '{0:-<{key_line_len}}'.format("", key_line_len=self.width)
        self._paginator.add_line(bar_line)

        if self.is_bot():
            data = sorted(self.filter_command_list(), key=category)
            for category, commands in itertools.groupby(data, key=category):
                # there simply is no prettier way of doing this.
                commands = list(commands)
                if len(commands) > 0:
                    self._paginator.add_line(category)

                self._add_subcommands_to_page(max_width, max_alias_length,
                                              commands)
        else:
            self._paginator.add_line('Commands:')
            self._add_subcommands_to_page(max_width,
                                          self.filter_command_list())

            # add the ending note
        self._paginator.add_line()
        ending_note = self.get_ending_note()
        self._paginator.add_line(ending_note)
        return self._paginator.pages
예제 #28
0
class CustomHelpFormatter(HelpFormatter):

    def __init__(self, show_hidden=False, show_check_failure=False, width=80):
        self.width = width
        self.show_hidden = show_hidden
        self.show_check_failure = show_check_failure

    def format(self):
        """Handles the actual behaviour involved with formatting.

        To change the behaviour, this method should be overridden.

        Returns
        --------
        list
            A paginated output of the help command.
        """
        self._paginator = Paginator()

        # we need a padding of ~80 or so

        description = self.command.description if not self.is_cog() else inspect.getdoc(self.command)

        if description:
            # <description> portion
            self._paginator.add_line(description, empty=True)

        if isinstance(self.command, Command):
            # <signature portion>
            signature = self.get_command_signature()
            self._paginator.add_line(signature, empty=True)

            # <long doc> section
            if self.command.help:
                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._paginator.close_page()
                return self._paginator.pages

        max_width = self.max_name_size

        def category(tup):
            cog = tup[1].cog_name
            # we insert the zero width space there to give it approximate
            # last place sorting position.
            return cog + ':' if cog is not None else '\u200bNo Category:'

        if self.is_bot():
            data = sorted(self.filter_command_list(), key=category)
            for category, commands in itertools.groupby(data, key=category):
                # there simply is no prettier way of doing this.
                if category == '\u200bNo Category:':
                    continue
                commands = list(commands)
                if len(commands) > 0:
                    fmt = "{0}\n  {1:>{width}}"
                    doc = inspect.getdoc(commands[0][1].instance)
                    if doc:
                        self._paginator.add_line('')
                        self._paginator.add_line(fmt.format(category, doc, width=max_width))
                    else:
                        self._paginator.add_line('')
                        self._paginator.add_line(fmt.format(category, 'No Description.', width=max_width))


        else:
            self._paginator.add_line('Commands:')
            self._add_subcommands_to_page(max_width, self.filter_command_list())

        # add the ending note
        self._paginator.add_line()
        ending_note = self.get_ending_note()
        self._paginator.add_line(ending_note)
        return self._paginator.pages
예제 #29
0
class NabHelpFormat(HelpFormatter):
    def get_ending_note(self):
        command_name = self.context.invoked_with
        if self.has_subcommands() and not self.is_bot():
            return "Type {0} <subcommand> for more info on a command.".format(
                self.context.message.content)
        else:
            return "Type {0}{1} <command> for more info on a command.\n" \
               "You can also type {0}{1} category for more info on a category.".format(self.clean_prefix, command_name)

    async def format(self):
        """Handles the actual behaviour involved with formatting.
        To change the behaviour, this method should be overridden.
        Returns
        --------
        list
            A paginated output of the help command.
        """
        self._paginator = Paginator()

        # we need a padding of ~80 or so

        description = self.command.description if not self.is_cog(
        ) else inspect.getdoc(self.command)

        if description:
            # <description> portion
            self._paginator.add_line(description, empty=True)

        if isinstance(self.command, Command):
            # <signature portion>
            signature = self.get_command_signature()
            self._paginator.add_line(signature, empty=True)

            # <long doc> section
            if self.command.help:
                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._paginator.close_page()
                return self._paginator.pages

        max_width = self.max_name_size

        def category(tup):
            cog = tup[1].cog_name
            # we insert the zero width space there to give it approximate
            # last place sorting position.
            return cog + ':' if cog is not None else '\u200bNo Category:'

        filtered = await self.filter_command_list()
        if self.is_bot():
            data = sorted(filtered, key=category)
            for category, commands in itertools.groupby(data, key=category):
                # there simply is no prettier way of doing this.
                commands = sorted(commands)
                if len(commands) > 0:
                    self._paginator.add_line(category)

                self._add_subcommands_to_page(max_width, commands)
        else:
            filtered = sorted(filtered)
            self._add_subcommands_to_page(max_width,
                                          self.filter_command_list())
            if filtered:
                self._paginator.add_line(
                    'Subcommands:' if self.has_subcommands() else 'Commands:')
                self._add_subcommands_to_page(max_width, filtered)

        # add the ending note
        self._paginator.add_line()
        ending_note = self.get_ending_note()
        self._paginator.add_line(ending_note)
        return self._paginator.pages
예제 #30
0
class KiaraFormatter(HelpFormatter):
    def __init__(self):
        super().__init__()

    def get_ending_note(self):
        return ''

    @asyncio.coroutine
    def format(self):
        """Handles the actual behaviour involved with formatting.

        To change the behaviour, this method should be overridden.

        Returns
        --------
        list
            A paginated output of the help command.
        """
        self._paginator = Paginator(prefix='```md')

        # we need a padding of ~80 or so

        description = self.command.description if not self.is_cog(
        ) else inspect.getdoc(self.command)

        if description:
            # <description> portion
            self._paginator.add_line(f'[ {description} ][-!`.]', empty=True)

        if isinstance(self.command, Command):
            # <long doc> section
            if self.command.help:
                self._paginator.add_line(self.command.help, empty=True)

            # <signature portion>
            signature = self.get_command_signature()
            self._paginator.add_line(f"<Usage>")
            self._paginator.add_line(f"{signature}", empty=True)

            # end it here if it's just a regular command
            if not self.has_subcommands():
                self._paginator.close_page()
                return self._paginator.pages

        max_width = self.max_name_size

        def category(tup):
            cog = tup[1].cog_name
            # we insert the zero width space there to give it approximate
            # last place sorting position.
            return f'<{cog}>' if cog is not None else '<Other>'

        filtered = yield from self.filter_command_list()
        if self.is_bot():
            data = sorted(filtered, key=category)
            for category, commands in itertools.groupby(data, key=category):
                # there simply is no prettier way of doing this.
                commands = sorted(commands)
                if len(commands) > 0:
                    self._paginator.add_line(category)

                self._add_subcommands_to_page(max_width, commands)
        else:
            filtered = sorted(filtered)
            if filtered:
                self._paginator.add_line('<Commands>')
                self._add_subcommands_to_page(max_width, filtered)

        # add the ending note
        self._paginator.add_line()
        ending_note = self.get_ending_note()
        self._paginator.add_line(ending_note)
        return self._paginator.pages

    def get_command_signature(self):
        """Retrieves the signature portion of the help page."""
        prefix = self.clean_prefix
        cmd = self.command
        return prefix + signature(cmd)

    def _add_subcommands_to_page(self, max_width, commands):
        for name, command in commands:
            if name in command.aliases:
                # skip aliases
                continue

            entry = ' {0:>{width}} : {1}'.format(name,
                                                 command.short_doc,
                                                 width=max_width)
            shortened = self.shorten(entry)
            self._paginator.add_line(shortened)