md2star 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- md2star-2.0.0/.gitignore +140 -0
- md2star-2.0.0/CHANGELOG.md +338 -0
- md2star-2.0.0/CONTRIBUTING.md +148 -0
- md2star-2.0.0/EXAMPLES.md +150 -0
- md2star-2.0.0/LANDSCAPE.md +168 -0
- md2star-2.0.0/LICENSE +30 -0
- md2star-2.0.0/LISEZMOI.md +430 -0
- md2star-2.0.0/Makefile +86 -0
- md2star-2.0.0/PKG-INFO +475 -0
- md2star-2.0.0/README.md +438 -0
- md2star-2.0.0/ROADMAP.md +113 -0
- md2star-2.0.0/SECURITY.md +94 -0
- md2star-2.0.0/assets/README.md +45 -0
- md2star-2.0.0/assets/docx/basic.md +4 -0
- md2star-2.0.0/assets/docx/math.md +12 -0
- md2star-2.0.0/assets/docx/with_author.md +2 -0
- md2star-2.0.0/assets/docx/with_bib.md +2 -0
- md2star-2.0.0/assets/docx/with_lang.md +3 -0
- md2star-2.0.0/assets/example.md +17 -0
- md2star-2.0.0/assets/logo.png +0 -0
- md2star-2.0.0/assets/pptx/example.md +181 -0
- md2star-2.0.0/assets/references.bib +323 -0
- md2star-2.0.0/assets/run.sh +37 -0
- md2star-2.0.0/docs/audit.md +223 -0
- md2star-2.0.0/docs/developer_guide.md +238 -0
- md2star-2.0.0/docs/installation.md +178 -0
- md2star-2.0.0/md2star/__init__.py +42 -0
- md2star-2.0.0/md2star/__main__.py +31 -0
- md2star-2.0.0/md2star/cache.py +93 -0
- md2star-2.0.0/md2star/cli.py +680 -0
- md2star-2.0.0/md2star/data/defaults/docx-star.yaml +26 -0
- md2star-2.0.0/md2star/data/defaults/pptx-star.yaml +26 -0
- md2star-2.0.0/md2star/data/example.md +17 -0
- md2star-2.0.0/md2star/data/filters/md2star.lua +315 -0
- md2star-2.0.0/md2star/data/mermaid-config.json +60 -0
- md2star-2.0.0/md2star/data/metadata.yaml +2 -0
- md2star-2.0.0/md2star/data/puppeteer-config.json +3 -0
- md2star-2.0.0/md2star/data/template.docx +0 -0
- md2star-2.0.0/md2star/data/template.pptx +0 -0
- md2star-2.0.0/md2star/doctor.py +405 -0
- md2star-2.0.0/md2star/errors.py +127 -0
- md2star-2.0.0/md2star/postprocess.py +259 -0
- md2star-2.0.0/md2star/preprocessing/__init__.py +33 -0
- md2star-2.0.0/md2star/preprocessing/alt_text.py +212 -0
- md2star-2.0.0/md2star/preprocessing/images.py +525 -0
- md2star-2.0.0/md2star/preprocessing/language.py +54 -0
- md2star-2.0.0/md2star/preprocessing/lint.py +261 -0
- md2star-2.0.0/md2star/preprocessing/math.py +145 -0
- md2star-2.0.0/md2star/preprocessing/mermaid.py +186 -0
- md2star-2.0.0/md2star/preprocessing/pipeline.py +409 -0
- md2star-2.0.0/md2star/preprocessing/regexes.py +21 -0
- md2star-2.0.0/md2star/preprocessing/tables.py +519 -0
- md2star-2.0.0/pyproject.toml +127 -0
- md2star-2.0.0/scripts/README.md +27 -0
- md2star-2.0.0/scripts/install.ps1 +88 -0
- md2star-2.0.0/scripts/install.sh +308 -0
- md2star-2.0.0/scripts/test.sh +146 -0
- md2star-2.0.0/scripts/uninstall.ps1 +65 -0
- md2star-2.0.0/scripts/uninstall.sh +84 -0
- md2star-2.0.0/scripts/update.ps1 +15 -0
- md2star-2.0.0/tests/README.md +40 -0
- md2star-2.0.0/tests/conftest.py +19 -0
- md2star-2.0.0/tests/examples/branded_slides.md +35 -0
- md2star-2.0.0/tests/examples/comprehensive_document.md +58 -0
- md2star-2.0.0/tests/examples/comprehensive_presentation.md +70 -0
- md2star-2.0.0/tests/examples/guide_complet_document_fr.md +58 -0
- md2star-2.0.0/tests/examples/run.sh +34 -0
- md2star-2.0.0/tests/examples/table_zoo.md +52 -0
- md2star-2.0.0/tests/fixtures/bibliography.md +15 -0
- md2star-2.0.0/tests/fixtures/images.md +22 -0
- md2star-2.0.0/tests/fixtures/mermaid.md +22 -0
- md2star-2.0.0/tests/fixtures/metadata.md +18 -0
- md2star-2.0.0/tests/fixtures/refs.bib +15 -0
- md2star-2.0.0/tests/fixtures/simple.md +17 -0
- md2star-2.0.0/tests/test_alt_text.py +194 -0
- md2star-2.0.0/tests/test_bibliography_localization.py +80 -0
- md2star-2.0.0/tests/test_doctor.py +172 -0
- md2star-2.0.0/tests/test_integration.py +204 -0
- md2star-2.0.0/tests/test_lua_filter.py +203 -0
- md2star-2.0.0/tests/test_offline_security.py +216 -0
- md2star-2.0.0/tests/test_postprocess.py +230 -0
- md2star-2.0.0/tests/test_preprocessing.py +1047 -0
md2star-2.0.0/.gitignore
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Tests & temp files
|
|
2
|
+
temp/
|
|
3
|
+
temp_*
|
|
4
|
+
~$*
|
|
5
|
+
test_list_extracted/
|
|
6
|
+
|
|
7
|
+
# Private working notes (per-developer scratch, not for main)
|
|
8
|
+
.private/
|
|
9
|
+
|
|
10
|
+
# Credentials directory. The real files (e.g. pypi.env with the
|
|
11
|
+
# TWINE_PASSWORD token) are gitignored; the matching *.example
|
|
12
|
+
# templates are committed so a fresh clone can see what shape to
|
|
13
|
+
# expect. Matches the project style guide rule 8 — see CONTRIBUTING.md.
|
|
14
|
+
.secrets/*
|
|
15
|
+
!.secrets/*.example
|
|
16
|
+
|
|
17
|
+
# Debug scripts (should not be committed)
|
|
18
|
+
debug.lua
|
|
19
|
+
|
|
20
|
+
assets/nexton-template.pptx
|
|
21
|
+
|
|
22
|
+
# Template adaptation temp files
|
|
23
|
+
pptx-templates/_extracted/
|
|
24
|
+
pptx-templates/*-pandoc.pptx
|
|
25
|
+
pptx-templates/pandoc_base.pptx
|
|
26
|
+
pptx-templates/*.pdf
|
|
27
|
+
|
|
28
|
+
# macOS
|
|
29
|
+
.DS_Store
|
|
30
|
+
.AppleDouble
|
|
31
|
+
.LSOverride
|
|
32
|
+
Icon?
|
|
33
|
+
._*
|
|
34
|
+
.DocumentRevisions-V100
|
|
35
|
+
.fseventsd
|
|
36
|
+
.Spotlight-V100
|
|
37
|
+
.TemporaryItems
|
|
38
|
+
.Trashes
|
|
39
|
+
.VolumeIcon.icns
|
|
40
|
+
.com.apple.timemachine.donotpresent
|
|
41
|
+
|
|
42
|
+
# Windows
|
|
43
|
+
Thumbs.db
|
|
44
|
+
Thumbs.db:encryptable
|
|
45
|
+
ehthumbs.db
|
|
46
|
+
ehthumbs_vista.db
|
|
47
|
+
*.stackdump
|
|
48
|
+
[Dd]esktop.ini
|
|
49
|
+
$RECYCLE.BIN/
|
|
50
|
+
*.cab
|
|
51
|
+
*.msi
|
|
52
|
+
*.msix
|
|
53
|
+
*.msm
|
|
54
|
+
*.msp
|
|
55
|
+
*.lnk
|
|
56
|
+
|
|
57
|
+
# Linux
|
|
58
|
+
*~
|
|
59
|
+
.fuse_hidden*
|
|
60
|
+
.directory
|
|
61
|
+
.trash
|
|
62
|
+
.nfs*
|
|
63
|
+
|
|
64
|
+
# VS Code
|
|
65
|
+
.vscode/*
|
|
66
|
+
!.vscode/settings.json
|
|
67
|
+
!.vscode/tasks.json
|
|
68
|
+
!.vscode/launch.json
|
|
69
|
+
!.vscode/extensions.json
|
|
70
|
+
!.vscode/code-actions.json
|
|
71
|
+
*.code-workspace
|
|
72
|
+
|
|
73
|
+
# JetBrains
|
|
74
|
+
.idea/
|
|
75
|
+
|
|
76
|
+
# Sublime Text
|
|
77
|
+
*.sublime-project
|
|
78
|
+
*.sublime-workspace
|
|
79
|
+
|
|
80
|
+
# Vim
|
|
81
|
+
[._]*.s[a-v][a-z]
|
|
82
|
+
[._]*.sw[a-p]
|
|
83
|
+
[._]s[a-rt-v][a-z]
|
|
84
|
+
[._]ss[a-z]
|
|
85
|
+
*.un~
|
|
86
|
+
Session.vim
|
|
87
|
+
.netrwhist
|
|
88
|
+
|
|
89
|
+
# Project Specific
|
|
90
|
+
*.docx
|
|
91
|
+
!assets/template.docx
|
|
92
|
+
!assets/docx/*.docx
|
|
93
|
+
!md2star/data/template.docx
|
|
94
|
+
*.pptx
|
|
95
|
+
!assets/template.pptx
|
|
96
|
+
!assets/pptx/*.pptx
|
|
97
|
+
!md2star/data/template.pptx
|
|
98
|
+
!pptx-templates/*.pptx
|
|
99
|
+
pptx-templates/Jellysmack-Presentation-Template.pptx
|
|
100
|
+
!tests/examples/Presentation1.pptx
|
|
101
|
+
tests/*.pptx
|
|
102
|
+
tests/*.docx
|
|
103
|
+
*.log
|
|
104
|
+
*.tmp
|
|
105
|
+
*.bak
|
|
106
|
+
.remote_*
|
|
107
|
+
.mermaid_*
|
|
108
|
+
|
|
109
|
+
!assets/docx/.*.docx
|
|
110
|
+
!assets/docx/.*.md
|
|
111
|
+
!assets/docx/.*.pptx
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# Python
|
|
115
|
+
__pycache__/
|
|
116
|
+
*.py[cod]
|
|
117
|
+
*.egg-info/
|
|
118
|
+
.pytest_cache/
|
|
119
|
+
.venv/
|
|
120
|
+
dist/
|
|
121
|
+
build/
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
.preprocessed_*
|
|
125
|
+
|
|
126
|
+
# Scratch screenshots from local playwright runs / manual captures.
|
|
127
|
+
# The curated set that ships with the docs lives at assets/screenshots/
|
|
128
|
+
# (tracked) — anything dropped at the repo root is treated as iteration
|
|
129
|
+
# noise and stays local.
|
|
130
|
+
/screenshots/
|
|
131
|
+
|
|
132
|
+
.ruff_cache/
|
|
133
|
+
|
|
134
|
+
.deepeval/
|
|
135
|
+
|
|
136
|
+
.claude/
|
|
137
|
+
|
|
138
|
+
.secrets/
|
|
139
|
+
|
|
140
|
+
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to **md2star** are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project
|
|
5
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [2.0.0] — 2026-06-29
|
|
10
|
+
|
|
11
|
+
This is the PyPI debut. Two breaking changes drive the major bump.
|
|
12
|
+
|
|
13
|
+
### Breaking
|
|
14
|
+
- **Licence is now BSD 3-Clause** (was The Unlicense / public domain).
|
|
15
|
+
Aligned with scikit-learn and the broader scientific-Python
|
|
16
|
+
conventions. Downstream redistributors must now ship the copyright
|
|
17
|
+
notice + disclaimer alongside the binary. The change is permissive
|
|
18
|
+
→ permissive, so existing usage is unaffected; only redistribution
|
|
19
|
+
obligations change.
|
|
20
|
+
- **GUI removed.** The Overleaf-style local web editor (`md2star gui`),
|
|
21
|
+
the `md2star html` subcommand, and the ~3 MB vendored frontend tree
|
|
22
|
+
(Tailwind, CodeMirror, PDF.js, Roboto Serif) have been removed for
|
|
23
|
+
the PyPI debut so the wheel stays under 250 KB. The GUI lives in
|
|
24
|
+
git history and is slated to return as an opt-in extra:
|
|
25
|
+
`pipx install 'md2star[gui]'` in v2.1.
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
- **PyPI distribution.** Install with `pipx install md2star` — no
|
|
29
|
+
clone required for end users. `make install` from a clone still
|
|
30
|
+
works for the development path.
|
|
31
|
+
- **Style guide formalised in CONTRIBUTING.md.** NumPy docstrings,
|
|
32
|
+
module headers with an Author link, and full type annotations
|
|
33
|
+
are now enforced for new and modified code.
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
- **Package description** mentions PDF alongside DOCX/PPTX.
|
|
37
|
+
- **README + LISEZMOI installation sections** restructured around the
|
|
38
|
+
three-OS pattern with the `brew.sh` hint for macOS and `pipx
|
|
39
|
+
install md2star` as the recommended path.
|
|
40
|
+
- **`md2star doctor`** no longer reports a "GUI" feature target.
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
- **PDF tables render correctly via headless LibreOffice.** The
|
|
44
|
+
bundled template's `TableNormal0` custom-style caused soffice to
|
|
45
|
+
spill table cell content out of the table as a vertical paragraph
|
|
46
|
+
dump (Word rendered the same DOCX fine — the bug was the style +
|
|
47
|
+
soffice's interpretation). The PDF pipeline now strips
|
|
48
|
+
`TableNormal0` from the intermediate DOCX before invoking
|
|
49
|
+
soffice (`md2star/postprocess.py:strip_table_normal_for_pdf`).
|
|
50
|
+
DOCX output (`md2docx`) is untouched, so Word users keep the
|
|
51
|
+
styled tables. Test coverage in
|
|
52
|
+
`tests/test_postprocess.py`. Resolves the `[1.1.1] — Known
|
|
53
|
+
issues` entry below.
|
|
54
|
+
|
|
55
|
+
### Removed
|
|
56
|
+
- `md2star/gui_server.py` (the GUI HTTP server).
|
|
57
|
+
- `md2star/data/gui/` (vendored Tailwind / CodeMirror / PDF.js / fonts).
|
|
58
|
+
- `tests/test_gui_security.py` (`/fs/*` path-confinement tests).
|
|
59
|
+
- `scripts/vendor_gui.sh` and the `make vendor` target.
|
|
60
|
+
- `md2star html` standalone-HTML subcommand (it existed solely for
|
|
61
|
+
the GUI preview pane).
|
|
62
|
+
- The `[Public Domain]` classifier in `pyproject.toml`, replaced by
|
|
63
|
+
`[OSI Approved :: BSD License]`.
|
|
64
|
+
|
|
65
|
+
## [1.3.0] — 2026-06-23
|
|
66
|
+
|
|
67
|
+
### Added
|
|
68
|
+
- **AI-drafted alt-text for empty image alts** — when `--lint` is on
|
|
69
|
+
and Ollama is reachable, every `` whose alt is empty is
|
|
70
|
+
described by a local vision model and the rewritten ``
|
|
71
|
+
is what Pandoc sees. URLs, missing files, and non-empty alts pass
|
|
72
|
+
through untouched. Same opt-in surface as the LLM Markdown lint —
|
|
73
|
+
alt-text drafting *is* a form of lint, so it sits behind the same
|
|
74
|
+
`--lint` flag (and `--offline` blocks it just like the text lint).
|
|
75
|
+
Default vision model is whatever the text lint already uses
|
|
76
|
+
(`gemma4:e2b-mlx` on macOS, `gemma4:e2b` elsewhere) — the gemma4
|
|
77
|
+
family is multimodal, so a single `ollama pull` powers both passes.
|
|
78
|
+
Override with `MD2STAR_ALT_TEXT_MODEL` to point alt-text at a
|
|
79
|
+
different vision model. Per-image results are cached at
|
|
80
|
+
`$XDG_CACHE_HOME/md2star/alt-text/<image-md5>_<model>.txt` so reruns
|
|
81
|
+
over the same source tree do not re-query Ollama.
|
|
82
|
+
|
|
83
|
+
## [1.2.0] — 2026-06-23
|
|
84
|
+
|
|
85
|
+
### Added
|
|
86
|
+
- **Branded Mermaid palette** — every rendered diagram now uses the
|
|
87
|
+
Warith colour system from
|
|
88
|
+
[harchaoui.org/warith/colors](https://harchaoui.org/warith/colors):
|
|
89
|
+
light-blue node fills (`#CCE4FF`) with blue borders (`#007AFF`),
|
|
90
|
+
grey edges (`#808080`), light-yellow notes (`#FFF5CC`), and matching
|
|
91
|
+
actor / activation / cluster colours for sequence and gantt
|
|
92
|
+
diagrams. The bundled `mermaid-config.json` switched from `neutral`
|
|
93
|
+
to `base` plus a full `themeVariables` block. Re-rendering is
|
|
94
|
+
automatic — the render-cache key now folds in the resolved config
|
|
95
|
+
hash, so palette edits invalidate stale PNGs on the next run.
|
|
96
|
+
- **Aspect-ratio-aware image cap (A4)** — bare `` images get a
|
|
97
|
+
`{width=15cm}` *or* `{height=17cm}` block based on the image's
|
|
98
|
+
pixel aspect ratio, so the rendered diagram or photo fits an A4
|
|
99
|
+
page in *both* dimensions. Applies uniformly to mermaid renders,
|
|
100
|
+
embedded photos, downloaded remote images, and SVG-to-PNG
|
|
101
|
+
conversions. URLs and unreadable files keep the previous
|
|
102
|
+
`{width=100%}` fallback.
|
|
103
|
+
|
|
104
|
+
### Fixed
|
|
105
|
+
- **Pandoc 3.6 Lua filter crash on tables** — `pandoc.utils.stringify`
|
|
106
|
+
no longer accepts a `Cell` userdata directly; the filter now passes
|
|
107
|
+
`cell.contents` so DOCX / PPTX builds work on Pandoc 3.6+ across
|
|
108
|
+
the whole table-styling path.
|
|
109
|
+
- **Python 3.10 / 3.11 `_data_path` crash** —
|
|
110
|
+
`MultiplexedPath.joinpath` only accepted one argument per call on
|
|
111
|
+
3.10–3.11; walking the components one at a time restores the
|
|
112
|
+
multi-segment `_data_path("filters", "md2star.lua")` form.
|
|
113
|
+
- **Windows date-format crash** — Windows' MSVCRT `strftime` rejects
|
|
114
|
+
`%e` (a GNU extension). The Lua filter now expands `%e` to the
|
|
115
|
+
literal day-of-month before handing the format string to
|
|
116
|
+
`os.date`.
|
|
117
|
+
- **Mermaid rendering on Ubuntu 24.04+ CI runners** — Puppeteer's
|
|
118
|
+
default sandbox is blocked by AppArmor user-namespace restrictions
|
|
119
|
+
on recent Linux distros. A bundled `puppeteer-config.json` passes
|
|
120
|
+
`--no-sandbox --disable-setuid-sandbox` to mmdc so headless Chrome
|
|
121
|
+
starts cleanly.
|
|
122
|
+
- **Bundled templates ship in the wheel** — `template.docx` and
|
|
123
|
+
`template.pptx` were silently excluded by the blanket `*.docx` /
|
|
124
|
+
`*.pptx` gitignore rules. Allow-listed under `md2star/data/` so
|
|
125
|
+
the built sdist / wheel always carry them.
|
|
126
|
+
|
|
127
|
+
## [1.1.1] — 2026-06-21
|
|
128
|
+
|
|
129
|
+
### Added
|
|
130
|
+
- **`assets/example.md`** — the canonical default demo content. The
|
|
131
|
+
GUI's `/example` endpoint serves it; the editor loads it as the
|
|
132
|
+
initial document when no localStorage / server draft is present.
|
|
133
|
+
Also used as the default in screenshots and any future demo runs.
|
|
134
|
+
- **`md2star html`** (and `md2html` if you alias it) — pandoc-only
|
|
135
|
+
HTML5 output path. Standalone document with MathML, inline CSS via
|
|
136
|
+
the bundled `preview.css`. Useful as a fast preview or for
|
|
137
|
+
publishing markdown to a website without the full Office pipeline.
|
|
138
|
+
- **GUI Save button** (replaces the old Clear button) — forces the
|
|
139
|
+
4 s auto-save to run RIGHT NOW. Writes to `/fs/save` when a real
|
|
140
|
+
file is loaded; falls back to the XDG draft cache otherwise. Status
|
|
141
|
+
bar confirms the destination.
|
|
142
|
+
|
|
143
|
+
### Fixed
|
|
144
|
+
- **`md2pdf` first-invocation crash** — the collision check used
|
|
145
|
+
`Path.samefile(out_path)` which raises `FileNotFoundError` when the
|
|
146
|
+
output PDF doesn't exist yet (i.e. every first run). Replaced with
|
|
147
|
+
an unconditional `.md2star.tmp.docx` sidecar so md2pdf can never
|
|
148
|
+
stomp a user's real `.docx` even on a repeat run.
|
|
149
|
+
- **GUI pane-header heights are now uniform** (`min-h-9` on every
|
|
150
|
+
sidebar / editor / preview header bar) so the three columns'
|
|
151
|
+
filename rows line up regardless of which buttons live in each.
|
|
152
|
+
|
|
153
|
+
### Known issues
|
|
154
|
+
- **Tables in the live PDF preview render with empty cells** in some
|
|
155
|
+
environments — the cell contents leak below the table border as a
|
|
156
|
+
vertical paragraph dump. Root cause is an interaction between the
|
|
157
|
+
bundled `template.docx` styles (specifically the `TableNormal0`
|
|
158
|
+
custom-style on top of pandoc's "Compact" cell paragraph) and
|
|
159
|
+
LibreOffice's headless renderer. Workarounds while a deeper fix
|
|
160
|
+
lands: (a) export to DOCX and open in Word, which renders the
|
|
161
|
+
table correctly; (b) write tables as raw `<table>` HTML inside the
|
|
162
|
+
markdown — those are passed through and styled by your reference
|
|
163
|
+
template; (c) avoid the preview rendering of tables and trust the
|
|
164
|
+
DOCX export. The DOCX itself is well-formed; only the soffice →
|
|
165
|
+
PDF intermediate stumbles.
|
|
166
|
+
|
|
167
|
+
## [1.1.0] — 2026-06-21
|
|
168
|
+
|
|
169
|
+
### Added
|
|
170
|
+
- **`md2pdf` / `md2star pdf`** — first-class PDF output. Internally runs
|
|
171
|
+
the DOCX pipeline (so mermaid, table styles, slide-aware tweaks all
|
|
172
|
+
apply) then renders to PDF via headless LibreOffice
|
|
173
|
+
(`soffice --headless --convert-to pdf`). Honors every flag `md2docx`
|
|
174
|
+
accepts (`--author`, `--bib`, `--lang`, `--date`, `--skip-phase`,
|
|
175
|
+
`--lint`, `--reference-doc`).
|
|
176
|
+
- **`--date "string"` CLI flag** (and matching GUI field) overrides
|
|
177
|
+
the auto-localized date in the subtitle. Lets authors backdate,
|
|
178
|
+
post-date, or stamp a non-date label ("Draft 2", "Q2 2026",
|
|
179
|
+
"submitted 14 March") without fighting the auto-locale path. The
|
|
180
|
+
Lua filter gains a `date_override` metadata branch that takes
|
|
181
|
+
priority over `date_format`.
|
|
182
|
+
- **`md2star gui`** — Overleaf-style local web editor. Highlights:
|
|
183
|
+
- CodeMirror 6 Markdown editor (left) + PDF.js preview (right).
|
|
184
|
+
- Debounced auto-render ~2.5 s after typing pause; **⌘↵** / **Ctrl ↵**
|
|
185
|
+
forces a preview-only render (never downloads).
|
|
186
|
+
- Format pill (PDF / DOCX / PPTX) with uniform **"Export X"** buttons.
|
|
187
|
+
Clicking exports + downloads in the chosen format and refreshes the
|
|
188
|
+
PDF preview.
|
|
189
|
+
- **Folder browser sidebar**: Open a folder (native macOS picker via
|
|
190
|
+
`osascript`, `zenity`/`kdialog` on Linux, `FolderBrowserDialog` on
|
|
191
|
+
Windows, or paste a path). Sidebar shows the tree with expandable
|
|
192
|
+
subdirectories. Click an `.md` to load (and any edits auto-save
|
|
193
|
+
back to that file). Non-`.md` files are visible but click-disabled.
|
|
194
|
+
`+` creates a new `.md`, `🗑` deletes selected files (multi-select
|
|
195
|
+
via checkboxes; only `.md` is ever deleted as a safety guard).
|
|
196
|
+
- **Server-side auto-save**: every edit persists 4 s after the last
|
|
197
|
+
keystroke. Routes to `/fs/save` when a real file is open;
|
|
198
|
+
otherwise to `$XDG_CACHE_HOME/md2star/drafts/last.md` as a
|
|
199
|
+
safety net. `navigator.sendBeacon` fires on tab close so the
|
|
200
|
+
very last edit can't get lost in the debounce window.
|
|
201
|
+
- **Theme toggle** (🌗 Auto / 🌞 Light / 🌚 Dark). Auto follows the
|
|
202
|
+
system `prefers-color-scheme`; choice persists in localStorage.
|
|
203
|
+
- **Custom reference templates**: two upload buttons in the options
|
|
204
|
+
drawer ("Load DOCX template" / "Load PPTX template") let the user
|
|
205
|
+
swap the bundled defaults for the active session. The uploaded
|
|
206
|
+
file lives in a per-process tempdir and is removed on
|
|
207
|
+
`/template/clear`.
|
|
208
|
+
- Backend is stdlib `http.server` on 127.0.0.1 only; no
|
|
209
|
+
authentication (single-user laptop tool, same model as Jupyter).
|
|
210
|
+
- **WCAG-AA-compliant color tokens** lifted from
|
|
211
|
+
`https://harchaoui.org/warith/colors/` (full base palette + light
|
|
212
|
+
variants, semantic aliases for surface / label / brand). Uniform
|
|
213
|
+
**10 px corner radius** across every container, button, input,
|
|
214
|
+
drawer, chip, and PDF-page card.
|
|
215
|
+
- **Install-time LibreOffice check**: `scripts/install.sh` /
|
|
216
|
+
`scripts/install.ps1` auto-install LibreOffice via Homebrew /
|
|
217
|
+
apt / dnf / pacman / winget when `soffice` is missing, so
|
|
218
|
+
`md2pdf` and the GUI preview pane work out of the box. Pass
|
|
219
|
+
`--no-libreoffice` (or `-NoLibreOffice` on Windows) to opt out.
|
|
220
|
+
- **Two-line subtitle** (authors on line 1, date on line 2) — the
|
|
221
|
+
Lua filter emits two `<w:p>` paragraphs inside the `Subtitle`
|
|
222
|
+
custom-style Div, both styled identically. Long author lists no
|
|
223
|
+
longer collide with the date on a single line.
|
|
224
|
+
- **Natural-language author list**: a comma-separated `--author`
|
|
225
|
+
string is rewritten as "X" / "X and Y" / "X, Y and Z". The
|
|
226
|
+
conjunction follows the document language: English "and",
|
|
227
|
+
French "et", Spanish "y", German "und", Italian/Portuguese "e",
|
|
228
|
+
Dutch "en", Russian "и"; falls back to "and" for any other.
|
|
229
|
+
|
|
230
|
+
### Changed
|
|
231
|
+
- **GUI is now fully offline.** Tailwind, CodeMirror, PDF.js (worker
|
|
232
|
+
included), Montserrat, and Roboto Serif are vendored under
|
|
233
|
+
`md2star/data/gui/vendor/` (~3.1 MB) and served from the local
|
|
234
|
+
`/vendor/*` paths. `md2star gui` makes zero CDN calls at runtime.
|
|
235
|
+
Refresh script: `make vendor` (requires `curl` + `node`).
|
|
236
|
+
- **CodeMirror is bundled as one esbuild artifact** (not 5 separate
|
|
237
|
+
esm.sh URLs) — separate bundles would each carry their own
|
|
238
|
+
`EditorState` constructor and `instanceof` checks would silently
|
|
239
|
+
break the editor.
|
|
240
|
+
- **Dropped JetBrains Mono** as the editor font; the OS's own system
|
|
241
|
+
monospace stack (`ui-monospace`, `SFMono-Regular`, `Menlo`,
|
|
242
|
+
`Monaco`, `Consolas`) is enough and saves ~100 kB of vendored
|
|
243
|
+
fonts. Added **Roboto Serif** as the serif token
|
|
244
|
+
(`class="font-serif"`) alongside Montserrat for sans.
|
|
245
|
+
- **deraison.ai template fetch** now caches the downloaded template
|
|
246
|
+
in `$XDG_CACHE_HOME/md2star/templates/` instead of dropping a
|
|
247
|
+
~2 MB / 16 MB file next to every source `.md`. First download
|
|
248
|
+
prints one breadcrumb; subsequent runs are silent. Users still
|
|
249
|
+
get per-project branding by placing their own `template.{docx,pptx}`
|
|
250
|
+
next to the source.
|
|
251
|
+
|
|
252
|
+
### Fixed
|
|
253
|
+
- **`pyproject.toml` wheel-build failure**: removed the
|
|
254
|
+
`[tool.hatch.build.targets.wheel.force-include]` block that was
|
|
255
|
+
duplicating `md2star/data/` (already covered by `packages =
|
|
256
|
+
["md2star"]`) and breaking `pipx install`.
|
|
257
|
+
- **GUI preview-empty placeholder stayed visible** after the first
|
|
258
|
+
successful render. Tailwind's `display: grid` on the placeholder
|
|
259
|
+
beat the browser's `[hidden] { display: none }` UA rule. Switched
|
|
260
|
+
to `.classList.add("hidden")` (Tailwind's `display: none
|
|
261
|
+
!important`).
|
|
262
|
+
- **Cache-busting**: GUI server splices a per-process random tag
|
|
263
|
+
into every static-asset URL so stale browsers can't keep serving
|
|
264
|
+
pre-restart `app.js` / `codemirror.js` / `pdf.min.mjs`.
|
|
265
|
+
|
|
266
|
+
### Notes
|
|
267
|
+
- The folder-browser endpoints (`/fs/*`) confine every operation to
|
|
268
|
+
the user-chosen root via `_safe_within_root` (rejects `..`,
|
|
269
|
+
absolute paths, symlink escapes). Delete refuses anything that
|
|
270
|
+
isn't `.md`/`.markdown`. Localhost-only, no auth — same trust
|
|
271
|
+
model as Jupyter or Vite dev. Don't expose to the LAN.
|
|
272
|
+
|
|
273
|
+
## [1.0.0] — 2026-06-20
|
|
274
|
+
|
|
275
|
+
The first proper release. The legacy "git clone + `make install`" workflow
|
|
276
|
+
is replaced by a real Python package; the bash / PowerShell / cmd CLI
|
|
277
|
+
wrappers are replaced by a single Python entry-point module.
|
|
278
|
+
|
|
279
|
+
### Added
|
|
280
|
+
- **`pyproject.toml`** — md2star is now a real installable Python package
|
|
281
|
+
(`pip install -e .` for dev, `pipx install .` for end users).
|
|
282
|
+
- **Console scripts** `md2docx`, `md2pptx`, and `md2star` are registered
|
|
283
|
+
via `[project.scripts]` and implemented once in `md2star/cli.py`.
|
|
284
|
+
- **`md2star/cache.py`** — every on-disk artifact (downloaded remote
|
|
285
|
+
images, downscaled rasters, cell-fitted images, SVG→PNG renders, mermaid
|
|
286
|
+
PNGs) now lives under `$XDG_CACHE_HOME/md2star/` (or the platform
|
|
287
|
+
equivalent on macOS / Windows). The user's source directories stay clean.
|
|
288
|
+
- **`md2star clear-cache`** and **`md2star cache-dir`** subcommands.
|
|
289
|
+
- **`--skip-phase NAME`** CLI flag (repeatable) and matching
|
|
290
|
+
`md2star_skip:` YAML front-matter key. Twelve named phases are
|
|
291
|
+
addressable: `lint`, `remote_images`, `html_tables`, `html_images`,
|
|
292
|
+
`absolutize`, `image_assets`, `language`, `line_pass`, `table_resize`,
|
|
293
|
+
`table_normalize`, `image_widths`, `pptx_isolation`.
|
|
294
|
+
- **`MD2STAR_LINT_MODEL`** environment variable to override the default
|
|
295
|
+
Ollama lint model without editing code.
|
|
296
|
+
- **GitHub Actions CI** (`.github/workflows/ci.yml`) — pytest matrix on
|
|
297
|
+
Python 3.10–3.13, integration suite on Ubuntu + macOS + Windows,
|
|
298
|
+
`shellcheck` on the install scripts.
|
|
299
|
+
- **Lua filter unit tests** (`tests/test_lua_filter.py`) — title
|
|
300
|
+
extraction, subtitle injection, French date rendering, heading-ID
|
|
301
|
+
strip, DOCX horizontal-rule → page break.
|
|
302
|
+
- **Postprocess unit tests** (`tests/test_postprocess.py`) —
|
|
303
|
+
`inject_table_styles` idempotency, partial-pre-existence, byte-identical
|
|
304
|
+
preservation of unrelated zip entries.
|
|
305
|
+
- **`CONTRIBUTING.md`** with quickstart (`make dev` + pytest) and PR
|
|
306
|
+
checklist.
|
|
307
|
+
|
|
308
|
+
### Changed
|
|
309
|
+
- **Install path** is now `pipx install .` (or `make install`). The old
|
|
310
|
+
`bash scripts/install.sh` writes a thin wrapper that just shells to
|
|
311
|
+
pipx; the 150+ lines of heredoc'd shell CLI are gone.
|
|
312
|
+
- **`scripts/test.sh`** no longer mutates `pandoc/metadata.yaml` mid-run
|
|
313
|
+
(which left the repo dirty on Ctrl-C). French date / language is now
|
|
314
|
+
passed via `--lang fr-FR --metadata date_format=...` per call.
|
|
315
|
+
- **Repo size shrunk by ~40 MB** — the regenerable `.docx` / `.pptx`
|
|
316
|
+
fixtures under `tests/examples/` are no longer committed (sources are
|
|
317
|
+
kept; outputs are produced by `tests/examples/run.sh`).
|
|
318
|
+
- **Default reference templates** are now bundled inside the wheel
|
|
319
|
+
(`md2star/data/template.{docx,pptx}`) so a fresh install works fully
|
|
320
|
+
offline. The `https://deraison.ai/template.{docx,pptx}` fallback is
|
|
321
|
+
still consulted when no `template.{docx,pptx}` sits next to the input
|
|
322
|
+
Markdown (preserved per project owner's request).
|
|
323
|
+
- **`make uninstall`** now prints what it will remove and prompts `[y/N]`.
|
|
324
|
+
Pass `--yes` to skip the prompt in CI.
|
|
325
|
+
|
|
326
|
+
### Fixed
|
|
327
|
+
- The committed `tests/examples/.preprocessed_63am_59p.md` artifact (a
|
|
328
|
+
stale temp file) is removed from the repo. The `.gitignore` rule that
|
|
329
|
+
excludes it was already in place.
|
|
330
|
+
- Image cache filenames now use a hash of the source path, eliminating
|
|
331
|
+
the rare collision when two source files with the same basename lived
|
|
332
|
+
in different directories.
|
|
333
|
+
|
|
334
|
+
### Notes
|
|
335
|
+
- The `gemma4:e2b` (Linux/Windows) and `gemma4:e2b-mlx` (macOS) default
|
|
336
|
+
lint models are confirmed published Ollama tags and remain the default.
|
|
337
|
+
- A WYSIWYG markdown editor / local GUI is planned for v1.1.0, building
|
|
338
|
+
on the `front-ui` + `front-cli-gui` Claude Skills.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Contributing to md2star
|
|
2
|
+
|
|
3
|
+
Thanks for considering a contribution. md2star is a small project with one
|
|
4
|
+
maintainer — small, well-scoped PRs are very welcome.
|
|
5
|
+
|
|
6
|
+
## Quickstart
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
git clone https://github.com/warith-harchaoui/md2star.git
|
|
10
|
+
cd md2star
|
|
11
|
+
|
|
12
|
+
# Create a dev venv at .venv/ and install the package editable + dev extras.
|
|
13
|
+
make dev
|
|
14
|
+
|
|
15
|
+
# Activate it (or use ./.venv/bin/<tool> directly).
|
|
16
|
+
source .venv/bin/activate
|
|
17
|
+
|
|
18
|
+
# Run the test suite.
|
|
19
|
+
python -m pytest tests/ -v
|
|
20
|
+
|
|
21
|
+
# Run the integration suite (needs pandoc + the package installed).
|
|
22
|
+
make test
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`make dev` is the only setup step. `pyproject.toml` declares everything
|
|
26
|
+
else (runtime deps, dev deps, console scripts, package data).
|
|
27
|
+
|
|
28
|
+
## Project layout
|
|
29
|
+
|
|
30
|
+
- `md2star/` — the importable Python package.
|
|
31
|
+
- `cli.py` — the single source of truth for `md2docx` / `md2pptx` /
|
|
32
|
+
`md2pdf` / `md2star`. There used to be a bash wrapper, a PowerShell
|
|
33
|
+
wrapper, and a `.cmd` wrapper. Don't bring them back.
|
|
34
|
+
- `doctor.py` — `md2star doctor` environment diagnostic.
|
|
35
|
+
- `preprocessing/` — the 12-phase Markdown preprocessor. The order
|
|
36
|
+
is in `pipeline.py` and is *load-bearing*; reordering needs a
|
|
37
|
+
correctness argument.
|
|
38
|
+
- `postprocess.py` — DOCX-only zip rewrite that re-injects the
|
|
39
|
+
`MyTable` / `MyTableSmall` styles Pandoc strips. Idempotent.
|
|
40
|
+
- `cache.py` — XDG cache dir resolver. Override with
|
|
41
|
+
`MD2STAR_CACHE_DIR` (tests do this via the autouse fixture).
|
|
42
|
+
- `data/` — bundled package data (Lua filter, defaults YAMLs,
|
|
43
|
+
templates, Mermaid config).
|
|
44
|
+
- `tests/` — pytest suite. `conftest.py` redirects the cache to `tmp_path`
|
|
45
|
+
for every test. The three files:
|
|
46
|
+
- `test_preprocessing.py` (~80 tests) — the line-level pipeline.
|
|
47
|
+
- `test_postprocess.py` — DOCX style re-injection.
|
|
48
|
+
- `test_lua_filter.py` — the Pandoc Lua filter (drives pandoc as a
|
|
49
|
+
subprocess; skipped when pandoc is not on PATH).
|
|
50
|
+
- `scripts/` — `install.sh` / `uninstall.sh` / `test.sh` and their
|
|
51
|
+
PowerShell siblings. Thin wrappers; the real install path is `pipx`.
|
|
52
|
+
- `docs/developer_guide.md` — architectural notes (the why, not the what).
|
|
53
|
+
|
|
54
|
+
## PR checklist
|
|
55
|
+
|
|
56
|
+
Before opening a PR:
|
|
57
|
+
|
|
58
|
+
- [ ] `python -m pytest tests/ -v` is green.
|
|
59
|
+
- [ ] `ruff check md2star/ tests/` is clean (no new warnings).
|
|
60
|
+
- [ ] If you touched the Lua filter, the integration suite still passes
|
|
61
|
+
(`make test`) — pytest alone does not cover end-to-end DOCX output.
|
|
62
|
+
- [ ] If you added a new preprocessing phase, register its name in
|
|
63
|
+
`md2star.preprocessing.pipeline.PHASES` so `--skip-phase` knows
|
|
64
|
+
about it, and add at least one test in `tests/test_preprocessing.py`
|
|
65
|
+
covering the skip behavior.
|
|
66
|
+
- [ ] No new files in `tests/examples/` larger than ~50 kB unless you've
|
|
67
|
+
checked it in via Git LFS. The regenerable demos live there as
|
|
68
|
+
Markdown only; their `.docx` / `.pptx` outputs are produced by
|
|
69
|
+
`tests/examples/run.sh` and intentionally not committed.
|
|
70
|
+
- [ ] If you added user-facing flags, update both `README.md` and
|
|
71
|
+
`LISEZMOI.md` (and `CHANGELOG.md`'s `## [Unreleased]` section).
|
|
72
|
+
- [ ] If you added a network-touching code path, route it through the
|
|
73
|
+
`--offline` / `--allow-remote-*` gates (see `md2star/cli.py`
|
|
74
|
+
and the contract in `SECURITY.md`).
|
|
75
|
+
- [ ] All `.py` files you add or modify keep a module header docstring
|
|
76
|
+
with an Author block linking to
|
|
77
|
+
[Warith HARCHAOUI](https://linkedin.com/in/warith-harchaoui/),
|
|
78
|
+
NumPy-style docstrings on every public function/class, and full
|
|
79
|
+
type annotations.
|
|
80
|
+
|
|
81
|
+
## Conventions
|
|
82
|
+
|
|
83
|
+
- **One short docstring per module / public function.** The codebase
|
|
84
|
+
already documents *why*, not *what* — keep that bias.
|
|
85
|
+
- **No backward-compat shims** unless you can name a real outside caller
|
|
86
|
+
that relies on the old API. This is a small, single-author project; do
|
|
87
|
+
the rename and update the imports.
|
|
88
|
+
- **Don't add features beyond the PR's stated scope.** A bug fix doesn't
|
|
89
|
+
need surrounding cleanup; a refactor doesn't need to also touch the
|
|
90
|
+
CHANGELOG format. Smaller diffs review faster.
|
|
91
|
+
|
|
92
|
+
## Rebuilding the bundled templates
|
|
93
|
+
|
|
94
|
+
`md2star/data/template.docx` and `md2star/data/template.pptx` ship the
|
|
95
|
+
branded reference docs that every conversion picks up by default. They
|
|
96
|
+
were rebuilt in v2.0.0 from a Pandoc-clean baseline so soffice renders
|
|
97
|
+
tables as proper grids (vs the v1.x vertical-dump bug).
|
|
98
|
+
|
|
99
|
+
To regenerate either from scratch:
|
|
100
|
+
|
|
101
|
+
1. Dump Pandoc's built-in reference (has every named style /
|
|
102
|
+
layout):
|
|
103
|
+
|
|
104
|
+
pandoc --print-default-data-file reference.docx > /tmp/ref.docx
|
|
105
|
+
pandoc --print-default-data-file reference.pptx > /tmp/ref.pptx
|
|
106
|
+
|
|
107
|
+
2. Write a comprehensive markdown source that exercises every
|
|
108
|
+
element you want to style. The two we used for v2.0 live in
|
|
109
|
+
`.private/template-source.md` (DOCX) and
|
|
110
|
+
`.private/template-pptx-source.md` (PPTX) — copy them as a
|
|
111
|
+
starting point.
|
|
112
|
+
|
|
113
|
+
3. Render with the default ref:
|
|
114
|
+
|
|
115
|
+
pandoc src.md -o branded.docx --reference-doc=/tmp/ref.docx
|
|
116
|
+
pandoc src.md -o branded.pptx --reference-doc=/tmp/ref.pptx
|
|
117
|
+
|
|
118
|
+
4. Open in Word / PowerPoint / Keynote / LibreOffice and brand:
|
|
119
|
+
fonts, colours, margins, logo in headers / slide masters,
|
|
120
|
+
etc. Don't rename existing styles — pandoc looks them up by
|
|
121
|
+
name (`Heading1`, `Title`, `Hyperlink`, ...). For PPTX, the
|
|
122
|
+
layout names must match the pandoc set: `Title Slide`,
|
|
123
|
+
`Section Header`, `Title and Content`, `Two Content`,
|
|
124
|
+
`Comparison`, `Content with Caption`, `Blank`, `Title Only`,
|
|
125
|
+
`Picture with Caption`.
|
|
126
|
+
|
|
127
|
+
5. Save back to `md2star/data/template.docx` /
|
|
128
|
+
`md2star/data/template.pptx` and verify:
|
|
129
|
+
|
|
130
|
+
md2docx assets/docx/basic.md && md2pdf assets/docx/basic.md
|
|
131
|
+
md2pptx assets/pptx/example.md
|
|
132
|
+
|
|
133
|
+
The tables in the PDF should render as a proper grid (not a
|
|
134
|
+
column-major vertical dump); pandoc should not warn about
|
|
135
|
+
missing layout names on the PPTX.
|
|
136
|
+
|
|
137
|
+
## Reporting bugs
|
|
138
|
+
|
|
139
|
+
Open an issue with: the input Markdown that triggers the bug, the exact
|
|
140
|
+
command you ran, the full stderr output, and your `md2star --version` /
|
|
141
|
+
`pandoc --version`. If the bug is in DOCX/PPTX output, attaching the
|
|
142
|
+
produced file is much faster than a long description.
|
|
143
|
+
|
|
144
|
+
## Licence
|
|
145
|
+
|
|
146
|
+
By contributing you agree your contributions are released under the
|
|
147
|
+
**BSD 3-Clause License**, the same licence as the rest of the project.
|
|
148
|
+
See [LICENSE](LICENSE) for the full text.
|