aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/cogs/codeblock/cog.py63
-rw-r--r--bot/cogs/codeblock/instructions.py113
-rw-r--r--bot/cogs/codeblock/parsing.py2
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,