Ejemplo n.º 1
0
    async def source_command(self, ctx, *, command):
        """Get the source code for a certain command, cog, or extension..."""
        try:
            try:
                command_obj = await neko3.converters.CommandConverter().convert(ctx, command)
                code = inspect.getsource(command_obj.callback)
                object_type = "command"
            except Exception:
                try:
                    code = inspect.getsource(type(ctx.bot.cogs[command]))
                    object_type = "cog"
                except Exception:
                    code = inspect.getsource(ctx.bot.extensions[command])
                    object_type = "extension"

            p = pagination.StringNavigatorFactory(
                prefix="```", suffix="```", max_lines=22, substitutions=[lambda s: s.replace("`", "′")]
            )
            p.add_line(f"# -*-*- Source for {command} {object_type}  -*-*-")

            p.disable_truncation()

            for line in code.split("\n"):
                p.add_line(line)

            p.start(ctx)
        except Exception:
            self.logger.exception("Failed to load source.")
            await ctx.send("No source was found...")
Ejemplo n.º 2
0
    async def unload_command(self, ctx, *, package):
        extensions = fnmatch.filter(ctx.bot.extensions, package)
        count = len(extensions)
        p = pagination.StringNavigatorFactory(prefix="```",
                                              suffix="```",
                                              max_lines=10)
        p.add_line(
            f"Requesting unload of extensions matching pattern {package}")
        p.add_line(f"Matched {count} extension{'s' if count - 1 else ''}")

        for extension in extensions:
            try:
                with algorithms.TimeIt() as timer:
                    ctx.bot.unload_extension(extension)
                p.add_line(
                    f"Unloaded {extension} in approx {timer.time_taken * 1_000:.0f}ms."
                )
            except Exception as ex:
                self.logger.exception("Could not unload %s",
                                      extension,
                                      exc_info=ex)
                p.add_line(
                    f"Could not unload {extension} because {type(ex).__name__}: {ex}"
                )

        p.start(ctx)
    async def cpp_reference_command(self, ctx, *terms):

        self.logger.info("Searching for terms %s", terms)
        try:
            async with ctx.typing():
                results = await self.results(ctx, *terms)
        except Exception as ex:
            self.logger.exception("search error", exc_info=ex)
            return await ctx.send(
                "CppReference did something unexpected. If this keeps "
                "happening, contact Esp with the following info: \n\n"
                f"{type(ex).__qualname__}: {ex!s}"
            )

        if not results:
            self.logger.info("no results")
            return await ctx.send("No results were found.", delete_after=10)

        if len(results) > 1:
            # Show an option picker
            try:
                self.logger.info("waiting for input")
                result = await pagination.option_picker(*results, ctx=ctx, max_lines=20)
            except asyncio.TimeoutError:
                return

            if result == pagination.NoOptionPicked():
                self.logger.info("no option picked")
                return
        else:
            result = results[0]

        # Fetch the result page.

        async with ctx.typing():
            try:
                self.logger.info("searching for info from %s", result.href)
                url, h1, tasters, header, desc = await self.get_information(ctx, result.href)
            except Exception as ex:
                self.logger.exception("An exception occurred", exc_info=ex)
                return await ctx.send("An error was encountered and a duck was shot.")

            binder = pagination.StringNavigatorFactory(max_lines=50)

            binder.disable_truncation()
            binder.add_line(f"**{h1}**\n<{url}>")
            if header:
                binder.add_line(f"\n`{header}`")

            if tasters:
                for taster in tasters:
                    binder.add_line(f"```cpp\n{taster}\n```")
            binder.enable_truncation()

            if desc:
                binder.add_line(desc.replace("*", "∗"))

        binder.start(ctx)
Ejemplo n.º 4
0
    async def emoji_library_command(self, ctx, arg=None):
        """Shows all emojis I can see ever. Pass the --verbose/-v flag to see names."""
        if arg:
            transform = self.transform_verbose
        else:
            transform = self.transform_mute

        emojis = transform(ctx.bot.emojis)

        p = pagination.StringNavigatorFactory()
        for emoji in emojis:
            p += emoji

        p.start(ctx)
