Files
Igor20264 516abe7b83
Python application / build (push) Has been cancelled
BigUpdate
2026-09-03 10:44:08 +03:00

160 lines
5.8 KiB
Python
Raw Permalink 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.
"""Pre-assign section-scoped numbers and resolve @Type:label references."""
from __future__ import annotations
import re
from .numberer import Numberer, APPENDIX_LETTERS
from .renderable import Renderable
from .renderable.heading import Heading
from .renderable.requires_numbering import RequiresNumbering
from .renderable.equation import Equation
from .renderable.paragraph import Paragraph
from .renderable.caption import CaptionInfo
APPENDIX_RE = re.compile(r"^ПРИЛОЖЕНИЕ\s+([А-ЯA-Z])\b", re.IGNORECASE)
class LabelRegistry:
def __init__(self):
self._map: dict[tuple[str, str], str] = {}
def put(self, category: str, name: str, number: str):
self._map[(category.lower(), name)] = number
# also store without category for loose lookup
self._map[("*", name)] = f"{category} {number}"
def get(self, category: str, name: str) -> str | None:
return self._map.get((category.lower(), name))
def get_display(self, category: str, name: str) -> str | None:
n = self.get(category, name)
if n:
return f"{category} {n}"
# try Russian category aliases
aliases = {
"рисунок": "Рисунок",
"figure": "Рисунок",
"таблица": "Таблица",
"table": "Таблица",
"листинг": "Листинг",
"listing": "Листинг",
"формула": "Формула",
"formula": "Формула",
"equation": "Формула",
}
cat = aliases.get(category.lower(), category)
n = self.get(cat, name)
if n:
return f"{cat} {n}"
return None
def assign_numbers(renderables: list[Renderable],
numbered_equations: set[str] | None = None,
numbering_scope: str = "section") -> LabelRegistry:
"""Walk renderables once, set_number on objects, fill LabelRegistry."""
numbered_equations = numbered_equations or set()
numberer = Numberer(mode=numbering_scope)
registry = LabelRegistry()
section_count = 0
appendix_index = 0
for r in renderables:
if isinstance(r, Heading):
text = (r.text or "").strip()
upper = text.upper()
if r.level == 1 and r.is_numbered:
section_count += 1
numberer.enter_section(section_count)
m = APPENDIX_RE.match(upper)
if m:
numberer.enter_appendix(m.group(1).upper())
elif upper.startswith("ПРИЛОЖЕНИЕ"):
parts = upper.split()
if len(parts) >= 2 and parts[1] in APPENDIX_LETTERS:
numberer.enter_appendix(parts[1])
elif appendix_index < len(APPENDIX_LETTERS):
numberer.enter_appendix(APPENDIX_LETTERS[appendix_index])
appendix_index += 1
if isinstance(r, Equation):
label = r.unique_name
if r.needs_numbering or (label and label in numbered_equations):
r.enable_numbering()
num = numberer.next_number("Формула", label)
r.set_number(num)
if label:
registry.put("Формула", label, num)
continue
if isinstance(r, RequiresNumbering):
label = getattr(r, "unique_name", None)
num = numberer.next_number(r.numbering_category, label)
r.set_number(num)
if label:
registry.put(r.numbering_category, label, num)
# Diagram +listing → also number Листинг with same label
from .renderable.diagram import DiagramFigure
if isinstance(r, DiagramFigure) and r.listing is not None:
lnum = numberer.next_number("Листинг", label)
r.set_listing_number(lnum)
if label:
registry.put("Листинг", label, lnum)
# Images nested in paragraphs
if isinstance(r, Paragraph):
pass
# Images attached to paragraphs
if isinstance(r, Paragraph):
for img in getattr(r, "_images", []):
label = getattr(img, "unique_name", None)
num = numberer.next_number(img.numbering_category, label)
img.set_number(num)
if label:
registry.put(img.numbering_category, label, num)
return registry
def resolve_pending_in_renderables(renderables: list[Renderable], resolve_fn) -> None:
"""Resolve @Type:label placeholders in paragraphs, lists, headings and table cells."""
from .renderable.list import List as RList
from .renderable.table import Table
from .renderable.heading import Heading
def resolve_para(p):
if hasattr(p, "resolve_pending_refs"):
p.resolve_pending_refs(resolve_fn)
for r in renderables:
if isinstance(r, Paragraph):
resolve_para(r)
elif isinstance(r, Heading):
resolve_para(r)
elif isinstance(r, RList):
for p in getattr(r, "_paragraphs", []):
resolve_para(p)
elif isinstance(r, Table):
for row in getattr(r, "_rows", []):
for cell in row:
for p in cell:
resolve_para(p)
# Patch Paragraph to resolve references at run-creation time via module-level registry
_ACTIVE_REGISTRY: LabelRegistry | None = None
def set_active_registry(registry: LabelRegistry | None):
global _ACTIVE_REGISTRY
_ACTIVE_REGISTRY = registry
def resolve_reference(type_: str, name: str) -> str:
if _ACTIVE_REGISTRY is None:
return f"{type_}?"
display = _ACTIVE_REGISTRY.get_display(type_, name)
return display or f"{type_}?"