S07: Iteration B3 und B3.5 fuer Teilgebiet 01 abgeschlossen. B3 in build/build-reference-docx.py ergaenzt: DocDefault widowControl plus keepNext und keepLines auf Heading 1/2/3 und FirstParagraph (Pandoc-Stil fuer ersten Absatz nach einem Heading, deckt die fett formatierten Kenntnisse-Subsection-Labels KI Software-Design Methodik IT etc ab). Erster Versuch Compact-Stil mit keepNext hat Listen komplett unteilbar gemacht (Job-Stationen begannen jedes Mal auf einer neuen Seite, ungenutzte Seitenenden) und wurde verworfen. Auf Wunsch von Thomas auf 3-3-Regel umgestellt: bei Listen mit mindestens 6 Bullets duerfen Trennungen passieren, aber mindestens 3 Bullets bleiben jeweils zusammen vor und nach dem Umbruch. Bei kuerzeren Listen alles zusammen. Da das stilbasiert nicht abbildbar ist (alle Bullets haben pStyle Compact), neues Post-Processing-Skript build/post-process-docx.py: scannt das fertige DOCX, findet Sequenzen aufeinanderfolgender Bullets mit numPr-Eigenschaft ausserhalb von Tabellen-Zellen, setzt keepNext auf den ersten 2 und den N-3 N-2 Bullets jeder Liste mit n groesser gleich 6 (bei n kleiner 6 alle keepNext). build.ps1 erweitert auf 3 Schritte und ruft das Post-Processing-Skript automatisch nach erfolgreichem DOCX-Build auf, mit Console-Output und Log-Statistiken (Anzahl Listen Bullets keepNext-Markierungen). Sandbox-Verifikation 26 Listen 184 Bullets 93 keepNext, Pattern fuer 11-Bullet-Liste KK......KK.. Auf Thomas System visuell bestaetigt: Listen werden an guten Stellen getrennt, keine ungenutzten Seitenenden, keine einzelnen Bullets allein am Seitenrand. teilgebiete/01-lebenslauf.md um B3- und B3.5-Bloecke ergaenzt sowie Naechste-Schritte-Liste auf B4 C D umstrukturiert. agent-prompt.md Aktueller-Stand-Abschnitt fortgeschrieben mit B3 und B3.5, Hinweis auf 3-stufige DOCX-Pipeline und Edit-Tool-Truncation an build.ps1 ergaenzt. Naechste Session startet mit B4 (Heading-Farben oder Trennlinien analog PDF).
This commit is contained in:
@@ -6,7 +6,7 @@ build-reference-docx.py
|
||||
Baut die templates/reference.docx fuer die Pandoc-DOCX-Pipeline aus der
|
||||
Pandoc-Default-Reference, mit gezielten Anpassungen.
|
||||
|
||||
Iteration B1 + B1.5 + B2 (aktuell):
|
||||
Iteration B1 + B1.5 + B2 + B3 (aktuell):
|
||||
B1 - Theme-Schriften (majorFont und minorFont) beide auf Calibri.
|
||||
B1 - Direkte Schriftnamen-Referenzen in styles.xml auf Calibri
|
||||
(Code-Schriften wie Consolas bleiben).
|
||||
@@ -14,24 +14,20 @@ Iteration B1 + B1.5 + B2 (aktuell):
|
||||
B1.5 - Body-DocDefault 11pt, Heading 1/2/3 auf 15/13/12 pt.
|
||||
B2 - Header (Name links, "Lebenslauf" rechts) ab Seite 2; Seite 1 mit
|
||||
leerem Header (titlePg-Mechanik). Footer (rechts: Seite n / m) auf
|
||||
allen Seiten inkl. Seite 1 (footer-Ref fuer "first" zeigt auf den
|
||||
gleichen Footer wie "default"). Page-Setup explizit: A4, Raender
|
||||
analog PDF (top/bottom 2.2 cm, left/right 2.5 cm). Damit ist der
|
||||
Tab-Stop deterministisch unabhaengig von Word-Locale-Defaults.
|
||||
allen Seiten inkl. Seite 1. Page-Setup explizit: A4, Raender
|
||||
analog PDF (top/bottom 2.2 cm, left/right 2.5 cm).
|
||||
B3 - DocDefault widowControl. Heading 1/2/3 mit keepNext + keepLines.
|
||||
Zusaetzlich 'FirstParagraph' (Pandoc-Stil fuer den ersten Absatz
|
||||
nach einem Heading) — deckt die fett formatierten Kenntnisse-
|
||||
Subsection-Labels ab. Hinweis: Listen-Bullet-Schutz (3-3-Regel)
|
||||
passiert nicht hier, sondern im Post-Processing
|
||||
(build/post-process-docx.py), das auf das fertige DOCX angewendet
|
||||
wird — ein Stil kann keine Per-Bullet-Logik abbilden.
|
||||
|
||||
Geplant in Folge-Iterationen:
|
||||
B3 - Heading-Stile mit "keep with next", Widow/Orphan-Control auf Stilebene
|
||||
B4 - optional Heading-Farben auf DesTEngS-Blau analog PDF
|
||||
|
||||
Vorgehen:
|
||||
1. Pandoc-Default-Reference per `pandoc --print-default-data-file
|
||||
reference.docx` extrahieren.
|
||||
2. Als ZIP entpacken.
|
||||
3. Relevante XML-Dateien anpassen, neue Header/Footer-XMLs anlegen,
|
||||
Beziehungen und ContentTypes ergaenzen, sectPr setzen.
|
||||
4. Als neue ZIP-Datei (templates/reference.docx) speichern.
|
||||
|
||||
Voraussetzungen: nur Python-Stdlib + Pandoc im PATH.
|
||||
C - Foto-Einbindung
|
||||
D - Hyphenation-Feintuning fuer PDF
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -44,15 +40,11 @@ import zipfile
|
||||
from pathlib import Path
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
# --- Pfade -----------------------------------------------------------------
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
BASE_DIR = SCRIPT_DIR.parent
|
||||
TEMPLATES_DIR = BASE_DIR / "templates"
|
||||
OUTPUT_FILE = TEMPLATES_DIR / "reference.docx"
|
||||
|
||||
# --- XML-Namespaces --------------------------------------------------------
|
||||
|
||||
NS = {
|
||||
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
||||
"a": "http://schemas.openxmlformats.org/drawingml/2006/main",
|
||||
@@ -67,8 +59,6 @@ ET.register_namespace("", NS["rel"])
|
||||
W = "{%s}" % NS["w"]
|
||||
A = "{%s}" % NS["a"]
|
||||
|
||||
# --- Konfiguration ---------------------------------------------------------
|
||||
|
||||
CODE_FONTS = {"consolas", "courier", "courier new", "liberation mono",
|
||||
"monaco", "menlo", "fira mono", "fira code"}
|
||||
TARGET_FONT = "Calibri"
|
||||
@@ -80,25 +70,23 @@ SIZE_HEADING3 = 24
|
||||
HEADING_SIZES = {"Heading1": SIZE_HEADING1,
|
||||
"Heading2": SIZE_HEADING2,
|
||||
"Heading3": SIZE_HEADING3}
|
||||
# Compact NICHT mehr in dieser Liste — Listen-Bullet-Schutz uebernimmt das
|
||||
# Post-Processing-Skript pro-Bullet.
|
||||
KEEP_STYLES = ("Heading1", "Heading2", "Heading3", "FirstParagraph")
|
||||
|
||||
# Page-Setup (in DXA, 1cm = 566.929 dxa; 1 inch = 1440 dxa)
|
||||
# A4: 21.0 x 29.7 cm
|
||||
PAGE_W = 11906 # A4 Breite
|
||||
PAGE_H = 16838 # A4 Hoehe
|
||||
MARGIN_TOP = 1247 # 2.2 cm
|
||||
MARGIN_BOT = 1247 # 2.2 cm
|
||||
MARGIN_LEFT = 1417 # 2.5 cm
|
||||
MARGIN_RIGHT = 1417 # 2.5 cm
|
||||
HEADER_POS = 720 # 1.27 cm vom oberen Seitenrand
|
||||
FOOTER_POS = 720 # 1.27 cm vom unteren Seitenrand
|
||||
# Tab-Stop am rechten Textrand: PAGE_W - LEFT - RIGHT = 9072 dxa = 16 cm
|
||||
PAGE_W = 11906
|
||||
PAGE_H = 16838
|
||||
MARGIN_TOP = 1247
|
||||
MARGIN_BOT = 1247
|
||||
MARGIN_LEFT = 1417
|
||||
MARGIN_RIGHT = 1417
|
||||
HEADER_POS = 720
|
||||
FOOTER_POS = 720
|
||||
HEADER_RIGHT_TAB = PAGE_W - MARGIN_LEFT - MARGIN_RIGHT
|
||||
|
||||
HEADER_LEFT = "Dr.-Ing. Thomas Langer"
|
||||
HEADER_RIGHT = "Lebenslauf"
|
||||
|
||||
# --- Hilfsfunktionen -------------------------------------------------------
|
||||
|
||||
def log(msg: str) -> None:
|
||||
print(f"[build-reference-docx] {msg}", flush=True)
|
||||
|
||||
@@ -178,8 +166,6 @@ def replace_direct_fonts_in_styles(styles_xml: Path) -> None:
|
||||
f" gesetzt (Code-Fonts unangetastet: {skipped})")
|
||||
write_xml(tree, styles_xml)
|
||||
|
||||
# --- B1: Tabellen ----------------------------------------------------------
|
||||
|
||||
def set_table_borders_none(styles_xml: Path) -> None:
|
||||
tree = ET.parse(styles_xml)
|
||||
root = tree.getroot()
|
||||
@@ -201,8 +187,6 @@ def set_table_borders_none(styles_xml: Path) -> None:
|
||||
log(" Style 'Table': tblBorders=none auf allen Sides")
|
||||
write_xml(tree, styles_xml)
|
||||
|
||||
# --- B1.5: Schriftgroessen ------------------------------------------------
|
||||
|
||||
def set_default_body_size(styles_xml: Path) -> None:
|
||||
tree = ET.parse(styles_xml)
|
||||
root = tree.getroot()
|
||||
@@ -230,7 +214,35 @@ def set_heading_sizes(styles_xml: Path) -> None:
|
||||
log(f" Stil {sid!r}: Schriftgroesse {target/2} pt")
|
||||
write_xml(tree, styles_xml)
|
||||
|
||||
# --- B2: Header und Footer ------------------------------------------------
|
||||
def set_widow_control_default(styles_xml: Path) -> None:
|
||||
tree = ET.parse(styles_xml)
|
||||
root = tree.getroot()
|
||||
docDefaults = root.find(f"{W}docDefaults") or ET.SubElement(root, f"{W}docDefaults")
|
||||
pPrDefault = docDefaults.find(f"{W}pPrDefault") or ET.SubElement(docDefaults, f"{W}pPrDefault")
|
||||
pPr = pPrDefault.find(f"{W}pPr") or ET.SubElement(pPrDefault, f"{W}pPr")
|
||||
if pPr.find(f"{W}widowControl") is None:
|
||||
ET.SubElement(pPr, f"{W}widowControl")
|
||||
log(" pPrDefault: widowControl aktiviert")
|
||||
write_xml(tree, styles_xml)
|
||||
|
||||
def set_keep_next_styles(styles_xml: Path) -> None:
|
||||
tree = ET.parse(styles_xml)
|
||||
root = tree.getroot()
|
||||
seen = set()
|
||||
for style in root.findall(f"{W}style"):
|
||||
sid = style.get(f"{W}styleId")
|
||||
if sid not in KEEP_STYLES:
|
||||
continue
|
||||
pPr = style.find(f"{W}pPr") or ET.SubElement(style, f"{W}pPr")
|
||||
for tag in (f"{W}keepNext", f"{W}keepLines"):
|
||||
if pPr.find(tag) is None:
|
||||
ET.SubElement(pPr, tag)
|
||||
log(f" Stil {sid!r}: keepNext + keepLines")
|
||||
seen.add(sid)
|
||||
missing = set(KEEP_STYLES) - seen
|
||||
if missing:
|
||||
log(f" Hinweis: Stil(e) {sorted(missing)!r} nicht gefunden, uebersprungen")
|
||||
write_xml(tree, styles_xml)
|
||||
|
||||
def header_default_xml() -> bytes:
|
||||
return (
|
||||
@@ -305,9 +317,6 @@ def update_sectpr_with_headers(document_xml: Path,
|
||||
header_default_rid: str,
|
||||
header_first_rid: str,
|
||||
footer_default_rid: str) -> None:
|
||||
"""Ersetzt sectPr durch Page-Setup + Header/Footer-Refs + titlePg.
|
||||
Footer-Ref wird zweimal eingebaut (default und first), beide auf
|
||||
den gleichen Footer — dann hat Seite 1 trotz titlePg den Footer."""
|
||||
text = document_xml.read_text(encoding="utf-8")
|
||||
new_sectpr = (
|
||||
f'<w:sectPr>'
|
||||
@@ -359,8 +368,6 @@ def add_header_footer(unpacked: Path) -> None:
|
||||
|
||||
update_sectpr_with_headers(doc_xml, rid_h_def, rid_h_first, rid_f_def)
|
||||
|
||||
# --- Hauptablauf -----------------------------------------------------------
|
||||
|
||||
def main() -> int:
|
||||
log(f"Ziel: {OUTPUT_FILE}")
|
||||
TEMPLATES_DIR.mkdir(parents=True, exist_ok=True)
|
||||
@@ -387,6 +394,10 @@ def main() -> int:
|
||||
set_default_body_size(styles_xml)
|
||||
log("Anpassung: Heading-Schriftgroessen 15/13/12 pt")
|
||||
set_heading_sizes(styles_xml)
|
||||
log("Anpassung: Widow/Orphan-Control im DocDefault (B3)")
|
||||
set_widow_control_default(styles_xml)
|
||||
log("Anpassung: keepNext + keepLines auf Heading 1/2/3 + FirstParagraph (B3)")
|
||||
set_keep_next_styles(styles_xml)
|
||||
log("Anpassung: Header und Footer einbauen (B2)")
|
||||
add_header_footer(unpacked)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user