Ejemplo n.º 5
0
    async def r_command(self, ctx, *, source):
        """
        Use the following to highlight your syntax:

        ```
        n.r
        ˋˋˋr
        
        t = (1:625) / 100\n
        x <- cos(t)\n
        y <- sin(t)\n
        plot(x, y)\n
        ˋˋˋ
        ```
        """
        code_block = utils.code_block_re.search(source)
        if code_block:
            source = code_block.group(2)

        with ctx.typing():
            result = await cranr.eval_r(source)

        binder = pagination.StringNavigatorFactory(prefix="```markdown",
                                                   suffix="```",
                                                   max_lines=40)

        # Last line is some error about rm not working.
        for line in result.output.split("\n"):
            if line == "sh: 1: rm: Permission denied":
                continue
            binder.add_line(line)

        binder.add_line(f"RESULT: {result.result.title()}")
        binder.add_line(f"STATE: {result.state.title()}")
        if result.fail_reason:
            binder.add_line(f"FAILURE REASON: {result.fail_reason}")

        booklet = binder.build(ctx)

        additionals = []

        for i in range(0, min(6, len(result.images))):
            with io.BytesIO(result.images[i][0]) as bio:
                bio.seek(0)
                f = discord.File(bio, f"output_{i + 1}.png")
                additionals.append(await ctx.send(file=f))

        await utils.start_and_listen_to_edit(ctx, booklet, *additionals)
Ejemplo n.º 6
0
    async def debug_command(self, ctx, *, content):
        message = ctx.message
        command_start = message.content.index(ctx.invoked_with) + len(
            ctx.invoked_with)
        message.content = message.content[command_start:].lstrip()

        if message.content.startswith(("!!", "debug")):
            await ctx.send(
                "That would loop recursively, so I am not going to invoke it.")
            return

        message.content = ctx.prefix + message.content

        stream = io.StringIO()
        reraise = None

        start = time.perf_counter()
        with contextlib.redirect_stderr(stream), contextlib.redirect_stdout(
                stream), cli.STREAM.add_delegate(stream):
            try:
                cli.LOGGER_STREAM = stream
                new_ctx = await ctx.bot.get_context(message)
                await new_ctx.command.invoke(new_ctx)
            except BaseException as ex:
                self.logger.exception("An error occurred executing %s:",
                                      new_ctx.message.content,
                                      exc_info=ex)
                reraise = ex
            finally:
                elapsed = time.perf_counter() - start

        stream.seek(0)
        logs = stream.getvalue()

        if logs:
            nav = pagination.StringNavigatorFactory(prefix="```", suffix="```")
            for line in stream.getvalue().split("\n"):
                nav.add_line(line)

            nav.start(new_ctx)

        await ctx.send(f"> Execution finished in {elapsed * 1_000:.2f}ms")

        if reraise is not None:
            raise reraise
Ejemplo n.º 7
0
    async def py_command(self, ctx, member):
        """Gets some help regarding the given Python member, if it exists..."""

        with io.StringIO() as buff:
            with contextlib.redirect_stdout(buff):
                with contextlib.redirect_stderr(buff):
                    help(member)
            data = buff.getvalue().splitlines()

        bb = pagination.StringNavigatorFactory(max_lines=20,
                                               prefix="```markdown",
                                               suffix="```")

        for line in data:
            line = line.replace("`", "′")
            bb.add_line(line)

        bb.start(ctx)
Ejemplo n.º 8
0
    def formatify(code, style, ctx, author):
        code, logs = code

        spf = pagination.StringNavigatorFactory(max_lines=None,
                                                prefix="```py",
                                                suffix="```")
        spf += f"# Using the {style} code-style\n"
        spf += code.replace("```", "ˋˋˋ")
        spf.add_page_break()
        spf += logs

        # Swap authors.
        temp = ctx.author
        # Lets both the invoker and the message being targeted edit by default
        ctx.author = author
        nav = spf.build(ctx)
        nav.owner = temp

        return nav
