diff options
author | 2021-04-10 20:23:45 -0400 | |
---|---|---|
committer | 2021-04-10 20:23:45 -0400 | |
commit | 13be6262e6048790062be9dd7daf178fb8b8d0e5 (patch) | |
tree | b8f940c3daaa14171fdf5d97d21bbdd11f5096f2 | |
parent | Change names (diff) |
Update codeblock regex
The snekbox implementation of the codeblock regex
was incorporated. This now correctly parses the
`code` and ``code`` markdown discord allows.
You can also use multiple code blocks with text interrupting it and
it will process the different code blocks as one continuous code block.
-rw-r--r-- | bot/exts/internal_eval/_internal_eval.py | 37 |
1 files changed, 36 insertions, 1 deletions
diff --git a/bot/exts/internal_eval/_internal_eval.py b/bot/exts/internal_eval/_internal_eval.py index f7a0946b..45bfbdc3 100644 --- a/bot/exts/internal_eval/_internal_eval.py +++ b/bot/exts/internal_eval/_internal_eval.py @@ -17,6 +17,23 @@ log = logging.getLogger("rattlesnake.exts.admin_tools.internal_eval") CODEBLOCK_REGEX = re.compile(r"(^```(py(thon)?)?\n)|(```$)") +FORMATTED_CODE_REGEX = re.compile( + r"(?P<delim>(?P<block>```)|``?)" # code delimiter: 1-3 backticks; (?P=block) only matches if it's a block + r"(?(block)(?:(?P<lang>[a-z]+)\n)?)" # if we're in a block, match optional language (only letters plus newline) + r"(?:[ \t]*\n)*" # any blank (empty or tabs/spaces only) lines before the code + r"(?P<code>.*?)" # extract all code inside the markup + r"\s*" # any more whitespace before the end of the code markup + r"(?P=delim)", # match the exact same delimiter from the start again + re.DOTALL | re.IGNORECASE # "." also matches newlines, case insensitive +) + +RAW_CODE_REGEX = re.compile( + r"^(?:[ \t]*\n)*" # any blank (empty or tabs/spaces only) lines before the code + r"(?P<code>.*?)" # extract all the rest as code + r"\s*$", # any trailing whitespace until the end of the string + re.DOTALL # "." also matches newlines +) + class InternalEval(commands.Cog): """Top secret code evaluation for admins and owners.""" @@ -141,7 +158,25 @@ class InternalEval(commands.Cog): @with_role(Roles.admin) async def eval(self, ctx: commands.Context, *, code: str) -> None: """Run eval in a REPL-like format.""" - code = CODEBLOCK_REGEX.sub("", code.strip()) + + if match := list(FORMATTED_CODE_REGEX.finditer(code)): + blocks = [block for block in match if block.group("block")] + + if len(blocks) > 1: + code = '\n'.join(block.group("code") for block in blocks) + info = "several code blocks" + else: + match = match[0] if len(blocks) == 0 else blocks[0] + code, block, lang, delim = match.group("code", "block", "lang", "delim") + if block: + info = (f"'{lang}' highlighted" if lang else "plain") + " code block" + else: + info = f"{delim}-enclosed inline code" + else: + code = RAW_CODE_REGEX.fullmatch(code).group("code") + info = "unformatted or badly formatted code" + + code = textwrap.dedent(code) await self._eval(ctx, code) @internal_group.command(name='reset', aliases=("clear", "exit", "r", "c")) |