From 3c8eda6fd9ff0dff654a2866fdf24c5c9cee1336 Mon Sep 17 00:00:00 2001 From: Brenno de Winter Date: Mon, 15 Jun 2026 23:57:49 +0200 Subject: [PATCH] Add markdown syntax validation and fix Linux dual-screen presenter teardown. Markdown mode now validates deck structure before apply, highlights issues by line, and allows proceeding after a warning. Dual-screen exit closes the audience window once and avoids Linux embedder crashes from duplicate teardown. Co-authored-by: Cursor --- README.md | 2 +- docs/ARCHITECTURE.md | 9 +- docs/FILE_FORMAT.md | 55 ++ docs/USER_GUIDE.md | 64 ++ lib/l10n/app_localizations.dart | 11 + lib/models/markdown_validation.dart | 36 + lib/services/markdown_validator.dart | 704 ++++++++++++++++++ lib/widgets/editors/markdown_deck_editor.dart | 490 ++++++++++++ lib/widgets/panels/editor_panel.dart | 126 +--- lib/widgets/presentation/audience_window.dart | 11 - .../presentation/fullscreen_presenter.dart | 62 +- test/fullscreen_presenter_test.dart | 17 + test/markdown_validator_test.dart | 224 ++++++ .../linux/multi_window_manager.cc | 7 +- 14 files changed, 1661 insertions(+), 157 deletions(-) create mode 100644 lib/models/markdown_validation.dart create mode 100644 lib/services/markdown_validator.dart create mode 100644 lib/widgets/editors/markdown_deck_editor.dart create mode 100644 test/markdown_validator_test.dart diff --git a/README.md b/README.md index 8a7f49c..5a1b115 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Built with Flutter for macOS, Windows, and Linux. - **Annotation layer** — draw on slides while presenting (pen, highlighter, eraser, laser pointer). Kept as a separate layer that never touches the Marp Markdown, mirrored live to the beamer, and saved in a `.ink.json` sidecar. - **Media handling** — drag-and-drop images, an image carousel picker, captions, and descriptions stored as sidecar metadata. The library can filter images without tags and clean up md5-identical duplicates (merging their tags/captions and repointing every deck — open or on disk — to the kept file). - **Import / export** — round-trips Marp Markdown, imports existing slides, and exports to PDF, PPTX (with speaker notes), and a self-contained offline HTML deck (code highlighting, math, charts, and mermaid diagrams render in the browser). Decks are saved as a self-contained package with copied assets. -- **Productivity** — find & replace, slide finder, undo/redo, skip-slide state, multi-select with bulk copy-to-another-deck / delete / skip, and tabbed multi-deck editing. Paste a spreadsheet selection (or CSV / a markdown table) into a table cell to fill the whole grid. `Ctrl/Cmd+O` opens, `Ctrl/Cmd+S` saves. +- **Productivity** — find & replace, slide finder, undo/redo, skip-slide state, multi-select with bulk copy-to-another-deck / delete / skip, and tabbed multi-deck editing. Paste a spreadsheet selection (or CSV / a markdown table) into a table cell to fill the whole grid. **Markdown mode** edits the whole deck as raw Marp text, with a structural syntax check (line highlights, optional **Apply anyway**) before switching back. `Ctrl/Cmd+O` opens, `Ctrl/Cmd+S` saves. - **Accessibility** — WCAG 2.1-oriented: interface text scaling up to 200%, keyboard-operable panel divider and dialogs, screen-reader labels for slides and charts (charts read out their data), and slide-change announcements while presenting. - **Crash recovery** — automatic snapshots so work survives an unexpected exit. - **Theming** — customizable deck style profiles (deck and source-code colours via presets or custom hex, fonts, logo, footer) and app appearance (including a dark interface), a bundled Marp CSS theme (`assets/themes/ocideck.css`), and a bundled EB Garamond font (no network fetch). diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index bc156e7..a24f0a5 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -15,7 +15,8 @@ are stored on disk, see [`FILE_FORMAT.md`](FILE_FORMAT.md). ``` lib/ models/ # Deck, Slide, Settings/ThemeProfile, Chart, Annotation - services/ # markdown, file, export, classification_policy, image, caption, + services/ # markdown, markdown_validator, file, export, classification_policy, + # image, caption, # description, image_dedup (md5 duplicates), # image_reference (.md rewrites), recovery, rasterizer, # marp_html, annotation_codec, rehearsal_controller @@ -48,6 +49,12 @@ lib/ by their `_class` and parsed separately (their fenced block would otherwise confuse the generic line parser). +`MarkdownValidator` (`lib/services/markdown_validator.dart`) performs a +structural pre-flight before applying raw markdown in the editor: it reports line- +anchored errors/warnings for the same shapes the parser expects (front matter, +slide separators, `_class`, fences, OciDeck HTML fragments, chart JSON, etc.). +See `docs/FILE_FORMAT.md` §10 and `docs/USER_GUIDE.md` (Markdown mode). + This service is heavily covered by the round-trip tests — treat it as the source-of-truth for the file format and keep `FILE_FORMAT.md` in sync. diff --git a/docs/FILE_FORMAT.md b/docs/FILE_FORMAT.md index 826200a..1913b30 100644 --- a/docs/FILE_FORMAT.md +++ b/docs/FILE_FORMAT.md @@ -497,3 +497,58 @@ genegeerd, op presenter-notities na): - **Voorwaartse migratie:** ontbrekende front-matter-velden en stijlprofiel-velden vallen terug op standaardwaarden, en het ontbreken van het `no-footer`-token betekent (voor oudere bestanden) "footer zichtbaar". + +--- + +## 10. Markdown-modus en syntaxcontrole + +In de editor schakelt het code-icoon in de werkbalk naar **Markdown-modus**: de +hele presentatie wordt als één Marp-markdownbestand getoond (dezelfde structuur +als op schijf). **Toepassen** parsed de tekst terug naar de getype slides; +**Annuleren** keert terug zonder wijzigingen door te voeren. + +### Wanneer controleren? + +- **Controleren** — op elk moment tijdens het bewerken; resultaten in een + samenvattingsbalk, met uitklapbare lijst. Regelnummers links worden rood + (fout) of geel (waarschuwing) gemarkeerd; klik op een melding om naar die regel + te springen. +- **Toepassen** — voert altijd eerst de controle uit. Bij bevindingen verschijnt + een dialoog met **Terug naar editor**, **Annuleren** of **Toch toepassen**. + +De controle is **structureel**: hij volgt dezelfde regels als `MarkdownService` +(front matter, `\n---\n` als scheiding, `_class`-commentaar, fenced blocks en de +HTML-fragmenten die OciDeck zelf genereert). Geldige Marp-syntax die OciDeck +niet modelleert wordt niet gerapporteerd. + +### Uitgevoerde controles + +| Onderdeel | Ernst | Controle | +| --- | --- | --- | +| **Document** | waarschuwing | Presentatie is leeg. | +| **Document** | fout | Geen slide-inhoud na front matter. | +| **Document** | fout | `parseDeck` faalt volledig (`null`). | +| **Front matter** | fout | Openings-`---` zonder afsluitende `---`-regel. | +| **Front matter** | waarschuwing | Regel zonder `sleutel: waarde`-vorm. | +| **Front matter** | fout | Onbekende `tlp:`-waarde. | +| **Commentaar** | fout | `` op dezelfde regel. | +| **Commentaar** | waarschuwing | Commentaar zonder `_class:`, `_style:`, `ocideck_…`, `skip`, `tlp:` of `advance:`. | +| **Codeblokken** | fout | Oneven aantal ` ``` `-regels (niet afgesloten). | +| **`_class`** | fout | Malformed ``. | +| **`_class`** | waarschuwing | Onbekend token in `_class` (bekend: `title`, `section`, `two-bullets`, `split`, `quote`, `video`, `table`, `code`, `chart`, `logo-safe`, `no-logo`, `no-footer`). | +| **Slide-metadata** | fout | Onbekende ``, niet-numerieke ``, of ongeldige `` (`bullets`, `numbered`, `checklist`). | +| **Twee kolommen** | fout | Ongeldige base64/JSON in `ocideck_two_bullets_*`-commentaren. | +| **Afbeeldingen** | fout | `![…](…` zonder sluitende `)`. | +| **Video/audio** | fout | Onvolledige `