Files
md_to_gost/md2gost/renderable_factory.py
T
Igor20264 b38661f588
Python application / build (push) Has been cancelled
Update 0.4.0
- Add\Rework UI
- Add Split Table and Listing
- Add Support Customazeble schems
2026-09-04 22:28:39 +03:00

183 lines
8.1 KiB
Python

import logging
from functools import singledispatchmethod
from docx.shared import Parented, RGBColor
from .renderable import *
from .renderable import Renderable
from . import extended_markdown
from .renderable.caption import CaptionInfo
from .renderable.paragraph import Link
from .renderable.table import Table
from .renderable.equation import Equation
from .renderable.heading import Heading
from .renderable.list import List
from .renderable.toc import ToC
from .renderable.diagram import DiagramFigure
from .label_pass import resolve_reference
from .diagram_renderer import is_diagram_lang
class RenderableFactory:
def __init__(self, parent: Parented, hr_pagebreak: bool = False):
self._parent = parent
self._hr_pagebreak = hr_pagebreak
@singledispatchmethod
def create(self, marko_element: extended_markdown.BlockElement,
caption_info: CaptionInfo) -> Renderable:
paragraph = Paragraph(self._parent)
paragraph.add_run(f"{marko_element.get_type()} is not supported", color=RGBColor.from_string('ff0000'))
logging.warning(f"{marko_element.get_type()} is not supported")
return paragraph
@staticmethod
def _create_runs(paragraph_or_link: Paragraph | Link, children, classes: list[type] = None):
if not classes:
classes = []
for child in children:
if isinstance(child, (extended_markdown.RawText, extended_markdown.Literal)):
paragraph_or_link.add_run(child.children,
is_bold=extended_markdown.StrongEmphasis in classes or None,
is_italic=extended_markdown.Emphasis in classes or None,
strike_through=extended_markdown.Strikethrough in classes or None)
elif isinstance(child, extended_markdown.CodeSpan):
paragraph_or_link.add_run(child.children, is_italic=True)
elif isinstance(child, extended_markdown.Image):
caption = CaptionInfo(
child.unique_name,
child.title,
getattr(child, "with_listing", False),
getattr(child, "landscape", False),
)
paragraph_or_link.add_image(child.dest, caption)
elif isinstance(child, extended_markdown.LineBreak):
pass
elif isinstance(child, extended_markdown.InlineEquation):
paragraph_or_link.add_inline_equation(child.latex_equation)
elif isinstance(child, extended_markdown.Reference):
if hasattr(paragraph_or_link, "add_reference"):
paragraph_or_link.add_reference(child.type, child.name)
else:
paragraph_or_link.add_run(resolve_reference(child.type, child.name))
elif isinstance(child, (extended_markdown.Link, extended_markdown.Url)):
RenderableFactory._create_runs(paragraph_or_link.add_link(child.dest),
child.children, classes)
elif isinstance(child, (extended_markdown.Emphasis, extended_markdown.StrongEmphasis,
extended_markdown.Strikethrough)):
RenderableFactory._create_runs(paragraph_or_link,
child.children, classes + [type(child)])
else:
paragraph_or_link.add_run(f" {child.get_type()} is not supported ",
color=RGBColor.from_string("FF0000"))
logging.warning(f"{child.get_type()} is not supported")
@create.register
def _(self, marko_paragraph: extended_markdown.Paragraph, caption_info: CaptionInfo):
paragraph = Paragraph(self._parent)
RenderableFactory._create_runs(paragraph, marko_paragraph.children)
return paragraph
@create.register
def _(self, marko_heading: extended_markdown.Heading, caption_info: CaptionInfo):
heading = Heading(self._parent, marko_heading.level, marko_heading.numbered)
RenderableFactory._create_runs(heading, marko_heading.children)
return heading
@create.register
def _(self, marko_code_block: extended_markdown.FencedCode, caption_info: CaptionInfo):
lang = (marko_code_block.lang or "").strip().lower()
source = marko_code_block.children[0].children
if is_diagram_lang(lang):
return DiagramFigure(
self._parent,
lang,
source,
caption_info,
with_listing=bool(caption_info and caption_info.with_listing),
)
listing = Listing(self._parent, marko_code_block.lang, caption_info)
listing.set_text(source)
return listing
@create.register
def _(self, marko_code_block: extended_markdown.CodeBlock, caption_info: CaptionInfo):
lang = (getattr(marko_code_block, "lang", "") or "").strip().lower()
source = marko_code_block.children[0].children
if is_diagram_lang(lang):
return DiagramFigure(
self._parent,
lang,
source,
caption_info,
with_listing=bool(caption_info and caption_info.with_listing),
)
listing = Listing(self._parent, getattr(marko_code_block, "lang", "") or "", caption_info)
listing.set_text(source)
return listing
@create.register
def _(self, marko_equation: extended_markdown.Equation, caption_info: CaptionInfo):
unique = caption_info.unique_name if caption_info else None
formula = Equation(self._parent, marko_equation.latex_equation,
unique_name=unique, numbered=False)
return formula
@create.register
def _(self, marko_list: extended_markdown.List, caption_info: CaptionInfo):
list_ = List(self._parent, marko_list.ordered)
def create_items_from_marko(marko_list_, level=1):
for list_item in marko_list_.children:
for child in list_item.children:
if isinstance(child, extended_markdown.List):
create_items_from_marko(child, level + 1)
elif isinstance(child, extended_markdown.Paragraph):
RenderableFactory._create_runs(
list_.add_item(level),
child.children
)
create_items_from_marko(marko_list)
return list_
@create.register
def _(self, marko_table: extended_markdown.Table, caption_info: CaptionInfo):
table = Table(self._parent, len(marko_table.children), len(marko_table.children[0].children),
caption_info)
for i, row in enumerate(marko_table.children):
for j, cell in enumerate(row.children):
merge_v = getattr(cell, "merge_v", "none") or "none"
merge_h = getattr(cell, "merge_h", "none") or "none"
table.set_cell_merge(i, j, merge_v, merge_h)
if merge_v == "continue" or merge_h == "continue":
# Placeholder paragraph so cell is still addressable; content unused on render
table.add_paragraph_to_cell(i, j)
continue
RenderableFactory._create_runs(
table.add_paragraph_to_cell(i, j),
cell.children
)
return table
@create.register
def _(self, marko_toc: extended_markdown.TOC, caption_info: CaptionInfo):
toc = ToC(self._parent)
return toc
@create.register
def _(self, marko_hr: extended_markdown.ThematicBreak, caption_info: CaptionInfo):
if self._hr_pagebreak:
from .renderable.page_break import PageBreak
return PageBreak(self._parent)
paragraph = Paragraph(self._parent)
paragraph.add_run(
"ThematicBreak is not supported",
color=RGBColor.from_string("ff0000"),
)
logging.warning("ThematicBreak is not supported")
return paragraph