diff options
Diffstat (limited to '')
| -rw-r--r-- | bot/cogs/codeblock/cog.py | 63 | ||||
| -rw-r--r-- | bot/cogs/codeblock/instructions.py | 113 | ||||
| -rw-r--r-- | bot/cogs/codeblock/parsing.py | 2 | 
3 files changed, 113 insertions, 65 deletions
diff --git a/bot/cogs/codeblock/cog.py b/bot/cogs/codeblock/cog.py index dad0cc9cc..efc22c8a5 100644 --- a/bot/cogs/codeblock/cog.py +++ b/bot/cogs/codeblock/cog.py @@ -1,6 +1,5 @@  import logging  import time -from typing import Optional  import discord  from discord import Embed, Message, RawMessageUpdateEvent @@ -33,68 +32,6 @@ class CodeBlockCog(Cog, name="Code Block"):          # Stores improperly formatted Python codeblock message ids and the corresponding bot message          self.codeblock_message_ids = {} -    def format_bad_ticks_message(self, message: discord.Message) -> Optional[str]: -        """Return the guide message to output for bad code block ticks in `message`.""" -        ticks = message.content[:3] -        content = self.codeblock_stripping(f"```{message.content[3:-3]}```", True) -        if content is None: -            return - -        content, repl_code = content - -        if len(content) == 2: -            content = content[1] -        else: -            content = content[0] - -        content = parsing.truncate(content) -        content_escaped_markdown = parsing.RE_MARKDOWN.sub(r'\\\1', content) - -        return ( -            "It looks like you are trying to paste code into this channel.\n\n" -            "You seem to be using the wrong symbols to indicate where the codeblock should start. " -            f"The correct symbols would be \\`\\`\\`, not `{ticks}`.\n\n" -            "**Here is an example of how it should look:**\n" -            f"\\`\\`\\`python\n{content_escaped_markdown}\n\\`\\`\\`\n\n" -            "**This will result in the following:**\n" -            f"```python\n{content}\n```" -        ) - -    def format_guide_message(self, message: discord.Message) -> Optional[str]: -        """Return the guide message to output for a poorly formatted code block in `message`.""" -        content = self.codeblock_stripping(message.content, False) -        if content is None: -            return - -        content, repl_code = content - -        if not repl_code and not parsing.is_python_code(content[0]): -            return - -        if content and repl_code: -            content = content[1] -        else: -            content = content[0] - -        content = parsing.truncate(content) - -        log.debug( -            f"{message.author} posted something that needed to be put inside python code " -            f"blocks. Sending the user some instructions." -        ) - -        content_escaped_markdown = parsing.RE_MARKDOWN.sub(r'\\\1', content) -        return ( -            "It looks like you're trying to paste code into this channel.\n\n" -            "Discord has support for Markdown, which allows you to post code with full " -            "syntax highlighting. Please use these whenever you paste code, as this " -            "helps improve the legibility and makes it easier for us to help you.\n\n" -            f"**To do this, use the following method:**\n" -            f"\\`\\`\\`python\n{content_escaped_markdown}\n\\`\\`\\`\n\n" -            "**This will result in the following:**\n" -            f"```python\n{content}\n```" -        ) -      @staticmethod      def is_help_channel(channel: discord.TextChannel) -> bool:          """Return True if `channel` is in one of the help categories.""" diff --git a/bot/cogs/codeblock/instructions.py b/bot/cogs/codeblock/instructions.py new file mode 100644 index 000000000..0bcd2eda8 --- /dev/null +++ b/bot/cogs/codeblock/instructions.py @@ -0,0 +1,113 @@ +import logging +from typing import Optional + +from . import parsing + +log = logging.getLogger(__name__) + +PY_LANG_CODES = ("python", "py") +EXAMPLE_PY = f"python\nprint('Hello, world!')"  # Make sure to escape any Markdown symbols here. +EXAMPLE_CODE_BLOCKS = ( +    "\\`\\`\\`{content}\n\\`\\`\\`\n\n" +    "**This will result in the following:**\n" +    "```{content}```" +) + + +def get_bad_ticks_message(code_block: parsing.CodeBlock) -> Optional[str]: +    """Return instructions on using the correct ticks for `code_block`.""" +    valid_ticks = f"\\{parsing.BACKTICK}" * 3 + +    # The space at the end is important here because something may be appended! +    instructions = ( +        "It looks like you are trying to paste code into this channel.\n\n" +        "You seem to be using the wrong symbols to indicate where the code block should start. " +        f"The correct symbols would be {valid_ticks}, not `{code_block.tick * 3}`. " +    ) + +    # Check if the code has an issue with the language specifier. +    addition_msg = get_bad_lang_message(code_block.content) +    if not addition_msg: +        addition_msg = get_no_lang_message(code_block.content) + +    # Combine the back ticks message with the language specifier message. The latter will +    # already have an example code block. +    if addition_msg: +        # The first line has a double line break which is not desirable when appending the msg. +        addition_msg = addition_msg.replace("\n\n", "\n", 1) + +        # Make the first character of the addition lower case. +        instructions += "Furthermore, " + addition_msg[0].lower() + addition_msg[1:] +    else: +        # Determine the example code to put in the code block based on the language specifier. +        if code_block.language.lower() in PY_LANG_CODES: +            content = EXAMPLE_PY +        elif code_block.language: +            # It's not feasible to determine what would be a valid example for other languages. +            content = f"{code_block.language}\n..." +        else: +            content = "Hello, world!" + +        example_blocks = EXAMPLE_CODE_BLOCKS.format(content) +        instructions += f"\n\n**Here is an example of how it should look:**\n{example_blocks}" + +    return instructions + + +def get_no_ticks_message(content: str) -> Optional[str]: +    """If `content` is Python/REPL code, return instructions on using code blocks.""" +    if parsing.is_repl_code(content) or parsing.is_python_code(content): +        example_blocks = EXAMPLE_CODE_BLOCKS.format(EXAMPLE_PY) +        return ( +            "It looks like you're trying to paste code into this channel.\n\n" +            "Discord has support for Markdown, which allows you to post code with full " +            "syntax highlighting. Please use these whenever you paste code, as this " +            "helps improve the legibility and makes it easier for us to help you.\n\n" +            f"**To do this, use the following method:**\n{example_blocks}" +        ) + + +def get_bad_lang_message(content: str) -> Optional[str]: +    """ +    Return instructions on fixing the Python language specifier for a code block. + +    If `content` doesn't start with "python" or "py" as the language specifier, return None. +    """ +    stripped = content.lstrip().lower() +    lang = next((lang for lang in PY_LANG_CODES if stripped.startswith(lang)), None) + +    if lang: +        # Note that get_bad_ticks_message expects the first line to have an extra newline. +        lines = ["It looks like you incorrectly specified a language for your code block.\n"] + +        if content.startswith(" "): +            lines.append(f"Make sure there are no spaces between the back ticks and `{lang}`.") + +        if stripped[len(lang)] != "\n": +            lines.append( +                f"Make sure you put your code on a new line following `{lang}`. " +                f"There must not be any spaces after `{lang}`." +            ) + +        example_blocks = EXAMPLE_CODE_BLOCKS.format(EXAMPLE_PY) +        lines.append(f"\n**Here is an example of how it should look:**\n{example_blocks}") + +        return "\n".join(lines) + + +def get_no_lang_message(content: str) -> Optional[str]: +    """ +    Return instructions on specifying a language for a code block. + +    If `content` is not valid Python or Python REPL code, return None. +    """ +    if parsing.is_repl_code(content) or parsing.is_python_code(content): +        example_blocks = EXAMPLE_CODE_BLOCKS.format(EXAMPLE_PY) + +        # Note that get_bad_ticks_message expects the first line to have an extra newline. +        return ( +            "It looks like you pasted Python code without syntax highlighting.\n\n" +            "Please use syntax highlighting to improve the legibility of your code and make" +            "it easier for us to help you.\n\n" +            f"**To do this, use the following method:**\n{example_blocks}" +        ) diff --git a/bot/cogs/codeblock/parsing.py b/bot/cogs/codeblock/parsing.py index 7a096758b..d541441e0 100644 --- a/bot/cogs/codeblock/parsing.py +++ b/bot/cogs/codeblock/parsing.py @@ -7,8 +7,6 @@ import discord  log = logging.getLogger(__name__) -RE_MARKDOWN = re.compile(r'([*_~`|>])') -RE_CODE_BLOCK_LANGUAGE = re.compile(r"```(?:[^\W_]+)\n(.*?)```", re.DOTALL)  BACKTICK = "`"  TICKS = {      BACKTICK,  |