Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
e246ffc
perf: debounce preview re-render while typing
Sep 24, 2026
0f62548
fix(perf): debounce live-preview render to stop sluggish typing (#4)
lukisch Sep 26, 2026
b26390d
chore(release): bump version to 1.0.3, harmonize metadata, fix CI Pil…
Sep 26, 2026
2ce9c34
fix: window/EXE-Icon zeigte altes Design nach Store-Update 1.0.3 (#5)
lukisch Sep 26, 2026
15565d4
chore: version badges to 1.0.4, fix stale legacy icon_*.png mirror (#6)
lukisch Sep 26, 2026
42f5249
fix: .md-Dateisymbol (Platte) + Store-Dateityp-Zuordnung, Version 1.0…
lukisch Sep 27, 2026
b9e45a2
docs(store): record submission 1152921505701985229 (v1.0.5.0 in certi…
Sep 27, 2026
b37068b
Save existing Markdown documents atomically
Sep 30, 2026
7460b46
fix: render raw HTML banners above following text
Sep 30, 2026
f32d8b5
test: isolate standalone smoke from user settings
Sep 30, 2026
e15b45f
fix: preserve settings when persistence fails
Sep 30, 2026
7bbf950
fix: export sessions atomically
Sep 30, 2026
2152b75
fix: preserve automatic export copies on name collisions
Sep 30, 2026
b772c1e
fix: preserve previous PDF on export failure
Sep 30, 2026
da2bb8c
fix: tolerate malformed optional session settings
Sep 30, 2026
818c16f
fix: reject malformed UTF-8 before replacing active document
Sep 30, 2026
e86bf82
fix: start current source instead of obsolete release executable
Sep 30, 2026
2c104ff
fix: protect active Markdown original during PDF export (#8)
lukisch Oct 1, 2026
0e69eb3
ci: verify Flutter and cover source smoke runtime inputs (#9)
lukisch Oct 1, 2026
f4092f3
Merge current main with preview flush and companion version
Oct 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/workflows/source-platform-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,27 @@ on:
push:
paths:
- 'main.py'
- 'translator.py'
- 'requirements.txt'
- 'pyproject.toml'
- 'locales/**'
- 'assets/**'
- '*.ico'
- '*.png'
- 'tests/source_platform_smoke.py'
- '.github/workflows/source-platform-smoke.yml'
pull_request:
paths:
- 'main.py'
- 'translator.py'
- 'requirements.txt'
- 'pyproject.toml'
- 'locales/**'
- 'assets/**'
- '*.ico'
- '*.png'
- 'tests/source_platform_smoke.py'
- '.github/workflows/source-platform-smoke.yml'
workflow_dispatch:

permissions:
Expand Down
32 changes: 31 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt pytest ruff
pip install -r requirements.txt pytest ruff Pillow

- name: Run ruff check
run: |
Expand All @@ -70,3 +70,33 @@ jobs:
PYTHONIOENCODING: utf-8
run: |
python main.py --self-test

flutter:
name: Flutter analyze and test
runs-on: ubuntu-latest
timeout-minutes: 20
defaults:
run:
working-directory: flutter_port
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Flutter
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
with:
channel: stable
flutter-version: '3.47.5'
cache: true

- name: Show SDK versions
run: flutter --version

- name: Resolve locked dependencies
run: flutter pub get --enforce-lockfile

- name: Analyze Flutter source
run: flutter analyze --no-pub

- name: Run Flutter tests
run: flutter test --no-pub
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ DECISIONS.md
TODO.md
DONE.md

# ---- Interne Abnahme-/Reviewberichte (lokale Pfade, Hostnamen, Reviewernamen) ----
_codex/

# ---- Developer-Backups (PWA-/Companion-Templates) ----
web_companion/_pwa_tpl_*/

Expand All @@ -144,3 +147,6 @@ _archive/
# PyInstaller-Ausgabe im Store-Paket (114 MB Qt-/Python-Laufzeit, wird gebaut, nicht versioniert)
store_package/*/_internal/
store_package/*/*.exe

# MSIX-Staging von _STORE/msstore_build_msix.ps1
_WARTUNG/
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,42 @@ Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.1.0/).

## [Unreleased]

### Behoben / Fixed
- Der PDF-Export lehnt das aktive Markdown-Original und dessen Pfad- oder
Datei-Aliase als Ziel ab. Eine erneute Prüfung vor der Veröffentlichung
schützt auch während des Druckens neu entstandene Verknüpfungen. Bei einem
Wechsel der aktiven Datei bleiben beide Originalpfade geschützt.
- PDF export rejects the original Markdown document and its aliases as a
destination, checking again before publication. Confirmed replacement of
an ordinary PDF remains supported.
- Bestehende Markdown-Dokumente werden über `QSaveFile` atomar gespeichert.
Teil-Schreibfehler und fehlgeschlagene Ersetzungen erhalten das bisherige
Dokument und den ungespeicherten Editorzustand. UTF-8 und die bisherigen
plattformspezifischen Zeilenumbrüche bleiben erhalten.
- Existing Markdown documents now save atomically; write or replacement failures
preserve the previous file and keep editor changes marked as unsaved.

## [1.0.5] - 2026-09-27

### Behoben
- `.md`-Dateien zeigten im Explorer und auf dem Desktop eine braune Platte mit kleinem Logo statt des App-Symbols (T-20260927-699609650). Ursache (gemessen): Das Dateityp-Symbol ist `CleanMarkdown.exe,0`, also das in die EXE eingebackene Icon. Die ausgelieferte 1.0.3-EXE trug noch das vor PR #5 fehlerhafte Plattendesign (Abweichung 0,35 zur Store-Kachel). Die 1.0.4-Korrektur lag nur im Quellbaum und wurde nie ausgeliefert; 1.0.5 ersetzt sie.
- Das Store-Paket registrierte trotz `file_types` in `store_package.json` keinen `.md`-Handler: Der gemeinsame MSIX-Builder erzeugte sein Manifest selbst und ließ die Dateityp-Zuordnung weg. Er übernimmt sie jetzt (mit `uap:Logo`) und baut `resources.pri`.
- Neue `Square44x44Logo.targetsize-{16…256}`-Varianten inklusive `altform-unplated`/`altform-lightunplated` (erzeugt mit `scripts/gen_targetsize_icons.py` aus der Store-Kachel). Ohne sie zeichnet Windows Dateityp- und Taskleistensymbole skaliert auf eine Platte.
- Das Icon-Gate prüft jetzt auch das gebaute MSIX (`--package`): Manifest-Version, Dateityp-Zuordnung, `resources.pri`, alle targetsize/unplated-Varianten (jede real ausgelieferte Größe, nicht nur eine Mindestliste) und das Icon jeder EXE im Paket.
- Der MSIX-Build übernimmt jetzt den vollständigen onedir-Laufzeitordner (Python-/Qt-Laufzeit) statt nur der EXE-Datei — ein vorheriger Build hätte nach Installation nicht gestartet.
- Neues `uninstall_local.ps1`: entfernt kontrolliert eine ältere lokale Installation (z. B. aus einer manuellen Vorabversion), die sonst dauerhaft die `.md`-Dateizuordnung der Store-Version überdecken würde. Läuft nur nach Bestätigung und mit vorherigem Registry-Backup.

## [1.0.4] - 2026-09-26

### Behoben
- Fenster-Icon (Titelleiste, EXE-Ressource) zeigte nach dem 1.0.3-Store-Update noch ein altes, anderes Design, während Taskleisten-/Kachel-Icon bereits korrekt war (T-20260926-864299616). Ursache: Die Store-Kachel (`store_assets/Square*.png`) wurde neu gebrandet, das Desktop-`.ico` (`assets/cleanmarkdown.ico` + Duplikate) sowie die Master-/Fallback-PNGs (`icon.png`, `DesktopIcon.png`, `assets/icon.png`, `assets/favicon.png`, `assets/favicon.ico`) wurden dabei nicht mitgezogen. Alle aus derselben Quelle wie die Store-Kachel neu erzeugt.
- Neuer Regressionstest `test_window_icon_matches_store_tile_branding` prüft künftig jedes Desktop-Icon (alle eingebetteten Größen) und jede Master-/Fallback-PNG gegen die Store-Kachel.

## [1.0.3] - 2026-09-26

### Behoben
- Live-Vorschau beim Tippen debounced (`fix(perf): debounce live-preview render to stop sluggish typing`, #4) — verzögertes Rendern statt Rendern pro Tastenanschlag, dadurch flüssigeres Tippen auch in großen Dokumenten.

### Hinzugefügt / Verbessert (2026-09-18 — Web Companion & PWA Release)

- **Web Companion & PWA Plattform-Transfer (P2):**
Expand Down
Binary file modified CleanMarkdown.ico
Binary file not shown.
Binary file modified DesktopIcon.ico
Binary file not shown.
Binary file modified DesktopIcon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions EXPORTFORMAT.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Status:

```json
{
"appVersion": "0.3.1",
"appVersion": "1.0.5",
"settings": {
"language": "de",
"theme": "paper",
Expand Down Expand Up @@ -113,7 +113,7 @@ cleanmarkdown-bundle-v1.zip
"session": "cleanmarkdown-session-v1.json",
"assetsRoot": "assets/",
"createdAt": "2026-05-28T16:10:00",
"appVersion": "0.3.1"
"appVersion": "1.0.5"
}
```

Expand Down
8 changes: 4 additions & 4 deletions PORTIERUNGSPLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ die Zielsystem-Architektur und den Austauschvertrag für **CleanMarkdown**.

| Plattform | Technologie | Priorität | Status | Kanonischer Pfad / Artefakt |
|---|---|---|---|---|
| **Windows Desktop** | Python 3.12, PySide6 (Qt6) | P0 (Kanonisch) | Aktiv (v1.0.2) | `main.py`, `build_exe.bat` |
| **Windows Desktop** | Python 3.12, PySide6 (Qt6) | P0 (Kanonisch) | Aktiv (v1.0.5) | `main.py`, `build_exe.bat` |
| **Windows Store (MSIX)** | Desktop-Bridge, AppxManifest, WACK | P0 (Release-Ready) | Bereit | `store_package/CleanMarkdown/`, `scripts/store_assets.py` |
| **Mobile Companion (Android/iOS)** | Flutter 3.x, Dart | P1 (Vollständig) | Getestet (37/37) | `flutter_port/` |
| **Web Companion & PWA** | Statisches HTML5 / WebAssembly | P2 (Vollständig) | Bereit (v1.0.2) | `web_companion/` |
| **Web Companion & PWA** | Statisches HTML5 / WebAssembly | P2 (Vollständig) | Bereit (v1.0.5) | `web_companion/` |
| **macOS & Linux Desktop** | PySide6 Source-Execution | P3 (Wartung) | Kompatibel | Source-Start via Python |

---
Expand Down Expand Up @@ -40,7 +40,7 @@ die Zielsystem-Architektur und den Austauschvertrag für **CleanMarkdown**.
- **Framework:** PySide6 (Qt for Python).
- **Philosophie:** Sofort einsatzbereit, reine Einzelfenster-Bedienung ohne überflüssige Menühierarchien.
- **Datenhaltung:** Einstellungen ausschließlich lokal in `%APPDATA%\CleanMarkdown\settings.json`.
- **Packaging:** PyInstaller Einzelfile (`CleanMarkdown-1.0.2-win64.exe`) und MSIX-Package für den Microsoft Store.
- **Packaging:** PyInstaller Einzelfile (`CleanMarkdown-1.0.5-win64.exe`) und MSIX-Package für den Microsoft Store.

### 2.2 Mobile-Linie (`flutter_port/`)
- **Framework:** Flutter (Android & iOS).
Expand Down Expand Up @@ -97,7 +97,7 @@ vollständig offline über JSON-Dateien nach der Spezifikation `cleanmarkdown-se
- **Package-ID / Identity Name:** `Geiger.CleanMarkdown`
- **Publisher:** `CN=52596601-BAB4-4F3F-B182-E8F3F273B202`
- **Publisher Display:** `Geiger`
- **Version:** `1.0.2.0`
- **Version:** `1.0.5.0`
- **Restricted Capabilities:** `runFullTrust`
- **File Type Associations:** `.md`, `.markdown`, `.mdown`, `.mkd`

Expand Down
39 changes: 36 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
[![Platform: Windows | macOS | Linux](https://img.shields.io/badge/Platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey.svg)](https://github.com/doc-bricks/CleanMarkdown)
[![Zero-Egress](https://img.shields.io/badge/Privacy-100%25%20Offline%20%7C%20Zero--Egress-success.svg)](SECURITY.md)
[![Security: Local-First](https://img.shields.io/badge/Security-Local--First%20%7C%20Non--Elevation-blueviolet.svg)](SECURITY.md)
[![Tests: 145 passed](https://img.shields.io/badge/Tests-145%20passed-brightgreen.svg)](tests)
[![Version: 1.0.2](https://img.shields.io/badge/Version-1.0.2-teal.svg)](CHANGELOG.md)
[![Tests: 227 passed](https://img.shields.io/badge/Tests-227%20passed-brightgreen.svg)](tests)
[![Version: 1.0.5](https://img.shields.io/badge/Version-1.0.5-teal.svg)](CHANGELOG.md)
[![LLM-Ready: llms.txt](https://img.shields.io/badge/LLM--Ready-llms.txt-orange.svg)](llms.txt)

> [!NOTE]
Expand Down Expand Up @@ -43,6 +43,7 @@
## Features

- **Dual-Tab Workspace**: Instant switching between rendered `Reading` view and raw `Editor` with optional scroll synchronization.
- **Safe UTF-8 Opening**: Files with invalid UTF-8 are rejected before replacing the active document, preserving unsaved edits and original bytes. Convert other encodings to UTF-8 before opening.
- **Raw Markdown Editor**: Direct Markdown editing with convenient helper buttons for headings, tables, links, images, and task lists without WYSIWYG complexity.
- **Clear Formatting**: Strip Markdown syntax from selected text with a single click to start clean.
- **Interactive Image Inspection**: High-resolution `ImagePreviewDialog` with Zoom (+/- / Fit / 1:1), Clipboard Copying, and image metadata.
Expand Down Expand Up @@ -186,6 +187,35 @@ Or start directly on Windows:
start.bat
```

The Windows starter runs the current source checkout, using `.venv` when present
and otherwise Python on `PATH`. It forwards arguments (for example,
`start.bat --self-test`) and does not select older release executables.

### Local install vs. Store install — don't run both

`install_local.ps1` registers CleanMarkdown as a local `.md` handler (its own
`CleanMarkdown.mdfile` ProgID, `%LOCALAPPDATA%\Programs\CleanMarkdown`, a
Start Menu shortcut). Installing CleanMarkdown from the Microsoft Store on
top of that **does not replace the local file association** — what matters
is whichever ProgID is currently chosen in `UserChoice`, regardless of which
copy was updated most recently. Leaving both installed causes `.md` files to
keep showing the old local EXE's icon even after the Store package has been
updated.

**Recommendation:** use only one install method at a time, in this order:

1. Install/update the Store version first — its manifest **must** already
declare a `.md` file-type association; `uninstall_local.ps1` checks this
and aborts otherwise (e.g. for 1.0.3, which had none).
2. Preview: `.\uninstall_local.ps1 -WhatIf` (no changes).
3. Backed-up removal: `.\uninstall_local.ps1` (asks for confirmation before
changing anything, backs up the affected registry keys via `reg export`,
then removes only what `install_local.ps1` itself created — it **only
removes the old association, it does not set a new one**).
4. Windows Settings → Apps → Default apps → ".md" → set CleanMarkdown
(Store) as the default manually.
5. Verify the result (the `.md` icon in Explorer/Desktop).

---

## Usage & Keyboard Shortcuts
Expand Down Expand Up @@ -246,6 +276,9 @@ CleanMarkdown is part of the [`doc-bricks`](https://github.com/doc-bricks) docum

## Development & Test Suite

The [CI contract](docs/CI-CONTRACT.md) lists the desktop, web-contract,
Flutter and source-smoke checks, their commands and acceptance limits.

```powershell
python -m pip install -r requirements.txt pytest ruff
python -m py_compile main.py translator.py
Expand All @@ -254,7 +287,7 @@ python -m pytest -q
python main.py --self-test
```

The test suite validates rendering accuracy, figure link preservation, math processing, session serialization, settings persistence, headless print isolation, asset parity, and automated metadata contract synchronization (135 passed tests).
The test suite validates rendering accuracy, figure link preservation, math processing, session serialization, settings persistence, atomic document saving, headless print isolation, asset parity, and automated metadata contract synchronization (227 passed tests).

For the mobile line in `flutter_port/`, verified scope includes local `.md`/`.markdown` file opening, live rendering, raw editing, and local storage flows.

Expand Down
38 changes: 35 additions & 3 deletions README_DE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ Deutsch · **[English](README.md)**
[![Plattform: Windows | macOS | Linux](https://img.shields.io/badge/Plattform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey.svg)](https://github.com/doc-bricks/CleanMarkdown)
[![Zero-Egress](https://img.shields.io/badge/Datenschutz-100%25%20Offline%20%7C%20Zero--Egress-success.svg)](SECURITY.md)
[![Sicherheit: Local-First](https://img.shields.io/badge/Sicherheit-Local--First%20%7C%20Non--Elevation-blueviolet.svg)](SECURITY.md)
[![Tests: 145 passed](https://img.shields.io/badge/Tests-145%20passed-brightgreen.svg)](tests)
[![Version: 1.0.2](https://img.shields.io/badge/Version-1.0.2-teal.svg)](CHANGELOG.md)
[![Tests: 227 passed](https://img.shields.io/badge/Tests-227%20passed-brightgreen.svg)](tests)
[![Version: 1.0.5](https://img.shields.io/badge/Version-1.0.5-teal.svg)](CHANGELOG.md)
[![LLM-Ready: llms.txt](https://img.shields.io/badge/LLM--Ready-llms.txt-orange.svg)](llms.txt)

> [!NOTE]
Expand Down Expand Up @@ -43,6 +43,7 @@ Deutsch · **[English](README.md)**
## Funktionen

- **Zwei-Tab-Arbeitsbereich**: Nahtloser Wechsel zwischen gerenderter `Lesen`-Ansicht und `Editor` mit optionaler Scroll-Synchronisierung.
- **Sicheres UTF-8-Öffnen**: Dateien mit ungültigem UTF-8 werden vor dem Austausch des aktiven Dokuments abgelehnt. Ungespeicherte Änderungen und ursprüngliche Bytes bleiben erhalten. Andere Kodierungen vor dem Öffnen nach UTF-8 konvertieren.
- **Reiner Markdown-Editor**: Direkte Bearbeitung von Markdown mit praktischen Hilfsbuttons für Überschriften, Tabellen, Links, Bilder und Aufgabenlisten ohne WYSIWYG-Komplexität.
- **Formatierung entfernen**: Markdown-Syntax markierter Textpassagen mit einem Klick auflösen und frisch beginnen.
- **Interaktive Bild-Inspektion**: Hochauflösender `ImagePreviewDialog` mit Zoom (+/- / Einpassen / 1:1), Zwischenablage-Kopieren und Bildmetadaten.
Expand Down Expand Up @@ -186,6 +187,37 @@ Oder direkt unter Windows starten:
start.bat
```

Der Windows-Starter führt die aktuelle Arbeitskopie aus. Er nutzt eine vorhandene
`.venv`, andernfalls Python aus `PATH`. Argumente werden weitergereicht
(zum Beispiel `start.bat --self-test`); ältere Release-EXEs werden nicht ausgewählt.

### Lokale Installation vs. Store-Installation — nicht parallel betreiben

`install_local.ps1` registriert CleanMarkdown lokal als `.md`-Handler (eigene
ProgID `CleanMarkdown.mdfile`, `%LOCALAPPDATA%\Programs\CleanMarkdown`,
Startmenü-Verknüpfung). Wird CleanMarkdown zusätzlich aus dem Microsoft Store
installiert, **ersetzt das Store-Paket die lokale Dateizuordnung nicht
automatisch** — entscheidend ist die aktuell in `UserChoice` gewählte
Zuordnung, unabhängig davon, welche Version zuletzt aktualisiert wurde. Beide
parallel installiert zu lassen führt dazu, dass `.md`-Dateien weiterhin das
Icon der alten lokalen EXE zeigen, selbst nachdem das Store-Paket
aktualisiert wurde.

**Empfehlung:** nur eine der beiden Installationsarten verwenden, in dieser
Reihenfolge:

1. Passende Store-Version installieren/aktualisieren — **muss** im Manifest
bereits eine `.md`-Dateityp-Zuordnung deklarieren; `uninstall_local.ps1`
prüft das und bricht sonst ab (z. B. bei 1.0.3, die keine hatte).
2. Vorschau: `.\uninstall_local.ps1 -WhatIf` (keine Änderung).
3. Gesicherter Rückbau: `.\uninstall_local.ps1` (fragt vor jeder Änderung
nach, sichert die betroffenen Registry-Zweige per `reg export` und
entfernt anschließend nur das, was `install_local.ps1` selbst angelegt
hat — er **entfernt nur die alte Zuordnung, er setzt keine neue**).
4. Windows-Einstellungen → Apps → Standard-Apps → „.md" → CleanMarkdown
(Store) manuell als Standard wählen.
5. Ergebnis prüfen (`.md`-Icon im Explorer/Desktop).

---

## Verwendung & Tastenkombinationen
Expand Down Expand Up @@ -254,7 +286,7 @@ python -m pytest -q
python main.py --self-test
```

Die Testsuite validiert Rendering-Präzision, Erhaltung von Figure-Links, Mathe-Verarbeitung, Sitzungsserialisierung, Einstellungs-Persistenz, isolierten Headless-Druck, Asset-Parität sowie automatisierte Metadaten-Vertragssynchronisation (135 bestandene Tests).
Die Testsuite validiert Rendering-Präzision, Erhaltung von Figure-Links, Mathe-Verarbeitung, Sitzungsserialisierung, Einstellungs-Persistenz, atomare Dokumentenspeicherung, isolierten Headless-Druck, Asset-Parität sowie automatisierte Metadaten-Vertragssynchronisation (227 bestandene Tests).

Für den mobilen Zweig in `flutter_port/` umfasst der geprüfte Umfang das Öffnen lokaler `.md`/`.markdown`-Dateien, Live-Rendering, Raw-Editing und lokale Speicher-Abläufe.

Expand Down
Loading
Loading