Ejemplo n.º 9
0
    async def load_command(self, ctx, *, package):
        try:
            self.logger.info("%s requested loading of %s", ctx.author, package)

            with algorithms.TimeIt() as timer:
                ctx.bot.load_extension(package)

            await ctx.send(
                f"Loaded {package} in approx {timer.time_taken * 1_000:.0f}ms."
            )
        except Exception as ex:
            self.logger.exception("Failed to load %s", package, exc_info=ex)
            p = pagination.StringNavigatorFactory(prefix="```",
                                                  suffix="```",
                                                  max_lines=10)
            for line in traceback.format_exception(type(ex), ex,
                                                   ex.__traceback__):
                p.add_line(line.rstrip())

            p.start(ctx)
Ejemplo n.º 10
0
    async def help_command(self,
                           ctx,
                           *,
                           language: neko3.converters.clean_content = None):
        """
        Shows all supported languages and their markdown highlighting
        syntax expected to invoke them correctly.
        """
        if not language:
            booklet = pagination.StringNavigatorFactory(max_lines=20)
            booklet.add_line("**Supported languages**")

            for lang in sorted(rextester.Language.__members__.keys()):
                lang = lang.lower()
                booklet.add_line(f"- {lang.title()} -- `{ctx.prefix}rxt "
                                 f"ˋˋˋ{lang} ...`")
            booklet.start(ctx)
        else:
            await ctx.send(
                "There is nothing here yet. The developer has been shot as a result."
            )
Ejemplo n.º 11
0
    async def reload_command(self, ctx, *, package="*"):
        extensions = fnmatch.filter(ctx.bot.extensions, package)
        count = len(extensions)
        p = pagination.StringNavigatorFactory(prefix="```",
                                              suffix="```",
                                              max_lines=10)
        p.add_line(
            f"Requesting reload of extensions matching pattern {package}")
        p.add_line(f"Matched {count} extension{'s' if count - 1 else ''}")

        successes = 0
        failures = 0

        with algorithms.TimeIt() as outer_timer:
            for extension in extensions:
                did_unload = False
                try:
                    with algorithms.TimeIt() as timer:
                        ctx.bot.unload_extension(extension)
                        did_unload = True
                        ctx.bot.load_extension(extension)
                    p.add_line(
                        f"Reloaded {extension} in approx {timer.time_taken * 1_000:.0f}ms."
                    )
                    successes += 1
                except Exception as ex:
                    prefix = "" if did_unload else "un"
                    self.logger.exception("Could not %sload %s",
                                          prefix,
                                          extension,
                                          exc_info=ex)
                    p.add_line(f"Could not {prefix}load {extension} "
                               f"because {type(ex).__name__}: {ex}")
                    failures += 1

        p.add_line(f"Reloaded {successes}/{successes + failures} in "
                   f"approx {outer_timer.time_taken * 1_000:.0f}ms.")

        p.start(ctx)
Ejemplo n.º 12
0
    async def event_loop_command(self, ctx):
        all_tasks = asyncio.Task.all_tasks(loop=ctx.bot.loop)

        booklet = pagination.StringNavigatorFactory(prefix="```",
                                                    suffix="```",
                                                    max_lines=None)
        summary = []

        for task in all_tasks:
            with io.StringIO() as fp:
                task.print_stack(file=fp)
                booklet.add_line(fp.getvalue())
                # noinspection PyProtectedMember
                # Repr, shorten it as it is obscenely long
                tup = getattr(task, "_repr_info", lambda: ["", "None"])()[1]
                summary.append(tup)
            booklet.add_page_break()

        booklet.add_page_break(to_back=False)
        summary = "\n".join(summary)
        booklet.add(summary, to_back=False)
        booklet.add_line(f"{len(all_tasks)} coroutines in the loop.",
                         to_back=False)
        booklet.start(ctx)
Ejemplo n.º 13
0
    async def view_binds_command(self, ctx):
        if ctx.guild.me.guild_permissions.manage_webhooks:

            @pagination.embed_generator(max_chars=2048)
            def generator(_, page, __):
                return theme.generic_embed(ctx, description=page)

            binder = pagination.StringNavigatorFactory(
                max_lines=10, prefix="```", suffix="```", substitutions=[self.scrub]
            )

            for bind_command, value in self.raw_binds.items():
                bind_command = bind_command.replace("|", ", ")
                if isinstance(value, tuple):
                    value = ", ".join(value)

                binder.add_line(f"{bind_command}: {value}")
            binder.start(ctx)
        else:
            await ctx.send(
                "I don't seem to have the MANAGE_WEBHOOKS "
                "permission required for this to work. Please "
                "grant me that "
            )
