Files
md_to_gost/mdexport/inline.py
T
Igor20264 f7136bd8bd
Example document / build (push) Has been cancelled
Python application / build (push) Has been cancelled
v0.5.3
- Мелкие исправления увеличивающие работу конвертера
2026-09-10 10:50:15 +03:00

99 lines
3.0 KiB
Python

"""Backend-agnostic traversal of md2gost inline AST nodes."""
from __future__ import annotations
from abc import ABC, abstractmethod
#: Wording used when a `@Тип:id` reference is spelled out, per ГОСТ 7.32.
REFERENCE_FULL_NAMES = {
"рисунок": "Рисунок",
"таблица": "Таблица",
"листинг": "Листинг",
"формула": "формула",
}
def reference_full_name(ref_type: str) -> str:
return REFERENCE_FULL_NAMES.get(ref_type.lower(), ref_type)
class InlineRenderer(ABC):
"""
Formatting hooks for :func:`render_inline`.
Defaults are provided only for the nodes every backend renders the same
way; everything else is abstract so a new backend cannot silently drop a
node type.
"""
@abstractmethod
def escape(self, text: str) -> str:
...
@abstractmethod
def code_span(self, node) -> str:
...
@abstractmethod
def emphasis(self, inner: str) -> str:
...
@abstractmethod
def strong_emphasis(self, inner: str) -> str:
...
@abstractmethod
def link(self, node, inner: str) -> str:
...
@abstractmethod
def reference(self, node) -> str:
...
@abstractmethod
def inline_equation(self, node) -> str:
...
@abstractmethod
def line_break(self) -> str:
...
def raw_text(self, text: str) -> str:
return self.escape(text)
def image(self, node) -> str:
return "" # images carry a caption, so they are emitted at block level
def unknown(self, node) -> str:
return self.escape(str(node))
def render_inline(children, renderer: InlineRenderer) -> str:
"""Render a list of inline nodes into a backend-specific string."""
parts: list[str] = []
for child in children or []:
node_type = type(child).__name__
if node_type in ("RawText", "Literal"):
parts.append(renderer.raw_text(getattr(child, "children", "") or ""))
elif node_type == "CodeSpan":
parts.append(renderer.code_span(child))
elif node_type == "Emphasis":
parts.append(renderer.emphasis(render_inline(child.children, renderer)))
elif node_type == "StrongEmphasis":
parts.append(renderer.strong_emphasis(render_inline(child.children, renderer)))
elif node_type == "Link":
parts.append(renderer.link(child, render_inline(child.children, renderer)))
elif node_type == "Reference":
parts.append(renderer.reference(child))
elif node_type == "InlineEquation":
parts.append(renderer.inline_equation(child))
elif node_type == "Image":
parts.append(renderer.image(child))
elif node_type == "LineBreak":
parts.append(renderer.line_break())
elif hasattr(child, "children"):
parts.append(render_inline(child.children, renderer))
else:
parts.append(renderer.unknown(child))
return "".join(parts)