Pi66

merodi
A markdown-based static site generator.
git clone https://git.pi66.xyz/merodi

← back to log

fix: prevent inline regex from matching backticks inside fenced blocks

author: pi66
date: 2026-06-27 20:27
hash: 1c37cef695b27e19d92d5a524bc2a1ac1d77c6af

Diffstat:

M

src/build.py
19 ++++++++++++++++++++++++------
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
diff --git a/src/build.py b/src/build.py
index 995d79b..80e006a 100644
--- a/src/build.py
+++ b/src/build.py
@@ -71,12 +71,23 @@ def jinja_handler(file, html_content, config=None):
         return html_fatal(e, f"Template error in {file}")

 def escape_code_blocks(md_content: str) -> str:
-    def wrap(m):
+    def wrap_fenced(m):
         return "\n{% raw %}\n" + m.group(0) + "\n{% endraw %}\n"

-    md_content = re.sub(r'`{3}[\s\S]*?`{3}', wrap, md_content)  # fenced ```
-    md_content = re.sub(r'`[^`\n]+`', wrap, md_content)          # inline `
-    return md_content
+    def wrap_inline(m):
+        return "\n{% raw %}" + m.group(0) + "{% endraw %}\n"
+
+    # split on fenced blocks, process alternating parts
+    parts = re.split(r'(`{3}[\s\S]*?`{3})', md_content)
+    result = []
+    for i, part in enumerate(parts):
+        if i % 2 == 1:
+            # fenced block — wrap it, skip inline pass
+            result.append(wrap_fenced(re.match(r'`{3}[\s\S]*?`{3}', part)))
+        else:
+            # outside fenced — only apply inline escaping here
+            result.append(re.sub(r'`[^`\n]+`', wrap_inline, part))
+    return "".join(result)

 def save_html(html_content:str, html_dest:str):
     makedirs( dirname( abspath(html_dest)), exist_ok=True )