1from html.parser import HTMLParser
2
3import mistune
4from pygments import highlight
5from pygments.formatters import html
6from pygments.lexers import get_lexer_by_name
7
8from plain.utils.text import slugify
9
10
11class PagesRenderer(mistune.HTMLRenderer):
12 def heading(self, text, level, **attrs):
13 """Automatically add an ID to headings if one is not provided."""
14
15 if "id" not in attrs:
16 inner_text = get_inner_text(text)
17 attrs["id"] = slugify(inner_text)
18
19 return super().heading(text, level, **attrs)
20
21 def block_code(self, code, info=None):
22 """Highlight code blocks using Pygments."""
23
24 if info:
25 lexer = get_lexer_by_name(info, stripall=True)
26 formatter = html.HtmlFormatter(wrapcode=True)
27 return highlight(code, lexer, formatter)
28
29 return "<pre><code>" + mistune.escape(code) + "</code></pre>"
30
31
32def render_markdown(content):
33 renderer = PagesRenderer(escape=False)
34 markdown = mistune.create_markdown(
35 renderer=renderer, plugins=["strikethrough", "table"]
36 )
37 return markdown(content)
38
39
40class InnerTextParser(HTMLParser):
41 def __init__(self):
42 super().__init__()
43 self.text_content = []
44
45 def handle_data(self, data):
46 # Collect all text data
47 self.text_content.append(data.strip())
48
49
50def get_inner_text(html_content):
51 parser = InnerTextParser()
52 parser.feed(html_content)
53 return " ".join([text for text in parser.text_content if text])