Files
md2gost/md2gost/handlers/inline.py
T

112 lines
2.5 KiB
Python

"""Инлайн-рендер: обработка токенов внутри абзацев и заголовков.
Диспетчеризация табличная (registry.INLINE): тип токена -> функция
``(tok) -> str``. Новый инлайн-узел = одна функция с декоратором.
"""
from __future__ import annotations
import sys
from markdown_it.token import Token
from md2gost.registry import INLINE, inline
_LATEX_SPECIAL = str.maketrans(
{
"&": r"\&",
"%": r"\%",
"$": r"\$",
"#": r"\#",
"_": r"\_",
"{": r"\{",
"}": r"\}",
"~": r"\textasciitilde{}",
"^": r"\textasciicircum{}",
"\\": r"\textbackslash{}",
}
)
def escape_latex(text: str) -> str:
return text.translate(_LATEX_SPECIAL)
@inline("text")
def _text(tok: Token) -> str:
return escape_latex(tok.content)
@inline("strong_open")
def _strong_open(tok: Token) -> str:
return r"\textbf{"
@inline("strong_close")
def _strong_close(tok: Token) -> str:
return "}"
@inline("em_open")
def _em_open(tok: Token) -> str:
return r"\textit{"
@inline("em_close")
def _em_close(tok: Token) -> str:
return "}"
@inline("code_inline")
def _code_inline(tok: Token) -> str:
return f"\\texttt{{\\small {escape_latex(tok.content)}}}"
@inline("link_open")
def _link_open(tok: Token) -> str:
href = str(tok.attrGet("href") or "")
return f"\\href{{{escape_latex(href)}}}{{"
@inline("link_close")
def _link_close(tok: Token) -> str:
return "}"
@inline("softbreak")
@inline("hardbreak")
def _break(tok: Token) -> str:
return "~\\\\"
@inline("math_inline")
def _math_inline(tok: Token) -> str:
return f"${tok.content}$"
@inline("image")
def _image_in_text(tok: Token) -> str:
print(
"предупреждение: картинка внутри текста пропущена "
"(по ГОСТ рисунок оформляется отдельным абзацем)",
file=sys.stderr,
)
return ""
def render_inline(tok: Token) -> str:
if not tok.children:
return escape_latex(tok.content or "")
return render_inline_tokens(tok.children)
def render_inline_tokens(tokens: list[Token]) -> str:
parts: list[str] = []
for tok in tokens:
handler = INLINE.get(tok.type)
if handler is not None:
parts.append(handler(tok))
else:
parts.append(escape_latex(tok.content) if tok.content else "")
return "".join(parts)