@@ -0,0 +1,163 @@
|
||||
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 DIAGRAM_LANGS
|
||||
|
||||
|
||||
class RenderableFactory:
|
||||
def __init__(self, parent: Parented):
|
||||
self._parent = parent
|
||||
|
||||
@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)
|
||||
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 lang in DIAGRAM_LANGS:
|
||||
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 lang in DIAGRAM_LANGS:
|
||||
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
|
||||
Reference in New Issue
Block a user