feat(md2doc): table, pre, blockquote, hr renderers

This commit is contained in:
2026-07-28 10:27:02 +03:00
parent 5fd05ba2be
commit 21b3a7a77d
2 changed files with 139 additions and 0 deletions
+65
View File
@@ -365,6 +365,71 @@ def _render_list(doc, node, style: dict, level: int = 0, num_state: dict = None)
_render_list(doc, nested, style=style, level=level + 1, num_state=num_state)
def _render_table(doc, node, style: dict):
"""Render <table> with header row shading."""
header_fill = style.get("table_header_fill", "1e3a8a")
rows = node.find_all("tr")
if not rows:
return
cols = max(len(row.find_all(["th", "td"])) for row in rows)
table = doc.add_table(rows=len(rows), cols=cols)
table.style = 'Table Grid'
for i, row in enumerate(rows):
cells = row.find_all(["th", "td"])
is_header = row.parent.name == "thead" or any(c.name == "th" for c in cells)
for j, cell in enumerate(cells):
if j >= cols:
break
tc = table.rows[i].cells[j]
tc.text = cell.get_text(strip=True)
if is_header:
add_cell_shading(tc, fill=header_fill)
def _render_pre(doc, node, style: dict):
"""Render <pre> (code block) — shaded background + monospace font.
Preserves newlines via add_break() between lines (Word ignores literal \\n in runs).
Leading whitespace on each line is preserved as literal spaces (monospace font
keeps alignment). Trailing empty line from markdown's final \\n is dropped.
"""
code_fill = style.get("code_fill", "f7f8fa")
text = node.get_text()
lines = text.split("\n")
while lines and lines[-1] == "":
lines.pop()
p = doc.add_paragraph()
for i, line in enumerate(lines):
if i > 0:
p.add_run().add_break()
run = p.add_run(line)
run.font.name = "Menlo"
run.font.size = Pt(8)
add_paragraph_shading(p, fill=code_fill)
def _render_blockquote(doc, node, style: dict):
"""Render <blockquote> — left indent + italic + shading."""
quote_fill = style.get("blockquote_fill", "f7f8fa")
text = node.get_text(strip=True)
p = doc.add_paragraph()
p.paragraph_format.left_indent = Cm(1)
run = p.add_run(text)
run.italic = True
add_paragraph_shading(p, fill=quote_fill)
def _render_hr(doc, node, style: dict):
"""Render <hr> as empty paragraph with bottom border."""
p = doc.add_paragraph()
add_paragraph_bottom_border(p, color="d8d8d8", size="6")
def convert_md_to_doc(md_file: Path, output_file: Path, style: str = "elegant") -> Path:
"""Convert a single markdown file to DOCX.