Compare commits

..
12 changed files with 248 additions and 17 deletions

View file

@ -29,6 +29,11 @@ bilder_04/ Quelle: Diagramme + erzeuge_*.py-
web_04/ Quelle: site.css, site.js, icons.svg, web_04/ Quelle: site.css, site.js, icons.svg,
plotly.min.js, katex/ - die statischen plotly.min.js, katex/ - die statischen
Bestandteile der Website Bestandteile der Website
pandoc/, pandoc-defaults-basis.yaml, pandoc-defaults-buch.yaml PDF-Konfiguration
(pandoc/emoji_fallback.lua schaltet Zeichen,
die Times New Roman fehlt, auf Symbola um -
siehe PROGRESS.md, "Sonderzeichen in der
PDF-Fassung")
Operations_Research_mit_Python_Version_04.md generiert: Gesamtdokument Operations_Research_mit_Python_Version_04.md generiert: Gesamtdokument
Operations_Research_mit_Python_Version_04.pdf generiert: PDF (xelatex) Operations_Research_mit_Python_Version_04.pdf generiert: PDF (xelatex)
OR_HTML_04/ generiert: Mehrseiten-Website OR_HTML_04/ generiert: Mehrseiten-Website

View file

@ -1588,7 +1588,7 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
<p><strong>🎯 Merksatz</strong> Die eine Aussage, die vom Abschnitt hängen bleiben soll.</p> <p><strong>🎯 Merksatz</strong> Die eine Aussage, die vom Abschnitt hängen bleiben soll.</p>
</blockquote> </blockquote>
<blockquote> <blockquote>
<p><strong>📝 Übungsaufgaben</strong> Am Kapitelende, gestaffelt nach Schwierigkeit: ⭐ Verständnis (im Kopf oder in zwei Sätzen) · ⭐⭐ Handrechnung oder kleine Modelländerung · ⭐⭐⭐ Eigenständige Programmieraufgabe. <strong>Alle Lösungen</strong> stehen in <strong><code>90_Anhang_Loesungen.md</code></strong>.</p> <p><strong>📝 Übungsaufgaben</strong> Am Kapitelende, gestaffelt nach Schwierigkeit: ⭐ Verständnis (im Kopf oder in zwei Sätzen) · ⭐⭐ Handrechnung oder kleine Modelländerung · ⭐⭐⭐ Eigenständige Programmieraufgabe. <strong>Alle Lösungen</strong> stehen in <a href="#anhang-loesungen">Anhang A</a>.</p>
</blockquote> </blockquote>
<blockquote> <blockquote>
<p><strong>✅ Selbsttest</strong> Fünf Fragen mit Kurzantworten zur schnellen Selbstkontrolle.</p> <p><strong>✅ Selbsttest</strong> Fünf Fragen mit Kurzantworten zur schnellen Selbstkontrolle.</p>
@ -2078,8 +2078,6 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
<p>Zweitens: <strong>Lassen Sie jedes Programm laufen und verändern Sie danach eine Zahl.</strong> Was passiert mit dem Vertretungsplan, wenn eine Lehrkraft ausfällt? Was mit dem Portfolio, wenn die Obergrenze von 20 % auf 10 % sinkt? Diese Experimente kosten Sekunden und bauen genau die Intuition auf, die man später beim Modellieren braucht.</p> <p>Zweitens: <strong>Lassen Sie jedes Programm laufen und verändern Sie danach eine Zahl.</strong> Was passiert mit dem Vertretungsplan, wenn eine Lehrkraft ausfällt? Was mit dem Portfolio, wenn die Obergrenze von 20 % auf 10 % sinkt? Diese Experimente kosten Sekunden und bauen genau die Intuition auf, die man später beim Modellieren braucht.</p>
<p>Und drittens: <strong>Nehmen Sie die Übungen ernst.</strong> Sie sind nicht Beiwerk, sondern der Ort, an dem aus Kenntnis Können wird.</p> <p>Und drittens: <strong>Nehmen Sie die Übungen ernst.</strong> Sie sind nicht Beiwerk, sondern der Ort, an dem aus Kenntnis Können wird.</p>
<hr /> <hr />
<p><em>Weiter mit:</em> <strong><code>01_Notation_und_Abkuerzungen.md</code></strong> — oder direkt zu <strong><a href="#kap-einfuehrung">Kapitel 1</a></strong>, wenn Sie die Notation lieber nachschlagen, sobald sie auftaucht.</p>
<hr />
<h1 id="notation-und-abkürzungen">Notation und Abkürzungen</h1> <h1 id="notation-und-abkürzungen">Notation und Abkürzungen</h1>
<p>Dieses Kapitel ist zum Nachschlagen gedacht, nicht zum Durchlesen. Schlagen Sie hier nach, sobald Ihnen ein Symbol oder ein Kürzel begegnet, das Sie nicht sicher zuordnen können.</p> <p>Dieses Kapitel ist zum Nachschlagen gedacht, nicht zum Durchlesen. Schlagen Sie hier nach, sobald Ihnen ein Symbol oder ein Kürzel begegnet, das Sie nicht sicher zuordnen können.</p>
<hr /> <hr />

View file

@ -337,7 +337,7 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
<p><strong>🎯 Merksatz</strong> Die eine Aussage, die vom Abschnitt hängen bleiben soll.</p> <p><strong>🎯 Merksatz</strong> Die eine Aussage, die vom Abschnitt hängen bleiben soll.</p>
</blockquote> </blockquote>
<blockquote> <blockquote>
<p><strong>📝 Übungsaufgaben</strong> Am Kapitelende, gestaffelt nach Schwierigkeit: ⭐ Verständnis (im Kopf oder in zwei Sätzen) · ⭐⭐ Handrechnung oder kleine Modelländerung · ⭐⭐⭐ Eigenständige Programmieraufgabe. <strong>Alle Lösungen</strong> stehen in <a href="anhang-loesungen.html"><code>90_Anhang_Loesungen.md</code></a>.</p> <p><strong>📝 Übungsaufgaben</strong> Am Kapitelende, gestaffelt nach Schwierigkeit: ⭐ Verständnis (im Kopf oder in zwei Sätzen) · ⭐⭐ Handrechnung oder kleine Modelländerung · ⭐⭐⭐ Eigenständige Programmieraufgabe. <strong>Alle Lösungen</strong> stehen in <a href="anhang-loesungen.html#anhang-loesungen">Anhang A</a>.</p>
</blockquote> </blockquote>
<blockquote> <blockquote>
<p><strong>✅ Selbsttest</strong> Fünf Fragen mit Kurzantworten zur schnellen Selbstkontrolle.</p> <p><strong>✅ Selbsttest</strong> Fünf Fragen mit Kurzantworten zur schnellen Selbstkontrolle.</p>
@ -826,8 +826,6 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
<p>Die wirksamste Art, mit diesem Buch zu arbeiten, ist unbequem: <strong>Lesen Sie die Problemstellung, schließen Sie das Buch und versuchen Sie, das Modell selbst aufzuschreiben</strong> — Variablen, Zielfunktion, Nebenbedingungen. Vergleichen Sie erst dann. Die Abweichungen zwischen Ihrem Entwurf und dem Text sind genau die Stellen, an denen Sie etwas lernen. Wer stattdessen mitliest und nickt, hat am Ende des Kapitels das angenehme Gefühl, es verstanden zu haben — und steht beim eigenen Problem vor einem leeren Blatt.</p> <p>Die wirksamste Art, mit diesem Buch zu arbeiten, ist unbequem: <strong>Lesen Sie die Problemstellung, schließen Sie das Buch und versuchen Sie, das Modell selbst aufzuschreiben</strong> — Variablen, Zielfunktion, Nebenbedingungen. Vergleichen Sie erst dann. Die Abweichungen zwischen Ihrem Entwurf und dem Text sind genau die Stellen, an denen Sie etwas lernen. Wer stattdessen mitliest und nickt, hat am Ende des Kapitels das angenehme Gefühl, es verstanden zu haben — und steht beim eigenen Problem vor einem leeren Blatt.</p>
<p>Zweitens: <strong>Lassen Sie jedes Programm laufen und verändern Sie danach eine Zahl.</strong> Was passiert mit dem Vertretungsplan, wenn eine Lehrkraft ausfällt? Was mit dem Portfolio, wenn die Obergrenze von 20 % auf 10 % sinkt? Diese Experimente kosten Sekunden und bauen genau die Intuition auf, die man später beim Modellieren braucht.</p> <p>Zweitens: <strong>Lassen Sie jedes Programm laufen und verändern Sie danach eine Zahl.</strong> Was passiert mit dem Vertretungsplan, wenn eine Lehrkraft ausfällt? Was mit dem Portfolio, wenn die Obergrenze von 20 % auf 10 % sinkt? Diese Experimente kosten Sekunden und bauen genau die Intuition auf, die man später beim Modellieren braucht.</p>
<p>Und drittens: <strong>Nehmen Sie die Übungen ernst.</strong> Sie sind nicht Beiwerk, sondern der Ort, an dem aus Kenntnis Können wird.</p> <p>Und drittens: <strong>Nehmen Sie die Übungen ernst.</strong> Sie sind nicht Beiwerk, sondern der Ort, an dem aus Kenntnis Können wird.</p>
<hr />
<p><em>Weiter mit:</em> <a href="notation.html"><code>01_Notation_und_Abkuerzungen.md</code></a> — oder direkt zu <a href="einfuehrung.html">[Kapitel 1](einfuehrung.html#kap-einfuehrung)</a>, wenn Sie die Notation lieber nachschlagen, sobald sie auftaucht.</p>
</article> </article>

View file

@ -260,7 +260,7 @@ Jedes Kapitel folgt derselben Struktur. Wenn Sie wissen, wie die Bausteine funkt
> **🎯 Merksatz** Die eine Aussage, die vom Abschnitt hängen bleiben soll. > **🎯 Merksatz** Die eine Aussage, die vom Abschnitt hängen bleiben soll.
> **📝 Übungsaufgaben** Am Kapitelende, gestaffelt nach Schwierigkeit: ⭐ Verständnis (im Kopf oder in zwei Sätzen) · ⭐⭐ Handrechnung oder kleine Modelländerung · ⭐⭐⭐ Eigenständige Programmieraufgabe. **Alle Lösungen** stehen in **`90_Anhang_Loesungen.md`**. > **📝 Übungsaufgaben** Am Kapitelende, gestaffelt nach Schwierigkeit: ⭐ Verständnis (im Kopf oder in zwei Sätzen) · ⭐⭐ Handrechnung oder kleine Modelländerung · ⭐⭐⭐ Eigenständige Programmieraufgabe. **Alle Lösungen** stehen in [Anhang A](#anhang-loesungen).
> **✅ Selbsttest** Fünf Fragen mit Kurzantworten zur schnellen Selbstkontrolle. > **✅ Selbsttest** Fünf Fragen mit Kurzantworten zur schnellen Selbstkontrolle.
@ -469,10 +469,6 @@ Zweitens: **Lassen Sie jedes Programm laufen und verändern Sie danach eine Zahl
Und drittens: **Nehmen Sie die Übungen ernst.** Sie sind nicht Beiwerk, sondern der Ort, an dem aus Kenntnis Können wird. Und drittens: **Nehmen Sie die Übungen ernst.** Sie sind nicht Beiwerk, sondern der Ort, an dem aus Kenntnis Können wird.
---
*Weiter mit:* **`01_Notation_und_Abkuerzungen.md`** — oder direkt zu **[Kapitel 1](#kap-einfuehrung)**, wenn Sie die Notation lieber nachschlagen, sobald sie auftaucht.
--- ---

View file

@ -318,7 +318,7 @@ können Sie gezielt springen.
> ⭐ Verständnis (im Kopf oder in zwei Sätzen) · > ⭐ Verständnis (im Kopf oder in zwei Sätzen) ·
> ⭐⭐ Handrechnung oder kleine Modelländerung · > ⭐⭐ Handrechnung oder kleine Modelländerung ·
> ⭐⭐⭐ Eigenständige Programmieraufgabe. > ⭐⭐⭐ Eigenständige Programmieraufgabe.
> **Alle Lösungen** stehen in [`90_Anhang_Loesungen.md`](90_Anhang_Loesungen.md). > **Alle Lösungen** stehen in {ref:anhang:loesungen}.
> **✅ Selbsttest** > **✅ Selbsttest**
> Fünf Fragen mit Kurzantworten zur schnellen Selbstkontrolle. > Fünf Fragen mit Kurzantworten zur schnellen Selbstkontrolle.
@ -644,6 +644,4 @@ dem aus Kenntnis Können wird.
--- ---
*Weiter mit:* [`01_Notation_und_Abkuerzungen.md`](01_Notation_und_Abkuerzungen.md) — *Weiter mit:* [dem Verzeichnis Notation und Abkürzungen](01_Notation_und_Abkuerzungen.md) — oder direkt zu [{ref:kap:einfuehrung}](10_Einfuehrung_OR.md), wenn Sie die Notation lieber nachschlagen, sobald sie auftaucht.
oder direkt zu [{ref:kap:einfuehrung}](10_Einfuehrung_OR.md), wenn Sie die Notation
lieber nachschlagen, sobald sie auftaucht.

View file

@ -395,6 +395,19 @@ def pruefe_dateien() -> list[str]:
f"folgt aber '{soll}' - die Lesekette ueberspringt eine Datei.") f"folgt aber '{soll}' - die Lesekette ueberspringt eine Datei.")
fehlend.append(name) fehlend.append(name)
# Die Navigationszeile muss in EINER Zeile bleiben: weiter_re und
# entferne_navigation() lesen nur bis zum Zeilenende. Ein umgebrochener
# Verweis bleibt sonst als Absatz in PDF und Website stehen - so geschah
# es im Vorwort (drei Zeilen, die Zeile leckte ins gedruckte Buch).
for name in DATEIEN:
with open(os.path.join(HIER, name), encoding="utf-8") as f:
for nr, zeile in enumerate(f, 1):
if zeile.startswith("*Weiter mit:") and \
not re.search(r"\]\(\S+?\.md\)", zeile):
print(f"FEHLER: {name}:{nr} - '*Weiter mit:' ist umgebrochen; "
f"das Linkziel (.md) muss in derselben Zeile stehen.")
fehlend.append(name)
# Marken fuer interaktive Figuren: Zeigt eine ins Leere, verschwindet sie # Marken fuer interaktive Figuren: Zeigt eine ins Leere, verschwindet sie
# auf der Website stillschweigend - im PDF steht dann ein Verweis auf eine # auf der Website stillschweigend - im PDF steht dann ein Verweis auf eine
# Figur, die es nicht gibt. # Figur, die es nicht gibt.
@ -548,8 +561,15 @@ def entferne_navigation(text: str) -> str:
""" """
Entfernt die 'Weiter mit:'-Navigationszeilen am Dateiende - im Entfernt die 'Weiter mit:'-Navigationszeilen am Dateiende - im
Gesamtdokument sind sie ueberfluessig und die Links zeigen ins Leere. Gesamtdokument sind sie ueberfluessig und die Links zeigen ins Leere.
Ein umgebrochener Navigationsabsatz (Fortsetzungszeilen bis zur naechsten
Leerzeile) wird mitgenommen. Ohne diese Toleranz blieb eine dreizeilige
"Weiter mit"-Zeile im PDF stehen und renderte auf der Website den
geschachtelten {ref:}-Link als Rohtext - passiert im Vorwort.
""" """
text = re.sub(r"\n---\n+\*(Weiter mit|Zurueck zum|Zurück zum)[^\n]*\n*$", "\n", text) text = re.sub(
r"\n---\n+\*(Weiter mit|Zurueck zum|Zurück zum)[^\n]*"
r"(?:\n(?!\n)[^\n]*)*\n*$", "\n", text)
return text.rstrip() + "\n" return text.rstrip() + "\n"
@ -1194,6 +1214,21 @@ def baue_pdf() -> None:
print(f"PDF wurde nicht erzeugt - LaTeX-Protokoll in " print(f"PDF wurde nicht erzeugt - LaTeX-Protokoll in "
f"{BUILD_BASISNAME}.log pruefen.") f"{BUILD_BASISNAME}.log pruefen.")
# Bewachung des Sonderzeichen-Fallbacks: xelatex verschweigt fehlende
# Glyphen im Druckbild (nur "Missing character" im Protokoll). Der Filter
# pandoc/emoji_fallback.lua deckt die bekannten Zeichen ab; taucht hier
# eine Zahl auf, kennt Times New Roman ein Zeichen, das der Filter noch
# nicht umschaltet - Zeichenliste im Filter ergaenzen.
protokoll = os.path.join(BASIS, BUILD_BASISNAME + ".log")
if os.path.exists(protokoll):
with open(protokoll, encoding="utf-8", errors="replace") as datei:
fehlend = sum(1 for zeile in datei if "Missing character" in zeile)
if fehlend:
print(f" WARNUNG: {fehlend} fehlende Zeichen im LaTeX-Protokoll "
f"(pandoc/emoji_fallback.lua erweitern)")
else:
print(" Kein fehlendes Zeichen - Font-Fallback deckt alles ab.")
for endung in (".tex", ".aux", ".log", ".out", ".toc", ".idx", ".ind", ".ilg"): for endung in (".tex", ".aux", ".log", ".out", ".toc", ".idx", ".ind", ".ilg"):
pfad = os.path.join(BASIS, BUILD_BASISNAME + endung) pfad = os.path.join(BASIS, BUILD_BASISNAME + endung)
if os.path.exists(pfad) and endung != ".log": if os.path.exists(pfad) and endung != ".log":

View file

@ -2592,6 +2592,69 @@ eine **doppelte Nummer** — „Abbildung 21: Abb. 7.2: …". Die erste vergibt
`nummeriere_marken()`. Das betrifft alle 48 Abbildungen und besteht seit Langem; behoben wäre `nummeriere_marken()`. Das betrifft alle 48 Abbildungen und besteht seit Langem; behoben wäre
es dadurch, dass die LaTeX-Nummerierung der Gleitumgebung unterdrückt wird. es dadurch, dass die LaTeX-Nummerierung der Gleitumgebung unterdrückt wird.
### Sonderzeichen in der PDF-Fassung — ein stiller Font-Fehler behoben ✅
In der gesamten PDF-Fassung fehlten alle Zeichen, die Times New Roman nicht mitbringt: die
Lernelemente-Symbole (⭐ ✏ ❓ 🎯 🚀 …), aber auch die Sub-/Superskripte (₀ ₁ ₂ ₜ ₙ ⁶ ᵀ) und die
langen Pfeile (⟹ ⟶ ⟵ ⇒). Das alte LaTeX-Protokoll enthielt **rund 2 070**
`Missing character`-Meldungen; die Zeichen fielen stillschweigend aus dem Druckbild.
Zwei Ursachen, beide lange unentdeckt, weil die Website die Zeichen korrekt zeigt
(der Browser weicht selbst auf eine Emoji-Schrift aus):
* xelatex hat keine automatische Font-Fallback-Kette — fehlt einem Zeichen der Glyph, wird
es weggelassen, ohne dass der Bau fehlschlägt.
* Die pandoc-Variable `emoji-font: "Noto Color Emoji"` wertet der LaTeX-Writer
(pandoc 3.1.3) **nicht aus** — sie hat seit ihrer Einführung still nichts getan.
**Die Lösung ist zweistufig**, weil die Zeichen auf zwei Wegen in den PDF gelangen:
1. **`pandoc/emoji_fallback.lua`** (neu) — ein pandoc-Filter, der die betreffenden Zeichen
im Fließtext in `{\texorpdfstring{\symfont{…}}{…}}` einschüttet. `\symfont` ist
**Symbola** — die einzige Schrift auf dem Bausystem, die das komplette Set abdeckt
(Noto Color Emoji funktioniert unter XeTeX nicht: die Zeichen landen im `nullfont`);
monochrom, für den Drucksatz ohnehin passend. Der `\texorpdfstring`-Antil hält die
PDF-Lesezeichen ruhig und erhalten. Variationsselektoren (U+FE0F) werden entfernt.
Zwei pandoc-3.1.3-Eigenheiten unterwegs gefunden: Filterhandler funktionieren **nur als
globale Funktionen** — ein vom Filter zurückgegebenes Table wird stillschweigend
ignoriert; und der Einschub muss `RawInline` sein, als `Str` würde pandoc die
Backslashes escapen.
2. **`ucharclasses`** in `pandoc/header-includes.tex` — für den **Diagrammtext**: Das Paket
`svg` exportiert die SVG-Texte (x₁, σᵀ, ∈ in Achsen- und Knotenbeschriftungen) als
LaTeX-Text, dorthin reicht der AST-Filter nicht. Die Zurück-Umschaltung ist bewusst
`\fontfamily{\familydefault}\selectfont` statt `\normalfont``\normalfont` würde den
Fettdruck hinter dem Stern einer Aufgabentitel-Zeile zerstören (gemessen mit
pdfminer: „Titel“ bleibt Bold).
Die tote `emoji-font`-Variable ist aus `pandoc-defaults-basis.yaml` entfernt (mit
Begründung), und `baue_pdf()` zählt die `Missing character`-Meldungen im Protokoll:
Der neue Lauf meldet **null fehlende Zeichen**; taucht die Warnung wieder auf, kennt Times
New Roman ein Zeichen, das der Filter noch nicht umschaltet. Symbola ist damit eingebettet,
der Buchumfang bleibt bei 792 Seiten; alle HTML-Seiten sind byteidentisch geblieben.
### „Weiter mit“ im Vorwort — ein Umbau, der die Navigationszeile ins Buch leckte ✅
Eine Überarbeitung des Vorworts (Zeilenumbrüche, Verweise) machte die „Weiter mit“-Zeile
dreizeilig. `entferne_navigation()` liest nur bis zum Zeilenende — die Zeile blieb stehen:
Im PDF stand sie als Absatz mit Dateinamen, auf der Vorwortseite zusätzlich mit dem
Rohlink `[Kapitel 1](einfuehrung.html#kap-einfuehrung)`. Ursache der Rohform: Im
Mehraseiten-Bau löst sich `{ref:}` zu einem **kompletten Markdown-Link** auf; steht es
innerhalb eines weiteren Links, rendert die Schachtelung als Rohtext. Im Gesamtdokument
funktioniert dieselbe Konstruktion scheinbar — dort täuscht sie.
Behoben und bewacht:
* Die Navigationszeile ist wieder einzeilig; die Linktexte nennen kein Dateinamen mehr
(„Anhang A“ über `{ref:anhang:loesungen}`, das Notationsverzeichnis über einen
sprechenden Text — es hat als Rahmenkapitel kein `{#kap:}`-Label).
* **Konvention dazu:** `{ref:}` gehört nie in einen Markdown-Link hinein — im Fließtext
als Text, in „Weiter mit“-Zeilen nur, weil diese entfernt werden.
* `entferne_navigation()` nimmt Fortsetzungszeilen bis zur nächsten Leerzeile mit;
`--check` bricht ab, wenn ein `*Weiter mit:` das Linkziel (.md) nicht in derselben
Zeile trägt.
Gegenprobe: PDF ohne „Weiter mit“-Absatz, Vorwortseite ohne Rohtext, 792 Seiten,
kein fehlendes Zeichen im LaTeX-Protokoll.
--- ---
## 8. Commit-Historie des V04-Strangs ## 8. Commit-Historie des V04-Strangs

View file

@ -39,6 +39,15 @@ metadata:
include-in-header: include-in-header:
- pandoc/header-includes.tex - pandoc/header-includes.tex
# Sonderzeichen, die Times New Roman fehlen (Emoji, Lernelemente-Symbole,
# Sub-/Superskripte, lange Pfeile), auf \symfont (= Symbola, definiert in
# pandoc/header-includes.tex) umschalten. Ohne diesen Filter liess xelatex
# alle betreffenden Zeichen in der PDF-Fassung stillschweigend weg —
# die Website zeigte sie, das PDF nicht. Nur für den PDF-Bau; der HTML-Bau
# benutzt diese Defaults nicht.
filters:
- pandoc/emoji_fallback.lua
# -------------------------------- # --------------------------------
# Fonts & Layout Variables # Fonts & Layout Variables
# -------------------------------- # --------------------------------
@ -48,7 +57,9 @@ variables:
monofont: "DejaVu Sans Mono" monofont: "DejaVu Sans Mono"
# sansfont: "DejaVu Sans" # sansfont: "DejaVu Sans"
sansfont: "Arial" # Sans-Serif sansfont: "Arial" # Sans-Serif
emoji-font: "Noto Color Emoji" # "emoji-font" hier bewusst NICHT gesetzt: Die Variable wertet der
# LaTeX-Writer (pandoc 3.1.3) nicht aus, sie hat jahrelang still nichts
# getan. Die Emoji-Abdeckung läuft über pandoc/emoji_fallback.lua.
mathfont: "STIX Two Math" mathfont: "STIX Two Math"
monofontoptions: "Scale=MatchLowercase" monofontoptions: "Scale=MatchLowercase"
papersize: a4 papersize: a4

91
pandoc/emoji_fallback.lua Normal file
View file

@ -0,0 +1,91 @@
-- emoji_fallback.lua
-- Pandoc-Filter für den PDF-Bau (nur `-t latex`, nur PDF, nicht für die Website).
--
-- Problem: Der Haupttext steht in Times New Roman — diese Schrift kennt weder
-- Emoji noch die Darstellungssymbole der Lernelemente (⭐ ✏ ❓ 🧠 …) und auch
-- keine hoch-/tiefgestellten Ziffern. XeLaTeX besitzt keine automatische
-- Font-Fallback-Kette: Fehlt einem Zeichen der Glyph, wird es stillschweigend
-- weggelassen ("Missing character" nur im Protokoll). Die pandoc-Variable
-- "emoji-font" wird vom LaTeX-Writer (pandoc 3.1.3) nicht ausgewertet — die
-- Zeichen fehlten daher in der gesamten PDF-Fassung, während die Website sie
-- über den Browser-Fontstack korrekt zeigte.
--
-- Lösung: Dieser Filter wickelt alle betreffenden Zeichen in
-- {\texorpdfstring{\symfont{<Zeichen>}}{<Zeichen>}}
-- ein. \symfont ist in pandoc/header-includes.tex auf Symbola gesetzt — die
-- einzige auf dem Bausystem vorhandene Schrift, die das komplette Set abdeckt
-- (Noto Color Emoji funktioniert unter XeTeX nicht, die Zeichen landen im
-- nullfont). Symbola ist monochrom — für den Drucksatz ohnehin passend.
--
-- Der \texorpdfstring-Anteil hält hyperref ruhig: In PDF-Lesezeichen und im
-- Inhaltsverzeichnis steht das schlichte Zeichen statt des Fontwechsels.
--
-- Codeblöcke werden nicht angetastet (Code/CodeBlock sind eigene
-- AST-Elemente): Der Mono-Font DejaVu Sans Mono deckt die dort vorkommenden
-- Symbole (✓ ✗ ★, Sub-/Superskripte) selbst ab.
local function braucht_symfont(cp)
return (cp >= 0x1F000 and cp <= 0x1FAFF) -- Emoji-Blöcke (🎯 📌 🚀 …)
or (cp >= 0x2600 and cp <= 0x27BF) -- Misc Symbols + Dingbats (★ ⚠ ✅ ✏ ✓ ✗ ❌ ❓)
or (cp >= 0x2B00 and cp <= 0x2BFF) -- Misc Symbols and Arrows (⭐)
or (cp >= 0x27F5 and cp <= 0x27FF) -- Supplemental Arrows-A (⟵ ⟶ ⟹)
or (cp >= 0x2070 and cp <= 0x209F) -- hoch-/tiefgestellte Ziffern (⁶ ₀ ₁ ₂ ₜ ₙ)
or cp == 0x21D2 -- ⇒
or cp == 0x1D40 -- ᵀ (Modifier Letter Capital T)
end
local function ersetze(text)
local teile = {}
local normal = {}
local symbole = nil -- Puffer für aufeinanderfolgende Fallback-Zeichen
local function flush_normal()
if #normal > 0 then
teile[#teile + 1] = pandoc.Str(table.concat(normal))
normal = {}
end
end
local function flush_symbole()
if symbole and #symbole > 0 then
local zeichen = table.concat(symbole)
teile[#teile + 1] = pandoc.RawInline("latex",
"{\\texorpdfstring{\\symfont{" .. zeichen .. "}}{"
.. zeichen .. "}}")
symbole = nil
end
end
for _, cp in utf8.codes(text) do
if cp == 0xFE0F then
-- Variationsselektor (Emoji- vs. Textdarstellung): für das PDF ohne
-- Bedeutung, Symbola enthält keinen sichtbaren Glyphen — weglassen.
elseif braucht_symfont(cp) then
flush_normal()
symbole = symbole or {}
symbole[#symbole + 1] = utf8.char(cp)
else
flush_symbole()
normal[#normal + 1] = utf8.char(cp)
end
end
flush_normal()
flush_symbole()
return teile
end
-- pandoc 3.1.3 ruft Filterhandler ausschließlich als globale Funktionen auf;
-- ein zurückgegebenes Handler-Table würde stillschweigend ignoriert.
function Str(el)
-- Schneller Ausstieg: nur anfassen, wenn überhaupt Multibyte drin ist.
if not el.text:find("[\194-\244]") then
return nil
end
local ok, teile = pcall(ersetze, el.text)
if not ok then
-- Kaputtes UTF-8 o. ä.: Element unverändert durchreichen.
return nil
end
return teile
end

View file

@ -2,5 +2,41 @@
\setmonofont{DejaVu Sans Mono}[ \setmonofont{DejaVu Sans Mono}[
Scale=MatchLowercase Scale=MatchLowercase
] ]
% --- Symbol-/Emoji-Fallback ------------------------------------------------
% Times New Roman (Haupttext) kennt weder Emoji noch die Symbole der
% Lernelemente und keine hoch-/tiefgestellten Ziffern. XeLaTeX hat keine
% automatische Fallback-Kette — fehlende Zeichen fielen stillschweigend weg.
% Der Filter pandoc/emoji_fallback.lua schaltet die betreffenden Zeichen
% deshalb auf \symfont um. Symbola ist die einzige Schrift auf dem
% Bausystem, die das komplette Set abdeckt; Noto Color Emoji funktioniert
% unter XeTeX nicht (die Zeichen landen im nullfont). Monochrom — für den
% Drucksatz ohnehin passend.
\newfontfamily\symfont{Symbola}
% --- Automatische Umschaltung für den Diagrammtext --------------------------
% Die SVG-Diagramme werden vom Paket "svg" mit Inkscape nach LaTeX
% exportiert; deren Texte (Achsenbeschriftungen, Knotenlabels wie x₁, σᵀ)
% setzt LaTeX selbst — da erreicht der pandoc-Filter nicht mehr hin. Für
% diese Ebene übernimmt ucharclasses die Umschaltung auf \symfont je
% Unicode-Block. Die Zurück-Umschaltung ist bewusst
% \fontfamily{\familydefault}\selectfont und NICHT \normalfont:
% \normalfont würde auch Fettdruck und Kursiv zurücksetzen — "Aufgabe ⭐ —
% Titel" wäre nach dem Stern nur noch mager. Im Fließtext schaltet der
% pandoc-Filter bereits in geschlossenen Gruppen um; ucharclasses greift
% dort nur innerhalb dieser Gruppen und bleibt unsichtbar.
\usepackage[quiet]{ucharclasses}
\setTransitionsFor{SuperscriptsAndSubscripts}{\symfont}{\fontfamily{\familydefault}\selectfont}
\setTransitionsFor{PhoneticExtensions}{\symfont}{\fontfamily{\familydefault}\selectfont}
\setTransitionsFor{MathematicalOperators}{\symfont}{\fontfamily{\familydefault}\selectfont}
\setTransitionsFor{Arrows}{\symfont}{\fontfamily{\familydefault}\selectfont}
\setTransitionsFor{SupplementalArrowsA}{\symfont}{\fontfamily{\familydefault}\selectfont}
\setTransitionsFor{Dingbats}{\symfont}{\fontfamily{\familydefault}\selectfont}
\setTransitionsFor{MiscellaneousSymbols}{\symfont}{\fontfamily{\familydefault}\selectfont}
\setTransitionsFor{MiscellaneousSymbolsAndArrows}{\symfont}{\fontfamily{\familydefault}\selectfont}
\setTransitionsFor{MiscellaneousSymbolsAndPictographs}{\symfont}{\fontfamily{\familydefault}\selectfont}
\setTransitionsFor{Emoticons}{\symfont}{\fontfamily{\familydefault}\selectfont}
\setTransitionsFor{TransportAndMapSymbols}{\symfont}{\fontfamily{\familydefault}\selectfont}
\setTransitionsFor{SupplementalSymbolsAndPictographs}{\symfont}{\fontfamily{\familydefault}\selectfont}
\usepackage{microtype} \usepackage{microtype}
\usepackage{pifont} \usepackage{pifont}