112 lines
2.5 KiB
Python
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)
|