diff --git a/BEDIENUNGSANLEITUNG.md b/BEDIENUNGSANLEITUNG.md index 173f5b5..e4d4d90 100644 --- a/BEDIENUNGSANLEITUNG.md +++ b/BEDIENUNGSANLEITUNG.md @@ -510,7 +510,7 @@ python3 epub2md_merge.py --help | `--boxes callout/quote/html/plain` | Darstellung von Infokästen | | `--styles semantic/html` | Farben, Schriften, Größen, Ausrichtung und Sprache als HTML übernehmen (`html`) | | `--page-markers none/visible/comment` | Seitenzahlen der Druckausgabe als `[S. 123]` oder `` | -| `--no-css-emphasis` | Hervorhebungen nur aus HTML-Tags übernehmen, nicht aus dem Stylesheet des Buches | +| `--no-css-emphasis` | Hervorhebungen nur aus HTML-Tags übernehmen, nicht aus dem Stylesheet des Buches (farbige Markierungen `` bleiben, sie gehören zu `--styles`) | | `--math auto/tex/mathml/image` | Formeldarstellung | | `--footnotes end-of-chapter/end-of-book/inline/keep-links` | Fußnoten-Platzierung | | `--format gfm/commonmark` | Markdown-Variante; `commonmark` für sehr strikte Programme | diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b451cb..48f5bc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,17 @@ Alle nennenswerten Änderungen an epub2md. Format nach [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), Versionsnummern nach [Semantic Versioning](https://semver.org/lang/de/). +## [Unveröffentlicht] + +### Geändert + +- Seitenmarken (`--page-markers`) aus einem Kastentitel stehen jetzt vor dem Kasten statt im fetten Titel, + wie bei Überschriften. + +### Dokumentation + +- `--no-css-emphasis` lässt ``-Markierungen bestehen; diese steuert `--styles`. + ## [0.2.0] – 2026-10-06 Schwerpunkt: Typografie und Gestaltung des Buches im Markdown abbilden. @@ -49,5 +60,6 @@ Erste Fassung. - Alle Befunde der QA-Prüfungen (R1–R7, QA2-01 bis QA2-19) behoben oder abgemildert. - README und Bedienungsanleitung. +[Unveröffentlicht]: https://kitux.de/forgejo/dschlueter/epub2md/compare/v0.2.0...main [0.2.0]: https://kitux.de/forgejo/dschlueter/epub2md/compare/v0.1.0...v0.2.0 [0.1.0]: https://kitux.de/forgejo/dschlueter/epub2md/src/tag/v0.1.0 diff --git a/README.md b/README.md index c8d420e..af4040b 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ python3 epub2md.py buch.epub output/buch --force --report berichte/buch.json | `--boxes {callout,quote,html,plain}` | `callout` | Infokästen (Tipp, Hinweis, Warnung, Exkurs, Merke …): `callout` = `> [!TIP]` mit fettem Titel (GitHub-Alerts, Obsidian-Callouts; anderswo ein Zitatblock), `quote` = Zitatblock mit fettem Titel, `html` = `
`, `plain` = normaler Text wie bisher | | `--styles {semantic,html}` | `semantic` | `semantic`: nur bedeutungstragende Gestaltung (Hintergrundmarkierung → ``). `html`: zusätzlich Farbe, Hintergrund, Schriftgröße, Schriftart, Kapitälchen, Ausrichtung als ``/`
` und fremdsprachige Passagen als ``, jeweils nur, wo sie vom normalen Text des Buches abweichen. Obsidian, VS Code und Pandoc (HTML/PDF/EPUB) zeigen das an, GitHub nicht | | `--page-markers {none,visible,comment}` | `none` | Seitenzahlen der Druckausgabe an der Stelle des Seitenwechsels: `visible` = `\[S. 123\]` im Text (zum Zitieren), `comment` = `` (unsichtbar, aber durchsuchbar), `none` = weglassen | -| `--css-emphasis` / `--no-css-emphasis` | an | Fett, kursiv, unterstrichen, durchgestrichen, hoch-/tiefgestellt auch übernehmen, wenn das Buch sie nur per CSS-Klasse setzt (z. B. `span.italic`). Einzelwörter in Monospace-Schrift werden zu Inline-Code; per CSS ausgeblendete Elemente (`display:none`) entfallen. Statistik im Bericht unter `css` | +| `--css-emphasis` / `--no-css-emphasis` | an | Fett, kursiv, unterstrichen, durchgestrichen, hoch-/tiefgestellt auch übernehmen, wenn das Buch sie nur per CSS-Klasse setzt (z. B. `span.italic`). Einzelwörter in Monospace-Schrift werden zu Inline-Code; per CSS ausgeblendete Elemente (`display:none`) entfallen. Statistik im Bericht unter `css`. Hintergrundmarkierungen (``) und Stile steuert unabhängig davon `--styles` | | `--keep-invisible-chars` | aus | Nullbreiten-Zeichen und weiche Trennstriche im Fließtext behalten. Standard: entfernen, weil sie Suche und RAG stören (Anzahl im Bericht: `text_cleanup`). Code bleibt immer unverändert | | `--keep-html` | aus | Unbekannte/nicht sicher konvertierbare Elemente als bereinigtes HTML erhalten (sonst: Text übernommen + Eintrag in `diagnostics/unsupported-elements.md`) | | `--strict` | aus | Abbruch bei kritischen Fehlern (fehlende/unlesbare Spine-Dokumente, unsichere ZIP-Pfade, ungültige Spine-Verweise) | diff --git a/epub2md/html_converter.py b/epub2md/html_converter.py index fb8f6ff..5ce4bb9 100644 --- a/epub2md/html_converter.py +++ b/epub2md/html_converter.py @@ -303,6 +303,7 @@ class Renderer: self.css = stylesheet self.scene_breaks = 0 self.page_markers = 0 + self.marker_sink: list[str] | None = None # collects page markers instead of emitting them inline self.poems = 0 self.boxes = 0 self.in_box = False @@ -417,7 +418,11 @@ class Renderer: return "" self.page_markers += 1 page = html.escape(page, quote=False).replace("--", "") - return f"" if self.opt.page_markers == "comment" else f"\\[S. {md_escape(page)}\\]" + marker = f"" if self.opt.page_markers == "comment" else f"\\[S. {md_escape(page)}\\]" + if self.marker_sink is not None: + self.marker_sink.append(marker) + return "" + return marker def anchors_of(self, el: Any, subtree: bool = False) -> str: nodes = iter_elements(el) if subtree else [el] @@ -622,13 +627,18 @@ class Renderer: break title_el = self._box_title(members) title = "" + markers: list[str] = [] # page breaks in the title go before the box, like for headings if title_el is not None: pieces: list[Piece] = [("t", self._text(title_el.text))] if title_el.text else [] - for child in title_el: - if is_element(child) and not self._title_symbol(child): - pieces.extend(self.inline(child)) - if child.tail: - pieces.append(("t", self._text(child.tail))) + self.marker_sink = markers + try: + for child in title_el: + if is_element(child) and not self._title_symbol(child): + pieces.extend(self.inline(child)) + if child.tail: + pieces.append(("t", self._text(child.tail))) + finally: + self.marker_sink = None title = join_inline(pieces, hard_break=" ").strip() kind = kind or _box_type(norm_ws(text_content(title_el))) saved = self.in_box @@ -653,7 +663,9 @@ class Renderer: if title and norm_ws(re.sub(r"[*_\\:]", "", title)).lower() in TYPE_WORDS: title = "" # 'Tipp' as title of a TIP box adds nothing self.boxes += 1 - out = [anchor] if anchor else [] + out = ["".join(markers)] if markers else [] + if anchor: + out.append(anchor) head = [f"**{title}**"] if title else [] if self.opt.boxes == "html": out.append(f'
\n\n' + "\n\n".join(head + blocks) + "\n\n
") diff --git a/tests/test_styles.py b/tests/test_styles.py index cc253d8..f3d3884 100644 --- a/tests/test_styles.py +++ b/tests/test_styles.py @@ -201,3 +201,11 @@ def test_hidden_span_gets_no_field_separator_and_class_type_wins(convert): text = convert(Book(docs=[Doc("c.xhtml", body)], media={"s.css": css})).chapter("001") assert "unterstrichen." in text and "VERSTECKT" not in text assert "> [!NOTE]\n> **Wichtige Regel**" in text # class 'hinweis' beats the word in the title + + +def test_page_marker_in_box_title_goes_before_the_box(convert): + body = ('

K

') + text = convert(Book(docs=[Doc("c.xhtml", body)]), "--page-markers", "visible").chapter("001") + assert "\\[S. 62\\]\n\n> [!NOTE]\n> **Wozu Deklarationen?**" in text + assert "> Weil es \\[S. 63\\]hilft." in text # markers in the box body stay in place