Ejemplo n.º 14
0
    async def _send_table(ctx, *unicodes):
        """Creates a markdown formatted table of results for characters."""
        book = pagination.StringNavigatorFactory(max_lines=None)

        if len(unicodes) >= 20:
            did_setify = True
            unicodes = aggregates.FrozenOrderedSet(unicodes)
        else:
            did_setify = False

        preamble = [
            "_Removed duplicate entries_"
            if did_setify else "\N{ZERO WIDTH SPACE}",
            f"**Character info (Unicode v{unicodedata.unidata_version})**",
            "__**`##  Ct UTF-CODE DECIMAL DESCRIPTION`**__",
        ]

        # Categories for current page
        categories = set()
        current_page = []

        def dump_page():
            nonlocal current_page
            # Define the categories used.
            category_amble = ""
            for category in sorted(categories):
                desc = _char2category.get(category, "Unknown")
                category_amble += f"\n`{category}` - {desc}"

            four_em = " "
            page = "\n".join((*preamble, *current_page,
                              category_amble)).replace(" ", four_em)
            book.add_page_break()
            book.add_block(page)
            categories.clear()
            current_page = []

        for i, char in enumerate(unicodes):
            decimal = char.raw
            hexd = f"U+{decimal:04x}"
            category = char.category
            name = char.name
            lit = chr(char.raw)

            current_page.append(
                f"`{i + 1:02}  {category} {hexd:>8} {decimal:>7} {name}  {lit}`  {lit}"
            )

            categories.add(category)

            if i % 16 == 15:
                dump_page()

        if current_page:
            dump_page()

        booklet = book.build(ctx)
        if len(booklet) > 1:
            await booklet.start()
        else:
            await ctx.send(booklet.current_page)
Ejemplo n.º 15
0
    async def coliru_group(self, ctx, *, code):
        """
        Attempts to execute some code by detecting the language in the
        syntax highlighting. You MUST format the code using markdown-formatted
        code blocks. Please, please, PLEASE read this before saying "it is
        broken!"

        Run `coliru help` to view a list of the supported languages, or
        `coliru help <lang>` to view the help for a specific language.

        If you want to upload more than one file, or you wish to specify a
        custom build routine or flags, see `coliru a`.
        """

        code = utils.code_block_re.search(code)

        if not code or len(code.groups()) < 2:
            booklet = pagination.StringNavigatorFactory()
            booklet.add_line("I couldn't detect a valid language in your "
                             "syntax highlighting... try again by editing "
                             "your initial message.")

            booklet = booklet.build(ctx)

            return await utils.start_and_listen_to_edit(ctx, booklet)

        # Extract the code
        language, source = code.groups()
        language = language.lower()

        try:
            with ctx.typing():
                output = await coliru.targets[language](source)
        except KeyError:
            booklet = pagination.StringNavigatorFactory()
            booklet.add_line(f"That language ({language}) is not yet supported"
                             " by this toolchain. Feel free to edit your"
                             " message if you wish to do something else.")
            booklet = booklet.build(ctx)

            return await utils.start_and_listen_to_edit(ctx, booklet)

        else:
            booklet = pagination.StringNavigatorFactory(prefix="```markdown",
                                                        suffix="```",
                                                        max_lines=25)

            booklet.add_line(f"Interpreting as {language!r} source.")

            for line in output.split("\n"):
                booklet.add_line(line)

            if ctx.invoked_with in ("ccd", "colirud"):
                await neko_commands.try_delete(ctx)

            if len(output.strip()) == 0:
                await ctx.send("No output...")
                return

            booklet = booklet.build(ctx)

            return await utils.start_and_listen_to_edit(ctx, booklet)
