82 lines
2.5 KiB
Python
Raw Normal View History

2025-01-24 14:00:10 +01:00
# Original source: https://brandonjay.dev/posts/2021/render-markdown-html-in-python-with-jinja2
2025-01-24 23:33:36 +01:00
from types import SimpleNamespace
2025-01-24 23:35:44 +01:00
from app.cache import time_cache_async
from mistune import HTMLRenderer, Markdown
2025-01-24 14:00:10 +01:00
from pygments import highlight
from pygments.formatters import html
2025-01-24 23:35:44 +01:00
from pygments.lexers import get_lexer_by_name
2025-01-24 14:00:10 +01:00
class MarkdownRenderer(HTMLRenderer):
2025-01-24 23:33:36 +01:00
_allow_harmful_protocols = True
2025-01-24 23:35:44 +01:00
2025-01-24 14:00:10 +01:00
def __init__(self, app, template):
2025-01-24 23:35:44 +01:00
self.template = template
self.app = app
self.env = self.app.jinja2_env
formatter = html.HtmlFormatter()
self.env.globals["highlight_styles"] = formatter.get_style_defs()
def _escape(self, str):
return str ##escape(str)
def block_code(self, code, lang=None, info=None):
2025-01-24 14:00:10 +01:00
if not lang:
lang = info
if not lang:
return f"<div>{code}</div>"
2025-01-24 23:35:44 +01:00
# return '\n<pre><code>%s</code></pre>\n' % escape(code)
2025-01-24 14:00:10 +01:00
lexer = get_lexer_by_name(lang, stripall=True)
formatter = html.HtmlFormatter(lineseparator="<br>")
return highlight(code, lexer, formatter)
2025-01-24 23:35:44 +01:00
2025-01-24 14:00:10 +01:00
def render(self):
markdown_string = self.app.template_path.joinpath(self.template).read_text()
2025-01-24 23:35:44 +01:00
renderer = MarkdownRenderer(self.app, self.template)
2025-01-24 14:00:10 +01:00
markdown = Markdown(renderer=renderer)
return markdown(markdown_string)
2025-01-24 16:08:56 +01:00
def render_markdown_sync(app, markdown_string):
2025-01-24 23:35:44 +01:00
renderer = MarkdownRenderer(app, None)
2025-01-24 16:08:56 +01:00
markdown = Markdown(renderer=renderer)
return markdown(markdown_string)
2025-01-24 23:35:44 +01:00
2025-01-24 16:33:27 +01:00
@time_cache_async(120)
2025-01-24 14:00:10 +01:00
async def render_markdown(app, markdown_string):
2025-01-24 23:35:44 +01:00
return render_markdown_sync(app, markdown_string)
2025-01-24 23:33:36 +01:00
2025-01-24 23:35:44 +01:00
from jinja2 import TemplateSyntaxError, nodes
2025-01-24 23:33:36 +01:00
from jinja2.ext import Extension
from jinja2.nodes import Const
2025-01-24 23:35:44 +01:00
2025-01-24 23:33:36 +01:00
# Source: https://ron.sh/how-to-write-a-jinja2-extension/
class MarkdownExtension(Extension):
2025-01-24 23:35:44 +01:00
tags = {"markdown"}
2025-01-24 23:33:36 +01:00
def __init__(self, environment):
self.app = SimpleNamespace(jinja2_env=environment)
super(MarkdownExtension, self).__init__(environment)
def parse(self, parser):
line_number = next(parser.stream).lineno
2025-01-24 23:35:44 +01:00
md_file = [Const("")]
body = ""
2025-01-24 23:33:36 +01:00
try:
md_file = [parser.parse_expression()]
except TemplateSyntaxError:
2025-01-24 23:35:44 +01:00
body = parser.parse_statements(["name:endmarkdown"], drop_needle=True)
return nodes.CallBlock(
self.call_method("_to_html", md_file), [], [], body
).set_lineno(line_number)
2025-01-24 23:33:36 +01:00
def _to_html(self, md_file, caller):
2025-01-24 23:35:44 +01:00
return render_markdown_sync(self.app, caller())