예제 #1
0
    async def build_pages(self) -> None:
        """Builds the list of content pages to be paginate through in the help message, as a list of str."""
        # Use LinePaginator to restrict embed line height
        paginator = LinePaginator(prefix='',
                                  suffix='',
                                  max_lines=self._max_lines)

        prefix = constants.Bot.prefix

        # show signature if query is a command
        if isinstance(self.query, commands.Command):
            signature = self._get_command_params(self.query)
            parent = self.query.full_parent_name + ' ' if self.query.parent else ''
            paginator.add_line(f'**```{prefix}{parent}{signature}```**')

            # show command aliases
            aliases = ', '.join(f'`{a}`' for a in self.query.aliases)
            if aliases:
                paginator.add_line(f'**Can also use:** {aliases}\n')

            if not await self.query.can_run(self._ctx):
                paginator.add_line('***You cannot run this command.***\n')

        # show name if query is a cog
        if isinstance(self.query, Cog):
            paginator.add_line(f'**{self.query.name}**')

        if self.description:
            paginator.add_line(f'*{self.description}*')

        # list all children commands of the queried object
        if isinstance(self.query, (commands.GroupMixin, Cog)):

            # remove hidden commands if session is not wanting hiddens
            if not self._show_hidden:
                filtered = [c for c in self.query.commands if not c.hidden]
            else:
                filtered = self.query.commands

            # if after filter there are no commands, finish up
            if not filtered:
                self._pages = paginator.pages
                return
예제 #2
0
    async def build_pages(self):
        """
        Builds the list of content pages to be paginated through in the
        help message.

        Returns
        -------
        list[str]
        """

        # Use LinePaginator to restrict embed line height
        paginator = LinePaginator(prefix='',
                                  suffix='',
                                  max_lines=self._max_lines)

        prefix = constants.Bot.prefix

        # show signature if query is a command
        if isinstance(self.query, commands.Command):
            signature = self._get_command_params(self.query)
            parent = self.query.full_parent_name + ' ' if self.query.parent else ''
            paginator.add_line(f'**```{prefix}{parent}{signature}```**')

            # show command aliases
            aliases = ', '.join(f'`{a}`' for a in self.query.aliases)
            if aliases:
                paginator.add_line(f'**Can also use:** {aliases}\n')

            if not await self.query.can_run(self._ctx):
                paginator.add_line('***You cannot run this command.***\n')

        # show name if query is a cog
        if isinstance(self.query, Cog):
            paginator.add_line(f'**{self.query.name}**')

        if self.description:
            paginator.add_line(f'*{self.description}*')

        # list all children commands of the queried object
        if isinstance(self.query, (commands.GroupMixin, Cog)):

            # remove hidden commands if session is not wanting hiddens
            if not self._show_hidden:
                filtered = [c for c in self.query.commands if not c.hidden]
            else:
                filtered = self.query.commands

            # if after filter there are no commands, finish up
            if not filtered:
                self._pages = paginator.pages
                return

            # set category to Commands if cog
            if isinstance(self.query, Cog):
                grouped = (('**Commands:**', self.query.commands), )

            # set category to Subcommands if command
            elif isinstance(self.query, commands.Command):
                grouped = (('**Subcommands:**', self.query.commands), )

                # don't show prefix for subcommands
                prefix = ''

            # otherwise sort and organise all commands into categories
            else:
                cat_sort = sorted(filtered, key=self._category_key)
                grouped = itertools.groupby(cat_sort, key=self._category_key)

            # process each category
            for category, cmds in grouped:
                cmds = sorted(cmds, key=lambda c: c.name)

                # if there are no commands, skip category
                if len(cmds) == 0:
                    continue

                cat_cmds = []

                # format details for each child command
                for command in cmds:

                    # skip if hidden and hide if session is set to
                    if command.hidden and not self._show_hidden:
                        continue

                    # see if the user can run the command
                    strikeout = ''
                    can_run = await command.can_run(self._ctx)
                    if not can_run:
                        # skip if we don't show commands they can't run
                        if self._only_can_run:
                            continue
                        strikeout = '~~'

                    signature = self._get_command_params(command)
                    info = f"{strikeout}**`{prefix}{signature}`**{strikeout}"

                    # handle if the command has no docstring
                    if command.short_doc:
                        cat_cmds.append(f'{info}\n*{command.short_doc}*')
                    else:
                        cat_cmds.append(f'{info}\n*No details provided.*')

                # state var for if the category should be added next
                print_cat = 1
                new_page = True

                for details in cat_cmds:

                    # keep details together, paginating early if it won't fit
                    lines_adding = len(details.split('\n')) + print_cat
                    if paginator._linecount + lines_adding > self._max_lines:
                        paginator._linecount = 0
                        new_page = True
                        paginator.close_page()

                        # new page so print category title again
                        print_cat = 1

                    if print_cat:
                        if new_page:
                            paginator.add_line('')
                        paginator.add_line(category)
                        print_cat = 0

                    paginator.add_line(details)

        # save organised pages to session
        self._pages = paginator.pages
예제 #3
0
파일: __init__.py 프로젝트: surister/bot
async def disambiguate(ctx: Context,
                       entries: List[str],
                       *,
                       timeout: float = 30,
                       per_page: int = 20,
                       empty: bool = False,
                       embed: discord.Embed = None):
    """
    Has the user choose between multiple entries in case one could not be chosen automatically.

    This will raise a BadArgument if entries is empty, if the disambiguation event times out,
    or if the user makes an invalid choice.

    :param ctx: Context object from discord.py
    :param entries: List of items for user to choose from
    :param timeout: Number of seconds to wait before canceling disambiguation
    :param per_page: Entries per embed page
    :param empty: Whether the paginator should have an extra line between items
    :param embed: The embed that the paginator will use.
    :return: Users choice for correct entry.
    """

    if len(entries) == 0:
        raise BadArgument('No matches found.')

    if len(entries) == 1:
        return entries[0]

    choices = (f'{index}: {entry}'
               for index, entry in enumerate(entries, start=1))

    def check(message):
        return (message.content.isdigit() and message.author == ctx.author
                and message.channel == ctx.channel)

    try:
        if embed is None:
            embed = discord.Embed()

        coro1 = ctx.bot.wait_for('message', check=check, timeout=timeout)
        coro2 = LinePaginator.paginate(choices,
                                       ctx,
                                       embed=embed,
                                       max_lines=per_page,
                                       empty=empty,
                                       max_size=6000,
                                       timeout=9000)

        # wait_for timeout will go to except instead of the wait_for thing as I expected
        futures = [asyncio.ensure_future(coro1), asyncio.ensure_future(coro2)]
        done, pending = await asyncio.wait(futures,
                                           return_when=asyncio.FIRST_COMPLETED,
                                           loop=ctx.bot.loop)

        # :yert:
        result = list(done)[0].result()

        # Pagination was canceled - result is None
        if result is None:
            for coro in pending:
                coro.cancel()
            raise BadArgument('Canceled.')

        # Pagination was not initiated, only one page
        if result.author == ctx.bot.user:
            # Continue the wait_for
            result = await list(pending)[0]

        # Love that duplicate code
        for coro in pending:
            coro.cancel()
    except asyncio.TimeoutError:
        raise BadArgument('Timed out.')

    # Guaranteed to not error because of isdigit() in check
    index = int(result.content)

    try:
        return entries[index - 1]
    except IndexError:
        raise BadArgument('Invalid choice.')