aboutsummaryrefslogtreecommitdiffstats
path: root/bot/exts/core/source.py
diff options
context:
space:
mode:
authorGravatar Janine vN <[email protected]>2021-09-05 00:06:04 -0400
committerGravatar Janine vN <[email protected]>2021-09-05 00:06:04 -0400
commitf0b5c14e1f59e5135f27a4966021f30c77d1fc7d (patch)
tree4c83b68de1e56e6fea10b26b489d493030dbf88a /bot/exts/core/source.py
parentUpdate paths to new resource links (diff)
Move internal eval and rename utils to core
Part of this restructure involves splitting out the massive evergreen folder into a `fun` folder and then a `utilities` folder. To help with that we've rename the `util` folder to `core`. The core functions to run the bot have been moved into this folder. `.source`, `.ping`, and `.int e` have been moved into this folder.
Diffstat (limited to 'bot/exts/core/source.py')
-rw-r--r--bot/exts/core/source.py85
1 files changed, 85 insertions, 0 deletions
diff --git a/bot/exts/core/source.py b/bot/exts/core/source.py
new file mode 100644
index 00000000..7572ce51
--- /dev/null
+++ b/bot/exts/core/source.py
@@ -0,0 +1,85 @@
+import inspect
+from pathlib import Path
+from typing import Optional
+
+from discord import Embed
+from discord.ext import commands
+
+from bot.bot import Bot
+from bot.constants import Source
+from bot.utils.converters import SourceConverter, SourceType
+
+
+class BotSource(commands.Cog):
+ """Displays information about the bot's source code."""
+
+ @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="Sir Lancebot's GitHub Repository")
+ embed.add_field(name="Repository", value=f"[Go to GitHub]({Source.github})")
+ embed.set_thumbnail(url=Source.github_avatar_url)
+ 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):
+ callback = inspect.unwrap(source_item.callback)
+ src = 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 = ""
+
+ file_location = Path(filename).relative_to(Path.cwd()).as_posix()
+
+ url = f"{Source.github}/blob/main/{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.Command):
+ description = source_object.short_doc
+ title = f"Command: {source_object.qualified_name}"
+ else:
+ title = f"Cog: {source_object.qualified_name}"
+ description = source_object.description.splitlines()[0]
+
+ embed = Embed(title=title, description=description)
+ embed.set_thumbnail(url=Source.github_avatar_url)
+ 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: Bot) -> None:
+ """Load the BotSource cog."""
+ bot.add_cog(BotSource())