aboutsummaryrefslogtreecommitdiffstats
path: root/bot/exts/evergreen/source.py
diff options
context:
space:
mode:
authorGravatar Anubhav1603 <[email protected]>2020-09-29 13:41:59 +0530
committerGravatar Anubhav1603 <[email protected]>2020-09-29 13:41:59 +0530
commitbd3dd9fa32a4f871b7033f0d322e5b675d51b8b1 (patch)
treed54efc957ae0512933a7c1ec8402ab9a909edb2f /bot/exts/evergreen/source.py
parentadded github url of seasonal bot (diff)
added source command
Diffstat (limited to 'bot/exts/evergreen/source.py')
-rw-r--r--bot/exts/evergreen/source.py126
1 files changed, 126 insertions, 0 deletions
diff --git a/bot/exts/evergreen/source.py b/bot/exts/evergreen/source.py
new file mode 100644
index 00000000..164430e2
--- /dev/null
+++ b/bot/exts/evergreen/source.py
@@ -0,0 +1,126 @@
+import inspect
+from pathlib import Path
+from typing import Optional, Tuple, Union
+
+from discord import Embed
+from discord.ext import commands
+
+from bot.constants import Source
+
+SourceType = Union[commands.HelpCommand, commands.Command, commands.Cog, str, commands.ExtensionNotLoaded]
+
+
+class SourceConverter(commands.Converter):
+ """Convert an argument into a help command, tag, command, or cog."""
+
+ async def convert(self, ctx: commands.Context, argument: str) -> SourceType:
+ """Convert argument into source object."""
+ cog = ctx.bot.get_cog(argument)
+ if cog:
+ return cog
+
+ cmd = ctx.bot.get_command(argument)
+ if cmd:
+ return cmd
+
+ raise commands.BadArgument(
+ f"Unable to convert `{argument}` to valid command or Cog."
+ )
+
+
+class BotSource(commands.Cog):
+ """Displays information about the bot's source code."""
+
+ def __init__(self, bot: commands.Bot):
+ self.bot = bot
+
+ @commands.command(name="source", aliases=("src",))
+ async def source_command(self, ctx: commands.Context, *, source_item: SourceConverter = None) -> None:
+ """Display information and a GitHub link to the source code of a command, tag, or cog."""
+ if not source_item:
+ embed = Embed(title="Bot's GitHub Repository")
+ embed.add_field(name="Repository", value=f"[Go to GitHub]({Source.github})")
+ embed.set_thumbnail(url="https://avatars1.githubusercontent.com/u/9919")
+ await ctx.send(embed=embed)
+ return
+
+ embed = await self.build_embed(source_item)
+ await ctx.send(embed=embed)
+
+ def get_source_link(self, source_item: SourceType) -> Tuple[str, str, Optional[int]]:
+ """
+ Build GitHub link of source item, return this link, file location and first line number.
+
+ Raise BadArgument if `source_item` is a dynamically-created object (e.g. via internal eval).
+ """
+ if isinstance(source_item, commands.Command):
+ if source_item.cog_name == "Alias":
+ cmd_name = source_item.callback.__name__.replace("_alias", "")
+ cmd = self.bot.get_command(cmd_name.replace("_", " "))
+ src = cmd.callback.__code__
+ filename = src.co_filename
+ else:
+ src = source_item.callback.__code__
+ filename = src.co_filename
+ else:
+ src = type(source_item)
+ try:
+ filename = inspect.getsourcefile(src)
+ except TypeError:
+ raise commands.BadArgument("Cannot get source for a dynamically-created object.")
+
+ if not isinstance(source_item, str):
+ try:
+ lines, first_line_no = inspect.getsourcelines(src)
+ except OSError:
+ raise commands.BadArgument("Cannot get source for a dynamically-created object.")
+
+ lines_extension = f"#L{first_line_no}-L{first_line_no+len(lines)-1}"
+ else:
+ first_line_no = None
+ lines_extension = ""
+
+ # Handle tag file location differently than others to avoid errors in some cases
+ if not first_line_no:
+ file_location = Path(filename).relative_to("/bot/")
+ else:
+ file_location = Path(filename).relative_to(Path.cwd()).as_posix()
+
+ url = f"{Source.github}/blob/master/{file_location}{lines_extension}"
+
+ return url, file_location, first_line_no or None
+
+ async def build_embed(self, source_object: SourceType) -> Optional[Embed]:
+ """Build embed based on source object."""
+ url, location, first_line = self.get_source_link(source_object)
+
+ if isinstance(source_object, commands.HelpCommand):
+ title = "Help Command"
+ description = source_object.__doc__.splitlines()[1]
+ elif isinstance(source_object, commands.Command):
+ if source_object.cog_name == "Alias":
+ cmd_name = source_object.callback.__name__.replace("_alias", "")
+ cmd = self.bot.get_command(cmd_name.replace("_", " "))
+ description = cmd.short_doc
+ else:
+ description = source_object.short_doc
+
+ title = f"Command: {source_object.qualified_name}"
+ elif isinstance(source_object, str):
+ title = f"Tag: {source_object}"
+ description = ""
+ else:
+ title = f"Cog: {source_object.qualified_name}"
+ description = source_object.description.splitlines()[0]
+
+ embed = Embed(title=title, description=description)
+ embed.add_field(name="Source Code", value=f"[Go to GitHub]({url})")
+ line_text = f":{first_line}" if first_line else ""
+ embed.set_footer(text=f"{location}{line_text}")
+
+ return embed
+
+
+def setup(bot: commands.Bot) -> None:
+ """Load the BotSource cog."""
+ bot.add_cog(BotSource(bot))