-- 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{}}{}} -- 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