Files
md_to_gost/md2gost/renderable/list.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

97 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from copy import copy
from typing import Generator
from docx.shared import Pt, Cm, Twips
from . import Paragraph
from .renderable import Renderable
from ..layout_tracker import LayoutState
from ..rendered_info import RenderedInfo
# ТЗ табл. 2.2: маркер 1,25 см; текст / табуляция 2,25 см
MARKER_POS = Cm(1.25)
TEXT_POS = Cm(2.25)
BULLET = "" # en dash, единый маркер на весь документ
class List(Renderable):
def __init__(self, parent, ordered: bool):
self._parent = parent
self._ordered = ordered
self._paragraphs: list[Paragraph] = []
self._last_paragraph_space_after = 0
self._numbering = [0 for _ in range(10)]
self._item_count = 0
def add_item(self, level: int) -> Paragraph:
self._numbering[level - 1] += 1
for i in range(level, len(self._numbering)):
self._numbering[i] = 0
self._item_count += 1
paragraph = Paragraph(self._parent)
if self._ordered:
marker = f"{self._numbering[level - 1]}."
else:
marker = BULLET
paragraph.add_run(marker + "\t")
# hanging indent: left = TEXT_POS (+ nesting), first_line = MARKER_POS - TEXT_POS
nest = TEXT_POS * (level - 1)
paragraph._docx_paragraph.paragraph_format.tab_stops.add_tab_stop(TEXT_POS + nest)
paragraph._docx_paragraph.paragraph_format.left_indent = TEXT_POS + nest
paragraph._docx_paragraph.paragraph_format.first_line_indent = MARKER_POS - TEXT_POS
self._last_paragraph_space_after = paragraph._docx_paragraph.paragraph_format.space_after
paragraph._docx_paragraph.paragraph_format.space_before = 0
paragraph._docx_paragraph.paragraph_format.space_after = 0
self._paragraphs.append(paragraph)
return paragraph
def finalize_punctuation(self) -> None:
"""Apply TZ list punctuation: bullet → lowercase + ';' (last '.'); numbered → Capital + '.'."""
for i, paragraph in enumerate(self._paragraphs):
runs = paragraph._docx_paragraph.runs
if len(runs) < 2:
continue
# Text after marker run
text_runs = runs[1:]
full = "".join(r.text or "" for r in text_runs).strip()
if not full:
continue
is_last = i == len(self._paragraphs) - 1
if self._ordered:
fixed = full[0].upper() + full[1:] if full else full
if not fixed.endswith("."):
fixed = fixed.rstrip(";,. ") + "."
else:
fixed = full[0].lower() + full[1:] if full else full
if is_last:
fixed = fixed.rstrip(";,. ") + "."
else:
fixed = fixed.rstrip(";,. ") + ";"
# Put all text into first content run, clear others
text_runs[0].text = fixed
for r in text_runs[1:]:
r.text = ""
def render(self, previous_rendered: RenderedInfo, layout_state: LayoutState) -> Generator[
RenderedInfo | Renderable, None, None]:
self.finalize_punctuation()
if self._paragraphs:
self._paragraphs[-1]._docx_paragraph.paragraph_format.space_after = self._last_paragraph_space_after
if getattr(self, "_space_before_mm6", False) and self._paragraphs:
from docx.shared import Mm
self._paragraphs[0]._docx_paragraph.paragraph_format.space_before = Mm(6)
for paragraph in self._paragraphs:
for x in paragraph.render(previous_rendered, copy(layout_state)):
layout_state.add_height(x.height)
previous_rendered = x
yield x