From 4ece6b0d15b4df92e2be4775c69c0856f0c32f67 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= <hugo@lysator.liu.se>
Date: Mon, 26 Jun 2023 19:59:51 +0200
Subject: [PATCH] Change markdown implementation.

Python-commonmark is deprecated, and recommends markdown-it-py instead.

This commit also introduces an abstract muppet.markdown module to allow
easier switching in the future, and enables id's for all headers in the
generated HTML.
---
 muppet/format.py   |  8 ++++----
 muppet/markdown.py | 49 ++++++++++++++++++++++++++++++++++++++++++++++
 muppet/output.py   |  6 +++---
 setup.cfg          |  3 ++-
 4 files changed, 58 insertions(+), 8 deletions(-)
 create mode 100644 muppet/markdown.py

diff --git a/muppet/format.py b/muppet/format.py
index 67aa555..97c38d1 100644
--- a/muppet/format.py
+++ b/muppet/format.py
@@ -6,7 +6,7 @@ provided as the first element. This program goes through every
 definition in it, and outputs a complete index.html.
 """
 
-from commonmark import commonmark
+from .markdown import markdown
 from subprocess import CalledProcessError
 import html
 import sys
@@ -1067,13 +1067,13 @@ def print_docstring(name: str, docstring: dict[str, Any]) -> str:
     #         if text := t.get('text'):
     #             text = re.sub(r'(NOTE|TODO)',
     #                           r'<mark>\1</mark>',
-    #                           commonmark(text))
+    #                           markdown(text))
     #             out += f"<dd>{text}</dd>"
     # out += '</dl>'
 
     if 'text' in docstring:
         out += '<div>'
-        out += commonmark(docstring['text'])
+        out += markdown(docstring['text'])
         out += '</div>'
 
     return out
@@ -1101,7 +1101,7 @@ def build_param_dict(docstring: dict[str, Any]) -> dict[str, str]:
                 if text := t.get('text'):
                     obj[t['name']] = re.sub(r'(NOTE|TODO)',
                                             r'<mark>\1</mark>',
-                                            commonmark(text))
+                                            markdown(text))
         return obj
     else:
         return {}
diff --git a/muppet/markdown.py b/muppet/markdown.py
new file mode 100644
index 0000000..df54fee
--- /dev/null
+++ b/muppet/markdown.py
@@ -0,0 +1,49 @@
+"""
+Muppet central markdown module.
+
+This module exports one procedure, ``markdown``. This to easily
+configure all markdown rendering to be the same in one central place,
+and to allow "easy" switching of the markdown engine.
+"""
+
+from markdown_it import MarkdownIt
+from mdit_py_plugins.anchors import anchors_plugin
+
+
+def markdown(text: str) -> str:
+    """
+    Render the given markdown string to HTML.
+
+    The current implementations sets these options and plugins:
+
+    html
+        Enable HTML in the source, which will be passed verbatim
+
+    linkify
+        Things which looks like links will be hyperlinked
+
+    anchors_plugin
+        Each header will get an appropriate id-attribute set, allowing
+        hyperlinks to it.
+
+    table
+        Allow markdown tables.
+
+    strikethrough
+        Allow GFM-like strikethrough (``~~striken out~~``).
+
+    :param text:
+        A Markdown string.
+
+    :returns:
+        A HTML string.
+    """
+    md = MarkdownIt('commonmark', {'html': True, 'linkify': True}) \
+        .use(anchors_plugin) \
+        .enable('table') \
+        .enable('strikethrough')
+
+    return md.render(text)
+
+
+# header_text.downcase().replace(' ', '-')
diff --git a/muppet/output.py b/muppet/output.py
index 242b3b5..0e83c58 100644
--- a/muppet/output.py
+++ b/muppet/output.py
@@ -14,7 +14,7 @@ from jinja2 import (
     FileSystemLoader,
 )
 from .lookup import lookup, Ref
-from commonmark import commonmark
+from .markdown import markdown
 from .format import (
     format_class,
     format_type_alias,
@@ -103,7 +103,7 @@ def index_item(obj: dict) -> IndexItem:
     }
 
     if summary:
-        out['summary'] = commonmark(summary)
+        out['summary'] = markdown(summary)
 
     return out
 
@@ -356,7 +356,7 @@ def setup_module(base: str, module: ModuleEntry, *, path_base: str) -> None:
         pathlib.Path(os.path.join(path, name)).mkdir(exist_ok=True)
         out_path = os.path.join(path, name, 'index.html')
 
-        content = commonmark(raw_content)
+        content = markdown(raw_content)
         template = jinja.get_template('content.html')
         crumbs = breadcrumbs(('Environment', ''),
                              module.name,
diff --git a/setup.cfg b/setup.cfg
index 9192dda..8d2416d 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -29,6 +29,7 @@ packages = muppet
 python_requires = >= 3.10
 install_requires =
 	jinja2~=3.1.2
-	commonmark~=0.9.1
+	markdown-it-py~=2.2
+	mdit_py_plugins=~0.3
 setup_requires =
 	setuptools
-- 
GitLab