wrapper,
and the stylesheet is scoped to "pre code" to match.
"""
try:
lexer = get_lexer_by_name(lang)
except ClassNotFound:
return "" # fall back to default
return highlight(text, lexer, _formatter)
def _image_rule(
self: RendererHTML,
tokens,
idx: int,
options,
env: dict,
) -> str:
"""Render images, resolving relative srcs against the page path."""
token = tokens[idx]
src = token.attrs["src"]
if not src.startswith(("/", "http://", "https://", "data:")):
page = env.get("page_path", "")
token.attrs["src"] = f"/{page}/{src}" if page else f"/{src}"
token.attrs["alt"] = self.renderInlineAsText(token.children, options, env)
img = self.renderToken(tokens, idx, options, env)
if len(tokens) == 1:
# The only inline content of its paragraph: render as a block
# figure, captioned when titled. (The
wrapper is dropped by
# _unwrap_lone_figures below.)
title = token.attrs.get("title")
caption = f"{escapeHtml(title)}" if title else ""
return f"{img}{caption}"
# Inline with other content: a plain inline image.
return img
def _unwrap_lone_figures(state) -> None:
"""Drop the
wrapper around a lone image.
markdown-it wraps inline content in a paragraph, but our image rule
turns lone images into — a block element that is invalid
inside
. Browsers hoist it out, leaving an empty paragraph whose
margins disturb the layout.
"""
tokens = state.tokens
for i, token in enumerate(tokens):
if token.type != "inline" or not token.children:
continue
[child] = token.children if len(token.children) == 1 else [None]
if child and child.type == "image":
if (tokens[i - 1].type == "paragraph_open"
and tokens[i + 1].type == "paragraph_close"):
tokens[i - 1].hidden = True
tokens[i + 1].hidden = True
def _tag_task_checkboxes(state) -> None:
"""Tag rendered task-list checkboxes with a stable index.
The public page and the editor preview use the index to identify which
`[ ]`/`[x]` marker in the Markdown source to toggle when a visitor
clicks the checkbox.
"""
index = 0
for token in state.tokens:
if token.type != "inline" or not token.children:
continue
for child in token.children:
if child.type == "html_inline" and 'type="checkbox"' in child.content:
child.content = child.content.replace(
'type="checkbox"',
f'data-task-index="{index}" type="checkbox"',
1,
)
index += 1
def _shorten_autolinks(state) -> None:
"""Hide the https:// scheme in the text of bare autolinked URLs.
GFM linkify sets the link text to the URL itself; only those links
(markup "autolink") are shortened. http:// and other schemes stay
visible, and manually labelled links keep whatever label was written.
"""
for token in state.tokens:
if token.type != "inline" or not token.children:
continue
for i, child in enumerate(token.children):
if child.type == "link_open" and child.markup == "autolink":
text = token.children[i + 1]
if text.type == "text" and text.content.startswith("https://"):
text.content = text.content.removeprefix("https://")
md = (
MarkdownIt(
"default",
{
"html": True,
"highlight": _highlight,
"typographer": True,
"breaks": True,
},
)
.use(attrs_plugin)
.use(admon_plugin)
.use(footnote_plugin)
.use(deflist_plugin)
.use(tasklists_plugin, enabled=True)
.use(gfm_autolink_plugin)
.use(sub_plugin)
.use(superscript_plugin)
)
md.add_render_rule("image", _image_rule)
md.core.ruler.push("unwrap_lone_figures", _unwrap_lone_figures)
md.core.ruler.push("tag_task_checkboxes", _tag_task_checkboxes)
md.core.ruler.push("shorten_autolinks", _shorten_autolinks)
def render(
text: str,
page_path: str = "",
created: datetime | None = None,
modified: datetime | None = None,
) -> str:
"""Render Markdown text to an HTML string.
A ``{dates}`` line expands to the article's published/updated dateline
(needs ``created``/``modified``; left as-is in contexts without them,
e.g. the editor preview). Position is the author's choice — typically
right after the article's h1.
"""
html = md.render(text, {"page_path": page_path})
if created is not None and "
{dates}
" in html:
html = html.replace("
{dates}
", _dateline(created, modified))
return html
def _dateline(created: datetime, modified: datetime | None) -> str:
"""Dateline for the ``{dates}`` tag: "1 Jan 2026", plus
" – edited 3 Jan 2026" when the last edit came >= 24h after
publishing (quick fixes right after posting stay unmentioned)."""
out = f''
if modified is not None and modified - created >= timedelta(hours=24):
out += f' – edited '
return f'
{out}
'
def has_h1(text: str) -> bool:
"""True if the Markdown source itself contains an h1 heading.
When it does, the article owns its heading and the page title is not
rendered as an additional h1 (the title is still used for the document
and navigation labels).
"""
return any(t.type == "heading_open" and t.tag == "h1" for t in md.parse(text))
def toggle_task(text: str, index: int) -> str | None:
"""Toggle the Nth task-list checkbox marker in ``text``.
Returns the modified Markdown source, or ``None`` if the index is out
of range or the marker could not be found.
"""
tokens = md.parse(text, {"page_path": ""})
checkbox_lines: list[int | None] = []
for token in tokens:
if token.type == "inline" and token.children:
for child in token.children:
if child.type == "html_inline" and 'type="checkbox"' in child.content:
checkbox_lines.append(token.map[0] if token.map else None)
break
if not (0 <= index < len(checkbox_lines)):
return None
line_idx = checkbox_lines[index]
if line_idx is None or line_idx < 0:
return None
lines = text.splitlines(keepends=True)
if line_idx >= len(lines):
return None
line = lines[line_idx]
def repl(m: re.Match[str]) -> str:
prefix = m.group(1)
marker = m.group(2)
new_marker = "x" if marker.strip() == "" else " "
return f"{prefix}[{new_marker}]{m.group(3)}"
new_line = _TASK_MARKER_RE.sub(repl, line, count=1)
if new_line == line:
return None
lines[line_idx] = new_line
return "".join(lines)