mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 11:18:54 -05:00
[V3 Context] Interactive sending of multiple messages (#1081)
* Interactive pages method for context * Use new methods in dev * Undo code formatting * Rename method to be more generalised * More general arg
This commit is contained in:
parent
8dcace4bfd
commit
b94bad38e7
@ -1,12 +1,15 @@
|
|||||||
"""Module for Red's Context class
|
"""
|
||||||
|
|
||||||
The purpose of this module is to allow for Red to further customise the command
|
The purpose of this module is to allow for Red to further customise the command
|
||||||
invocation context provided by discord.py.
|
invocation context provided by discord.py.
|
||||||
"""
|
"""
|
||||||
|
import asyncio
|
||||||
|
from typing import Iterable, List
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
|
||||||
|
from redbot.core.utils.chat_formatting import box
|
||||||
|
|
||||||
__all__ = ["RedContext"]
|
__all__ = ["RedContext"]
|
||||||
|
|
||||||
TICK = "\N{WHITE HEAVY CHECK MARK}"
|
TICK = "\N{WHITE HEAVY CHECK MARK}"
|
||||||
@ -20,7 +23,7 @@ class RedContext(commands.Context):
|
|||||||
This class inherits from `commands.Context <discord.ext.commands.Context>`.
|
This class inherits from `commands.Context <discord.ext.commands.Context>`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
async def send_help(self):
|
async def send_help(self) -> List[discord.Message]:
|
||||||
"""Send the command help message.
|
"""Send the command help message.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
@ -36,7 +39,7 @@ class RedContext(commands.Context):
|
|||||||
ret.append(await self.send(page))
|
ret.append(await self.send(page))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
async def tick(self):
|
async def tick(self) -> bool:
|
||||||
"""Add a tick reaction to the command message.
|
"""Add a tick reaction to the command message.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
@ -51,3 +54,60 @@ class RedContext(commands.Context):
|
|||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
async def send_interactive(self,
|
||||||
|
messages: Iterable[str],
|
||||||
|
box_lang: str=None,
|
||||||
|
timeout: int=15) -> List[discord.Message]:
|
||||||
|
"""Send multiple messages interactively.
|
||||||
|
|
||||||
|
The user will be prompted for whether or not they would like to view
|
||||||
|
the next message, one at a time. They will also be notified of how
|
||||||
|
many messages are remaining on each prompt.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
messages : `iterable` of `str`
|
||||||
|
The messages to send.
|
||||||
|
box_lang : str
|
||||||
|
If specified, each message will be contained within a codeblock of
|
||||||
|
this language.
|
||||||
|
timeout : int
|
||||||
|
How long the user has to respond to the prompt before it times out.
|
||||||
|
After timing out, the bot deletes its prompt message.
|
||||||
|
|
||||||
|
"""
|
||||||
|
messages = tuple(messages)
|
||||||
|
ret = []
|
||||||
|
|
||||||
|
more_check = lambda m: (m.author == self.author and
|
||||||
|
m.channel == self.channel and
|
||||||
|
m.content.lower() == "more")
|
||||||
|
|
||||||
|
for idx, page in enumerate(messages, 1):
|
||||||
|
if box_lang is None:
|
||||||
|
msg = await self.send(page)
|
||||||
|
else:
|
||||||
|
msg = await self.send(box(page, lang=box_lang))
|
||||||
|
ret.append(msg)
|
||||||
|
n_remaining = len(messages) - idx
|
||||||
|
if n_remaining > 0:
|
||||||
|
if n_remaining == 1:
|
||||||
|
plural = ""
|
||||||
|
is_are = "is"
|
||||||
|
else:
|
||||||
|
plural = "s"
|
||||||
|
is_are = "are"
|
||||||
|
query = await self.send(
|
||||||
|
"There {} still {} message{} remaining. "
|
||||||
|
"Type `more` to continue."
|
||||||
|
"".format(is_are, n_remaining, plural))
|
||||||
|
try:
|
||||||
|
resp = await self.bot.wait_for(
|
||||||
|
'message', check=more_check, timeout=timeout)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
await query.delete()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
await self.channel.delete_messages((query, resp))
|
||||||
|
return ret
|
||||||
|
|||||||
@ -51,6 +51,11 @@ class Dev:
|
|||||||
''.format(e, '^', type(e).__name__),
|
''.format(e, '^', type(e).__name__),
|
||||||
lang="py")
|
lang="py")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_pages(msg: str):
|
||||||
|
"""Pagify the given message for output to the user."""
|
||||||
|
return pagify(msg, delims=["\n", " "], priority=True, shorten_by=10)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def sanitize_output(ctx: commands.Context, input_: str) -> str:
|
def sanitize_output(ctx: commands.Context, input_: str) -> str:
|
||||||
"""Hides the bot's token from a string."""
|
"""Hides the bot's token from a string."""
|
||||||
@ -115,7 +120,7 @@ class Dev:
|
|||||||
|
|
||||||
result = self.sanitize_output(ctx, str(result))
|
result = self.sanitize_output(ctx, str(result))
|
||||||
|
|
||||||
await ctx.send(box(result, lang="py"))
|
await ctx.send_interactive(self.get_pages(result), box_lang="py")
|
||||||
|
|
||||||
@commands.command(name='eval')
|
@commands.command(name='eval')
|
||||||
@checks.is_owner()
|
@checks.is_owner()
|
||||||
@ -162,28 +167,24 @@ class Dev:
|
|||||||
return await ctx.send(self.get_syntax_error(e))
|
return await ctx.send(self.get_syntax_error(e))
|
||||||
|
|
||||||
func = env['func']
|
func = env['func']
|
||||||
|
result = None
|
||||||
try:
|
try:
|
||||||
with redirect_stdout(stdout):
|
with redirect_stdout(stdout):
|
||||||
ret = await func()
|
result = await func()
|
||||||
except:
|
except:
|
||||||
value = stdout.getvalue()
|
printed = "{}{}".format(stdout.getvalue(), traceback.format_exc())
|
||||||
await ctx.send(
|
|
||||||
box('\n{}{}'.format(value, traceback.format_exc()), lang="py"))
|
|
||||||
else:
|
else:
|
||||||
value = stdout.getvalue()
|
printed = stdout.getvalue()
|
||||||
try:
|
await ctx.tick()
|
||||||
await ctx.message.add_reaction('\N{White Heavy Check Mark}')
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if ret is None:
|
if result is not None:
|
||||||
if value:
|
self._last_result = result
|
||||||
value = self.sanitize_output(ctx, str(value))
|
msg = "{}{}".format(printed, result)
|
||||||
await ctx.send(box(value, lang="py"))
|
|
||||||
else:
|
else:
|
||||||
self._last_result = ret
|
msg = printed
|
||||||
ret = self.sanitize_output(ctx, str(ret))
|
msg = self.sanitize_output(ctx, msg)
|
||||||
await ctx.send(box("{}{}".format(value, ret), lang="py"))
|
|
||||||
|
await ctx.send_interactive(self.get_pages(msg), box_lang="py")
|
||||||
|
|
||||||
@commands.command()
|
@commands.command()
|
||||||
@checks.is_owner()
|
@checks.is_owner()
|
||||||
@ -260,7 +261,6 @@ class Dev:
|
|||||||
result = await result
|
result = await result
|
||||||
except:
|
except:
|
||||||
value = stdout.getvalue()
|
value = stdout.getvalue()
|
||||||
value = self.sanitize_output(ctx, value)
|
|
||||||
msg = "{}{}".format(value, traceback.format_exc())
|
msg = "{}{}".format(value, traceback.format_exc())
|
||||||
else:
|
else:
|
||||||
value = stdout.getvalue()
|
value = stdout.getvalue()
|
||||||
@ -270,10 +270,10 @@ class Dev:
|
|||||||
elif value:
|
elif value:
|
||||||
msg = "{}".format(value)
|
msg = "{}".format(value)
|
||||||
|
|
||||||
|
msg = self.sanitize_output(ctx, msg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for page in pagify(str(msg), shorten_by=12):
|
await ctx.send_interactive(self.get_pages(msg), box_lang="py")
|
||||||
page = self.sanitize_output(ctx, page)
|
|
||||||
await ctx.send(box(page, "py"))
|
|
||||||
except discord.Forbidden:
|
except discord.Forbidden:
|
||||||
pass
|
pass
|
||||||
except discord.HTTPException as e:
|
except discord.HTTPException as e:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user