Files
omicron-ssg/omicron/ssg/markdown.py
T

52 lines
1.5 KiB
Python

from typing import cast
from markdown_it import MarkdownIt
from markdown_it.token import Token as Token
from pygments import highlight as pygments_highlight
from pygments.formatters import HtmlFormatter
from pygments.lexers import get_lexer_by_name
from pygments.lexers.special import TextLexer
from pygments.util import ClassNotFound
from markupsafe import Markup
text_lexer = TextLexer()
html_formatter = HtmlFormatter()
class MarkdownError(RuntimeError):
pass
def highlight_style() -> str:
style = html_formatter.get_style_defs(".highlight") # type: ignore[no-untyped-call]
return cast(str, style)
def highlight(code: str, lang: str, attrs: str) -> str:
try:
lexer = get_lexer_by_name(lang) if lang else text_lexer
except ClassNotFound:
lexer = text_lexer
return pygments_highlight(code, lexer, html_formatter)
md = MarkdownIt(options_update={"highlight": highlight})
def render_summary(tokens: list[Token]) -> Markup:
if not tokens or tokens[0].type != "paragraph_open" or tokens[0].hidden:
raise MarkdownError(
"Body does not start with a paragraph; set 'summary' in frontmatter"
)
for j in range(1, len(tokens)):
if tokens[j].type == "paragraph_close":
return Markup(md.renderer.render(tokens[1:j], md.options, {}))
raise MarkdownError("Content has no paragraph to use as summary")
def render(tokens: list[Token]) -> Markup:
return Markup(md.renderer.render(tokens, md.options, {}))
def parse(body: str) -> list[Token]:
return md.parse(body)