Esempio n. 1
0
    async def _format_command_category(self, paginator: LinePaginator,
                                       category: str,
                                       cmds: List[Command]) -> None:
        cmds = sorted(cmds, key=lambda c: c.name)
        cat_cmds = []
        for command in cmds:
            cat_cmds += await self._format_command(command)

        # 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)
Esempio n. 2
0
    async def _add_command_signature(self, paginator: LinePaginator) -> None:
        prefix = constants.Client.prefix

        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}```**")
        aliases = [
            f"`{alias}`" if not parent else f"`{parent} {alias}`"
            for alias in self.query.aliases
        ]
        aliases += [
            f"`{alias}`" for alias in getattr(self.query, "root_aliases", ())
        ]
        aliases = ", ".join(sorted(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")
Esempio n. 3
0
    async def build_pages(self) -> None:
        """Builds the list of content pages to be paginated 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)

        # show signature if query is a command
        if isinstance(self.query, commands.Command):
            await self._add_command_signature(paginator)

        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)):
            await self._list_child_commands(paginator)

        self._pages = paginator.pages
Esempio n. 4
0
    async def build_pages(self) -> None:
        """Builds the list of content pages to be paginated 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.Client.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}```**')

            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')

        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

            if isinstance(self.query, Cog):
                grouped = (('**Commands:**', self.query.commands), )

            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)

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

                if len(cmds) == 0:
                    continue

                cat_cmds = []

                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 = ''

                    # Patch to make the !help command work outside of #bot-commands again
                    # This probably needs a proper rewrite, but this will make it work in
                    # the mean time.
                    try:
                        can_run = await command.can_run(self._ctx)
                    except CheckFailure:
                        can_run = False

                    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)

        self._pages = paginator.pages
Esempio n. 5
0
async def disambiguate(
        ctx: Context, entries: List[str], *, timeout: float = 30,
        entries_per_page: int = 20, empty: bool = False, embed: discord.Embed = None
) -> str:
    """
    Has the user choose between multiple entries in case one could not be chosen automatically.

    Disambiguation will be canceled after `timeout` seconds.

    This will raise a BadArgument if entries is empty, if the disambiguation event times out,
    or if the user makes an invalid choice.
    """
    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: discord.Message) -> bool:
        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=entries_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.')