Ejemplo n.º 16
0
    async def rextester_group(self, ctx, *, source):
        """
        Attempts to execute some code by detecting the language in the
        syntax highlighting. You MUST format the code using markdown-formatted
        code blocks. Please, please, PLEASE read this before saying "it is
        broken!"

        This provides many more languages than coliru does, however, it is
        mainly untested and will probably break in a lot of places. It also
        has much less functionality. Many languages have to be formatted
        in a specific way or have specific variable names or namespaces.

        Run `cc help` to view a list of the supported languages, or
        `cc help <lang>` to view the help for a specific language.
        """
        code_block = utils.code_block_re.search(source)

        if not code_block or len(code_block.groups()) < 2:
            booklet = pagination.StringNavigatorFactory()
            booklet.add_line("I couldn't detect a valid language in your "
                             "syntax highlighting... try again by editing "
                             "your initial message.")
            booklet = booklet.build(ctx)
            return await utils.start_and_listen_to_edit(ctx, booklet)

        # Extract the code
        language, source = code_block.groups()
        language = language.lower()

        if language not in rextester.Language.__members__:
            booklet = pagination.StringNavigatorFactory()
            booklet.add_line("Doesn't look like I support that language. "
                             "Run `coliru help` for a list.")

            booklet = booklet.build(ctx)
            return await utils.start_and_listen_to_edit(ctx, booklet)

        booklet = pagination.StringNavigatorFactory(prefix="```markdown",
                                                    suffix="```",
                                                    max_lines=15)

        lang_no = rextester.Language.__members__[language]

        async with ctx.typing():
            response = await rextester.execute(lang_no, source)

        if response.errors:
            booklet.add_line("> ERRORS:")
            booklet.add_line(response.errors)

        if response.warnings:
            booklet.add_line("> WARNINGS:")
            booklet.add_line(response.warnings)

        if response.result:
            booklet.add_line("> OUTPUT:")
            booklet.add_line(response.result)

        booklet.add_line(
            f"Interpreted as {language.lower()} source; {response.stats}")

        if response.files:
            booklet.add_line(
                f"- {len(response.files)} file(s) included. Bug my dev to implement this properly!"
            )

        booklet = booklet.build(ctx)
        await utils.start_and_listen_to_edit(ctx, booklet)
Ejemplo n.º 17
0
    async def advanced_command(self, ctx, *, code):
        """
        This tool enables you to specify more than one file, in any supported
        language on Coliru. It also lets you upload source code files.

        Advanced code execution will first pool all source files into the
        current working directory in the sandbox. It will then proceed to
        execute the build/run command: this is the first argument, and should
        be enclosed in single back-ticks. The execute command can be something
        as simple as `make`, or as complicated as you like. You must invoke
        all of your logic you wish to perform from this argument, however.

        It is worth noting that this build script WILL be executed as Bash
        commands.

        For small programs, it may be as simple as invoking the interpreter
        or compiler, and then running the output. However, if you have much
        more complicated input, it is advisable to invoke something like a
        Makefile and call your logic from that.
        """

        try:
            # Get the first block as the command.
            command = utils.inline_block_re.search(code)

            if not command:
                raise ValueError("No command was given.")

            command = command.groups()[0]

            rest = code[len(command):].lstrip()

            # Get files:
            files = []
            for m in utils.file_name_and_block_re.findall(rest):
                files.append(m)

            for attachment in ctx.message.attachments:
                with io.StringIO() as buff:
                    attachment.save(buff)
                    buff = buff.getvalue()

                files.append((attachment.filename, buff))

            if len(files) == 0:
                raise ValueError("Expected one or more source files.")

            # Map to sourcefile objects
            files = [coliru.SourceFile(*file) for file in files]

            # Main file
            main = coliru.SourceFile(".run.sh", command)

            # Generate the coliru API client instance.
            c = coliru.Coliru("bash .run.sh", main, *files, verbose=True)

            async with self.acquire_http_session() as http:
                output = await c.execute(http)

            booklet = pagination.StringNavigatorFactory(prefix="```markdown",
                                                        suffix="```",
                                                        max_lines=25)

            for line in output.split("\n"):
                booklet.add_line(line)

            if ctx.invoked_with in ("ccd", "colirud"):
                await neko_commands.try_delete(ctx)

            if len(output.strip()) == 0:
                await ctx.send("No output...")
                return

            booklet = booklet.build(ctx)

            return await utils.start_and_listen_to_edit(ctx, booklet)

        except IndexError:
            return await ctx.send("Invalid input format.")
        except ValueError as ex:
            return await ctx.send(str(ex))