pdfmd-cli 3.24.19__tar.gz → 3.25.20__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.
Files changed (129) hide show
  1. {pdfmd_cli-3.24.19/pdfmd_cli.egg-info → pdfmd_cli-3.25.20}/PKG-INFO +279 -27
  2. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/README.md +278 -26
  3. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd.py +2342 -524
  4. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20/pdfmd_cli.egg-info}/PKG-INFO +279 -27
  5. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_cli.egg-info/SOURCES.txt +45 -1
  6. pdfmd_cli-3.25.20/pdfmd_cli.egg-info/top_level.txt +13 -0
  7. pdfmd_cli-3.25.20/pdfmd_direct/__init__.py +14 -0
  8. pdfmd_cli-3.25.20/pdfmd_direct/defaults.py +166 -0
  9. pdfmd_cli-3.25.20/pdfmd_direct/html.py +207 -0
  10. pdfmd_cli-3.25.20/pdfmd_direct/typst.py +34 -0
  11. pdfmd_cli-3.25.20/pdfmd_edit/__init__.py +284 -0
  12. pdfmd_cli-3.25.20/pdfmd_help/__init__.py +178 -0
  13. pdfmd_cli-3.25.20/pdfmd_history/__init__.py +11 -0
  14. pdfmd_cli-3.25.20/pdfmd_history/git.py +86 -0
  15. pdfmd_cli-3.25.20/pdfmd_history/hst.py +133 -0
  16. pdfmd_cli-3.25.20/pdfmd_history/versions.py +99 -0
  17. pdfmd_cli-3.25.20/pdfmd_images/__init__.py +11 -0
  18. pdfmd_cli-3.25.20/pdfmd_images/remote.py +60 -0
  19. pdfmd_cli-3.25.20/pdfmd_images/scan.py +70 -0
  20. pdfmd_cli-3.25.20/pdfmd_images/svg.py +107 -0
  21. pdfmd_cli-3.25.20/pdfmd_lua/__init__.py +17 -0
  22. pdfmd_cli-3.25.20/pdfmd_lua/code.lua +90 -0
  23. pdfmd_cli-3.25.20/pdfmd_lua/code_wrap.tex +15 -0
  24. pdfmd_cli-3.25.20/pdfmd_lua/csv_table.lua +443 -0
  25. pdfmd_cli-3.25.20/pdfmd_lua/graphicx.tex +1 -0
  26. pdfmd_cli-3.25.20/pdfmd_lua/images.lua +68 -0
  27. pdfmd_cli-3.25.20/pdfmd_lua/pdf_images.lua +94 -0
  28. pdfmd_cli-3.25.20/pdfmd_lua/raw.lua +318 -0
  29. pdfmd_cli-3.25.20/pdfmd_lua/table_width.lua +216 -0
  30. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_office/__init__.py +2 -2
  31. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_office/docx_post.py +49 -0
  32. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_office/office.lua +84 -6
  33. pdfmd_cli-3.25.20/pdfmd_raw/__init__.py +90 -0
  34. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_setup/registry.py +28 -3
  35. pdfmd_cli-3.25.20/pdfmd_tables/__init__.py +8 -0
  36. pdfmd_cli-3.25.20/pdfmd_tables/convert.py +427 -0
  37. pdfmd_cli-3.25.20/pdfmd_tables/scan.py +382 -0
  38. pdfmd_cli-3.25.20/pdfmd_tables/verify.py +65 -0
  39. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pyproject.toml +2 -1
  40. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_attach.py +28 -1
  41. pdfmd_cli-3.25.20/tests/test_code_blocks.py +165 -0
  42. pdfmd_cli-3.25.20/tests/test_compat.py +124 -0
  43. pdfmd_cli-3.25.20/tests/test_csv_table.py +125 -0
  44. pdfmd_cli-3.25.20/tests/test_direct.py +296 -0
  45. pdfmd_cli-3.25.20/tests/test_docx_tables.py +49 -0
  46. pdfmd_cli-3.25.20/tests/test_edit.py +125 -0
  47. pdfmd_cli-3.25.20/tests/test_embedding.py +209 -0
  48. pdfmd_cli-3.25.20/tests/test_help.py +62 -0
  49. pdfmd_cli-3.25.20/tests/test_history.py +224 -0
  50. pdfmd_cli-3.25.20/tests/test_images.py +297 -0
  51. pdfmd_cli-3.25.20/tests/test_markdown_features.py +65 -0
  52. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_native.py +11 -0
  53. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_office_latex.py +77 -0
  54. pdfmd_cli-3.25.20/tests/test_raw.py +246 -0
  55. pdfmd_cli-3.25.20/tests/test_soffice_parts.py +81 -0
  56. pdfmd_cli-3.25.20/tests/test_table_widths.py +113 -0
  57. pdfmd_cli-3.25.20/tests/test_tables.py +532 -0
  58. pdfmd_cli-3.25.20/tests/test_typst_input.py +80 -0
  59. pdfmd_cli-3.25.20/tests/test_versions.py +258 -0
  60. pdfmd_cli-3.24.19/pdfmd_cli.egg-info/top_level.txt +0 -5
  61. pdfmd_cli-3.24.19/tests/test_csv_table.py +0 -62
  62. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/LICENSE +0 -0
  63. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_cli.egg-info/dependency_links.txt +0 -0
  64. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_cli.egg-info/entry_points.txt +0 -0
  65. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_cli.egg-info/requires.txt +0 -0
  66. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/LICENSE +0 -0
  67. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/VENDORED.md +0 -0
  68. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/__init__.py +0 -0
  69. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/_kerning_data.py +0 -0
  70. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/assets/fonts/DejaVuSans-LICENSE.txt +0 -0
  71. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/assets/fonts/DejaVuSans.ttf +0 -0
  72. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/ast.py +0 -0
  73. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/cidfont.py +0 -0
  74. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/embedded.py +0 -0
  75. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/embedded_metrics.py +0 -0
  76. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/emoji.py +0 -0
  77. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/emoji_font.py +0 -0
  78. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/fonts.py +0 -0
  79. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/html_filter.py +0 -0
  80. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/image_loader.py +0 -0
  81. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/layout.py +0 -0
  82. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/parser.py +0 -0
  83. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/pdf.py +0 -0
  84. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/py.typed +0 -0
  85. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/render.py +0 -0
  86. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/truetype.py +0 -0
  87. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_inkmd/url_filter.py +0 -0
  88. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_office/docx.py +0 -0
  89. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_office/fonts.py +0 -0
  90. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_office/fragments.py +0 -0
  91. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_office/labels.py +0 -0
  92. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_office/odt.py +0 -0
  93. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_office/spec.py +0 -0
  94. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_office/units.py +0 -0
  95. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_setup/__init__.py +0 -0
  96. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_setup/fancy.py +0 -0
  97. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_setup/plain.py +0 -0
  98. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_unicode/__init__.py +0 -0
  99. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_unicode/_catalog.py +0 -0
  100. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_unicode/_scripts.py +0 -0
  101. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_unicode/_tessdata_catalog.py +0 -0
  102. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_unicode/colorfont.py +0 -0
  103. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_unicode/emoji.py +0 -0
  104. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_unicode/fonts.py +0 -0
  105. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_unicode/install.py +0 -0
  106. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_unicode/plan.py +0 -0
  107. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_unicode/scripts.py +0 -0
  108. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_unicode/tessdata.py +0 -0
  109. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/pdfmd_unicode/translit.py +0 -0
  110. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/setup.cfg +0 -0
  111. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_api.py +0 -0
  112. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_apple_emoji.py +0 -0
  113. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_cache_location.py +0 -0
  114. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_completion.py +0 -0
  115. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_config.py +0 -0
  116. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_display_path.py +0 -0
  117. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_doctor.py +0 -0
  118. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_install_ocr.py +0 -0
  119. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_lookup.py +0 -0
  120. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_office.py +0 -0
  121. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_packaging.py +0 -0
  122. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_pdf_input.py +0 -0
  123. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_polish.py +0 -0
  124. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_sections.py +0 -0
  125. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_setup.py +0 -0
  126. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_tessdata.py +0 -0
  127. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_text_input.py +0 -0
  128. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_translit.py +0 -0
  129. {pdfmd_cli-3.24.19 → pdfmd_cli-3.25.20}/tests/test_unicode.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pdfmd-cli
3
- Version: 3.24.19
3
+ Version: 3.25.20
4
4
  Summary: One command from Markdown to a good-looking PDF: a Pandoc wrapper with smart defaults, project-file discovery and a multi-engine fallback chain
5
5
  Author: Ali Perdekhan
6
6
  License-Expression: MIT
@@ -40,7 +40,9 @@ Dynamic: license-file
40
40
  [Pandoc](https://pandoc.org) and fills in everything you would otherwise
41
41
  have to remember: sensible fonts and margins, the right Markdown dialect,
42
42
  your project's metadata/preamble/filter files, and a fallback chain across
43
- every PDF engine you have installed.
43
+ every PDF engine you have installed. The same document also builds to a
44
+ Word or OpenDocument file that follows its page setup, fonts and LaTeX (see
45
+ [Word and OpenDocument output](#word-and-opendocument-output)).
44
46
 
45
47
  ```console
46
48
  $ pdfmd lecture
@@ -48,6 +50,11 @@ AUTO: READER TITLE MARGIN MONOFONT. Use --verbose to see in full
48
50
  OK lecture.md
49
51
  ```
50
52
 
53
+ In a folder with a single Markdown file you do not even need the name: `cd` into the folder and run `pdfmd`. It finds
54
+ the file, its metadata, preamble and filters, and writes the PDF beside it (with several Markdown files it asks for
55
+ one, or for `-b` to convert all of them or `-r` to join them). `pdfmd --help` is one short page; `pdfmd --help all`
56
+ is the complete option list and `pdfmd --help tables` (or `source`, `history`, `output` ...) one subject at a time.
57
+
51
58
  <p align="center">
52
59
  <img src="https://raw.githubusercontent.com/aliperdehan/pdfmd/main/docs/lecture.png" width="560" alt="lecture.md rendered to PDF">
53
60
  </p>
@@ -76,6 +83,13 @@ turns that knowledge into defaults:
76
83
  - **It doesn't give up on the first engine.** If `lualatex` fails or isn't
77
84
  installed, it tries the next engine, then the next, and tells you why each
78
85
  one failed.
86
+ - **It writes real Word files.** `pdfmd report -o report.docx` reads the front matter the PDF reads (paper size,
87
+ margins, fonts, line spacing) and writes it into the file's page setup and styles, so the Word file is laid out the
88
+ way the PDF is. With LaTeX installed, what only LaTeX can say in the document comes along: `\ce{...}` chemistry,
89
+ `\SI{...}{...}` units and equations become native, editable Word text and equations; a house style's own macros can be
90
+ given a Word recipe; what is left (tikz, chemfig, math Pandoc cannot convert) is drawn by LaTeX in the document's
91
+ own preamble and embedded as vector pictures. `pdfmd-options: {office: {latex: auto|images|off}}`, `--no-auto
92
+ officelatex` and `pdfmd --setup` switch it (see [Word and OpenDocument output](#word-and-opendocument-output)).
79
93
  - **It handles every script and emoji.** Text the main font cannot draw (Arabic,
80
94
  Hebrew, Chinese, Japanese, Korean, Greek, Cyrillic with Kazakh letters, Indic and
81
95
  more) is set run by run in an installed font for its script, emoji become colour
@@ -86,6 +100,17 @@ turns that knowledge into defaults:
86
100
  `pdfmd mingyun` finds `命運.md`.
87
101
  - **It reads PDFs too.** `pdfmd paper.pdf` restores a PDF's own embedded source or
88
102
  OCRs the pages to Markdown (see [PDF to Markdown](#pdf-to-markdown)).
103
+ - **Tables can be data.** A `::: {.csv}` block puts a table's data in a CSV file or right in the document (any
104
+ delimiter, alignment and widths as attributes), and `pdfmd --extract-tables` turns the tables you already have into
105
+ such blocks after checking that Pandoc reads the same tables back (see [Tables straight from a CSV
106
+ file](#tables-straight-from-a-csv-file)). A table that is too wide gets its columns sized by their content.
107
+ - **Long code wraps, SVG and web images work.** Code lines wrap at the margin in a LaTeX build, an SVG is converted for
108
+ LaTeX with whatever is installed, and an image from the web is fetched once and kept.
109
+ - **Finished files are not rewritten.** A `.typ` file goes to Typst and an `.html` file to WeasyPrint or a browser, so
110
+ the page setup, styles and scripts survive; `--hybrid` makes the PDF open in LibreOffice as an editable document.
111
+ - **It keeps the history.** `pdfmd --history` lists the backups, commits and compiles of a file, `--history-restore`
112
+ puts a version back (backing up the one it replaces), and the build history can live in a `.hst` file instead of the
113
+ document (see [Build stamps, history and snapshots](#build-stamps-history-and-snapshots)).
89
114
  - **It shows what it did.** Every automatic decision prints an `AUTO` line,
90
115
  `-v` shows the exact Pandoc command, and every default can be switched off.
91
116
 
@@ -156,8 +181,8 @@ Office files.
156
181
  <details>
157
182
  <summary>Without pipx</summary>
158
183
 
159
- `pdfmd.py` is a single file that needs Python 3.9+ (with `pdfmd_inkmd/`
160
- beside it for the no-Pandoc fallback). It also runs
184
+ `pdfmd.py` needs Python 3.9+ and runs straight from a clone, with the folders beside it
185
+ (`pdfmd_inkmd/` for the no-Pandoc fallback, `pdfmd_office/`, `pdfmd_setup/`, `pdfmd_unicode/`). It also runs
161
186
  directly, and `pyyaml`/`pypdf` are optional (features that need them are
162
187
  skipped with a warning):
163
188
 
@@ -199,7 +224,7 @@ the cache, ending with the command that fixes each missing piece:
199
224
  $ pdfmd --doctor
200
225
  ...
201
226
  Reading PDFs (PDF to Markdown):
202
- OK batchocr 1.2.4
227
+ OK batchocr 1.2.5
203
228
  MISS tesseract: not found
204
229
  MISS poppler: not found
205
230
 
@@ -219,6 +244,27 @@ pdfmd --completion bash > ~/.local/share/bash-completion/completions/pdfmd
219
244
  pdfmd --completion fish > ~/.config/fish/completions/pdfmd.fish
220
245
  ```
221
246
 
247
+ ### An older Pandoc, and a machine with no network
248
+
249
+ The oldest Pandoc `pdfmd` is tested with is **3.1.3** (what the claude.ai sandbox has); the whole test suite runs against
250
+ it. An older one may work, and the first build with it says so once; `pdfmd --doctor` lists what a given Pandoc does
251
+ without. With 3.1.3: Typst PDFs cannot show a picture `pdfmd` drew itself (before 3.2), a numbered equation in a Word file
252
+ sits in a plain table instead of a borderless one (before 3.4), and `--extract-tables` leaves a table whose caption has
253
+ a `{#tbl:id}` (before 3.8.2: Pandoc reads that as words, so the change could not be checked). A `pandoc-crossref` must be
254
+ the release built for the Pandoc you run; one built for another is not run, with a warning, because it would put `??` where
255
+ the numbers go.
256
+
257
+ Where `pip install pdfmd-cli` cannot reach the network (a sandbox with no DNS that only takes an upload), two ways:
258
+
259
+ ```sh
260
+ python3 scripts/build_zipapp.py # on a machine with pdfmd's source: dist/pdfmd.pyz, 1.4 MB, PyYAML and pypdf inside
261
+ python3 pdfmd.pyz report.md # on the other: needs Python 3.9+, Pandoc and a PDF engine; unpacks itself once
262
+ # into ~/.cache/pdfmd/pyz/ because Pandoc has to open the Lua filters as files
263
+
264
+ pip download pdfmd-cli -d wheelhouse # or: a folder of wheels, carried over
265
+ pip install --no-index --find-links wheelhouse pdfmd-cli
266
+ ```
267
+
222
268
  ### No Pandoc? The built-in fallback
223
269
 
224
270
  On a machine with no Pandoc, or Pandoc but no PDF engine, `pdfmd` does not
@@ -322,6 +368,28 @@ letters, no tones, vowels left out where the script leaves them out. Names that
322
368
  romanize alike (homophones) are listed as ambiguous, never picked between. The
323
369
  same spelling rules find a section by its heading (`doc#tyche`).
324
370
 
371
+ ### A small editor
372
+
373
+ ```sh
374
+ pdfmd --install tui # once: prompt_toolkit, about 1 MB
375
+ pdfmd --edit lecture # nano-like full screen; Ctrl-B saves and builds, Ctrl-P opens the PDF
376
+ ```
377
+
378
+ `pdfmd --edit` (alpha) opens the Markdown file in a plain full-screen editor with the build one key away: Ctrl-S
379
+ saves, Ctrl-B saves and builds (what pdfmd said stays at the bottom), Ctrl-P opens the result, Ctrl-W / F3 find,
380
+ Ctrl-G go to a line, Ctrl-K / Ctrl-U cut and paste a line, Ctrl-Z / Ctrl-Y undo and redo, Ctrl-X leaves (asking once
381
+ when there are unsaved changes); F1 lists them. Options given beside it (`pdfmd --edit lecture -e lualatex`) are used
382
+ for the build, and a name that does not exist yet starts a new file. It is deliberately rough: a base for what comes later.
383
+
384
+ ### In VS Code
385
+
386
+ `pdfmd --init-vscode` writes a `.vscode/tasks.json` here (build, build and open, watch, extract tables; Terminal > Run
387
+ Build Task). The [`vscode/`](https://github.com/aliperdehan/pdfmd/tree/main/vscode) folder of the repository is a small
388
+ extension over the same command line: build (`Cmd/Ctrl+Alt+B`), build and open, build as Word/HTML/Typst/slides, extract
389
+ tables (all, or chosen ones), file history, compare and restore, restore the source a PDF carries (right-click it). Every
390
+ command it runs is written to the *pdfmd* output panel. Install it with `npx @vscode/vsce package` and
391
+ `code --install-extension pdfmd-vscode-*.vsix`.
392
+
325
393
  ### One section
326
394
 
327
395
  `pdfmd doc#onlyapart` builds just the section whose heading is "Only a Part"
@@ -445,8 +513,9 @@ LaTeX. For `.docx` and `.odt` pdfmd adds a filter that makes it native where it
445
513
  environment or macro behind each (`the tikzpicture environment`, `the macro \irspectrum`), without drawing or writing anything: a
446
514
  quick way to see what is left to give a recipe (see the profile below).
447
515
 
448
- `pdfmd-options: {office: {latex: off}}` or `--no-auto officelatex` skips all of it, `office: {labels: off}`
449
- skips the PDF build (numbers are then counted).
516
+ `pdfmd-options: {office: {latex: auto}}` is the default; `latex: images` draws everything LaTeX says as a picture
517
+ (formulas, `\ce` and units too, instead of making them native); `latex: off` or `--no-auto officelatex` skips all of it
518
+ (Pandoc's own behaviour). `office: {labels: off}` skips the PDF build (numbers are then counted).
450
519
 
451
520
  The same filter serves the other outputs when LaTeX is the problem: **the soffice fallback** (the Word file above, then LibreOffice: `pdfmd -e soffice report.md` is the `.docx` as LibreOffice draws it) now
452
521
  keeps the page size, margins and fonts, shows equations and draws what LaTeX can; a **Typst or WeasyPrint run after LaTeX
@@ -570,12 +639,16 @@ style, a compound library, a shared bibliography and parts.
570
639
  The TeX distribution's own packages, fonts and Pandoc are not carried.
571
640
  - **Comments.** Notes to yourself do not travel: the attached source loses its
572
641
  `<!-- -->` comments, the LaTeX preamble's `%` comments, the text between a
573
- `.bib`'s entries and a CSL file's XML comments. Choose per kind:
574
- `strip-comments: [preamble, bibliography]` or `{markdown: false}`
575
- (`--strip-comments-in`, `--keep-comments-in`). Code blocks, `\verb`, `\url` and
576
- verbatim environments are never touched, and a `%` that closes a line keeps a
577
- bare `%`, because it swallows the line break. YAML metadata is merged and
578
- written again, so its `#` comments are always gone.
642
+ `.bib`'s entries, a CSL file's XML comments and the `#` comments of YAML
643
+ files. Choose per kind: `strip-comments: [preamble, bibliography]` or
644
+ `{markdown: false}` (`--strip-comments-in`, `--keep-comments-in`). Code
645
+ blocks, `\verb`, `\url` and verbatim environments are never touched, and a
646
+ `%` that closes a line keeps a bare `%`, because it swallows the line break.
647
+ With `strip-comments: false` (or `metadata` kept) the attached source gives
648
+ back your metadata files and the document's front matter byte for byte,
649
+ comments and quoting included; `--restore` of such a PDF is a full source
650
+ copy. The data files of `.csv` blocks (`tables/*.csv`) are always stored
651
+ with the source.
579
652
  - **Only the bibliography entries you cite** are attached (and what they
580
653
  cross-reference), not a shared file of hundreds; `attach-bibliography: all`
581
654
  keeps it whole, and `nocite: '@*'` keeps every entry.
@@ -832,12 +905,31 @@ Measured values:
832
905
  <img src="https://raw.githubusercontent.com/aliperdehan/pdfmd/main/docs/results.png" width="480" alt="A CSV file rendered as a table">
833
906
  </p>
834
907
 
908
+ Or write the data in the document itself, in a code block so that nothing in it is read as Markdown:
909
+
910
+ ````markdown
911
+ ::: {.csv align="lrr"}
912
+ ```
913
+ Compound,Mass (g),Price
914
+ Water,18.015,1.20
915
+ "Ethanol, dry",46.07,3.45
916
+ ```
917
+ :::
918
+
919
+ : Masses and prices {#tbl:m}
920
+ ````
921
+
835
922
  - Cells are read as Pandoc Markdown (`H~2~O`, `$x^2$`, `\ce{...}`, `[@key]`); `reader="gfm"` makes them plain GFM.
836
923
  - A caption is the line after the block (`: Caption {#tbl:id}`, or `Table: Caption`), or `caption="Caption"` inside the
837
924
  braces, with the identifier as `#tbl:id` there too. A caption in the attributes wins over a line after the block.
838
- - A relative `file=` is found beside the document (and along the resource path), wherever Pandoc runs.
839
- - The delimiter is detected from the extension (`.tsv` means tab), or set
840
- with `delimiter=";"`.
925
+ - A relative `file=` is found beside the document (and along the resource path), wherever Pandoc runs. With both
926
+ `file=` and data inside the block, the file is used.
927
+ - The delimiter is `delimiter=";"` or its name (`semicolon`, `tab`, `pipe`, `space`, `colon`, `comma`); without one it
928
+ comes from the extension (`.tsv` means tab) or from the first line (whichever of `,` `;` tab `|` it holds most of).
929
+ - Columns are aligned with `align="lcr"` (or `align="left,center,right"`), or by a second row in the data made of
930
+ `---`, `:--`, `:-:`, `--:` as in a pipe table; `align=` wins. If such a row is really data, say `separator="none"`.
931
+ `widths="5,1,1"` sets relative widths, and a second row with unequal dashes does too. Without either, pdfmd picks
932
+ widths that suit the contents.
841
933
  - The first row is the header unless you add `header="false"`.
842
934
  - Large files are capped at 10 rows × 7 columns, so a huge CSV can't
843
935
  silently fill 40 pages. `rows=all` or `cols=20` raise the cap. When a
@@ -845,6 +937,118 @@ Measured values:
845
937
 
846
938
  This works for every output format.
847
939
 
940
+ #### Turning tables into CSV blocks, and back
941
+
942
+ ```
943
+ pdfmd --extract-tables report.md # every table becomes a .csv block reading tables/<name>.csv
944
+ pdfmd --expand-tables report.md # and back to ordinary tables
945
+ ```
946
+
947
+ `--extract-tables` rewrites the document in place, after copying the old one to the backup folder, and says so. Pipe,
948
+ simple, multiline and grid tables are all read (the ones inside code blocks are not tables). The files are named after
949
+ the captions (`Masses and prices` gives `tables/masses-and-prices.csv`), or `table1`, `table2` by position;
950
+ `--table-names a,b,c` names them, and a list that does not match the number of tables is an error that changes nothing.
951
+ `--table-numbers 1,3-4` extracts just those tables (by position in the document) and leaves the rest; the names then go to
952
+ the chosen ones. In a document in parts the data goes to the report's `tables/` folder and an unnamed table is named after
953
+ its part (`discussion-table1.csv`).
954
+ The caption, the alignment and the widths the document chose stay as attributes of the block, and before anything is
955
+ written Pandoc reads the old and the new document and the tables must come out the same. A table Pandoc cannot write
956
+ as CSV (a list inside a cell, a cell spanning rows, no header row) is left as it is, with the reason; so is every
957
+ `.csv` block already in the document, and if the check fails the whole document is left untouched and the command exits
958
+ with an error. A document with no front matter is built as `gfm`, which reads pipe tables only, so only those are
959
+ touched there. `--tables-inline` puts the data
960
+ inside the document (in a fenced block) instead of in files, `--tables-dir DIR` picks the folder, and `--dry-run` shows
961
+ the change without making it. `--expand-tables` is the reverse, every row included.
962
+
963
+ A `.csv` block that holds its data inside the document stays as it is, unless you pass `--extract-inline-csv`, which moves
964
+ that data to a file as well. To keep one table or block as it is whatever you run, put `<!-- pdfmd: ignore -->` on the
965
+ line above it (or under its caption); the comment survives comment stripping, because pdfmd's own comments are kept.
966
+ A comment between a table and its caption would stop Pandoc from reading the caption as one, so there is no such
967
+ position.
968
+
969
+ ### Code: wrapping and line numbers
970
+
971
+ With a LaTeX engine a long line of code wraps at the margin instead of running off the page (a long path or option list
972
+ breaks where the line is full), and `{wrap=false}` on one block, `--no-code-wrap` or `code-wrap: false` in
973
+ `pdfmd-options` lets it run on. Line numbers are off until you ask for them:
974
+
975
+ ````markdown
976
+ ``` {.python .numberLines startFrom=10}
977
+ def f(x):
978
+ return x * 2
979
+ ```
980
+ ````
981
+
982
+ `--line-numbers` (or `pdfmd-options: {line-numbers: true}`, or the setting in `pdfmd --setup`) numbers every code block,
983
+ `--line-numbers 5` numbers every fifth line, `{.noNumberLines}` leaves one block out, and `step=5` and `numbersep=8pt`
984
+ adjust a single block.
985
+
986
+ ### Images: SVG and remote ones
987
+
988
+ LaTeX reads PDF, PNG and JPEG, not SVG. In a LaTeX build pdfmd converts each SVG the document names, once, with
989
+ whatever is installed (`rsvg-convert`, Inkscape, `cairosvg`, `svglib`, or LibreOffice, which most machines have), keeps
990
+ the PDF by the file's content, and uses it where the document wrote the SVG: a Markdown image, a raw
991
+ `\includegraphics{figure.svg}`, a raw `\includesvg{figure}`. A raw `\includegraphics` also gets `graphicx` loaded,
992
+ which Pandoc only does for a Markdown image (a PNG in one used to stop the build with "undefined control sequence").
993
+ A Markdown image from the web is fetched once and kept for a week, so the build does not need the network again, an SVG
994
+ badge works, and a Pandoc built without HTTP support (Homebrew's is) no longer drops it; with no network there is one
995
+ warning and the image's description stays. `--no-auto svg` and `--no-auto remoteimages` turn the two off, and
996
+ `pdfmd --doctor` says which converter will be used.
997
+
998
+ ### Editable in LibreOffice, and one file that carries its data
999
+
1000
+ `--hybrid` makes the PDF a LibreOffice *hybrid PDF*: besides its pages it carries an OpenDocument copy of the document
1001
+ (`Original.odt`, or `.odp`, `.ods`), and when LibreOffice opens the PDF it opens that copy as a document you can edit,
1002
+ instead of the pages in Draw. An Office file (`pdfmd minutes.docx --hybrid`) is converted by LibreOffice, so the copy is
1003
+ the file itself; a Markdown file gets an `.odt` built by pdfmd with its metadata, so what LibreOffice shows is the
1004
+ Word-route rendering of the source (not the LaTeX pages). `pdfmd --restore report.pdf` writes the ODF file back out.
1005
+ `pdfmd-options: {hybrid: true}` or `pdfmd --setup` makes it the default.
1006
+
1007
+ A single Markdown file can carry its data too: `pdfmd report.md --assemble-only --embed-metadata files -o report.one.md`
1008
+ folds in the images, CSV tables and included files the text points at (text as it is, anything else as base64), and the
1009
+ file builds on its own, in an empty folder; `pdfmd --unpack` writes them back byte for byte. It is left out of the default
1010
+ kinds because it can be big (`bundle-max-mb` caps it); for a PDF, `--bundle` stores the same files beside the source.
1011
+
1012
+ ### HTML, LaTeX, Typst and Word pieces inside Markdown
1013
+
1014
+ Markdown can carry raw pieces: `<img>`, `<table>`, `<b>` and `<div>` (HTML), `\ce{...}` or a tikz picture (LaTeX), a
1015
+ `` ```{=typst} `` block, Word or OpenDocument XML. Pandoc keeps the ones written in the format it is writing and drops
1016
+ every other, silently, so a document that mixes them loses pieces in every build. `pdfmd-options.raw` (or `--raw`) says
1017
+ which syntaxes take part in each output family, and carries the foreign ones over:
1018
+
1019
+ ```yaml
1020
+ pdfmd-options:
1021
+ raw:
1022
+ tex: [tex, html, typst] # LaTeX builds: PDF through lualatex, xelatex ...
1023
+ typst: [typst, html, tex] # Typst builds
1024
+ html: [html, tex, typst] # HTML, EPUB, PDF through weasyprint and the other HTML engines (-e html)
1025
+ office: [office, html] # Word and OpenDocument, and PDF through soffice
1026
+ ```
1027
+
1028
+ ```sh
1029
+ pdfmd report --raw # everything for every family
1030
+ pdfmd report --raw-for html=tex,typst --raw-for tex=html # or per family, on the command line
1031
+ ```
1032
+
1033
+ A family takes the syntaxes it lists, in this way: its own syntax stays as written; **HTML** is read by Pandoc's HTML
1034
+ reader, so an `<img>` becomes the target's image (an SVG then goes through the image conversion below), a `<table>` a
1035
+ real table, `<b>...</b>` bold text and a `<div>` around Markdown a division, even when the opening and the closing tag
1036
+ sit in separate pieces; **LaTeX** is read by Pandoc's LaTeX reader (what it does not know, a custom macro, stays LaTeX
1037
+ and is lost outside LaTeX; Word builds keep their own LaTeX route, see
1038
+ [Word and OpenDocument output](#word-and-opendocument-output)); **Typst** is drawn by `typst compile` as a cropped
1039
+ vector picture, a PDF for LaTeX, Typst and Word, an SVG for HTML. A syntax a family does not list is dropped, its own
1040
+ included, which is odd but a clear way to say "this output has no HTML in it". A family not mentioned is left to Pandoc
1041
+ as it always was, `raw: all` lists everything, and `--no-raw` turns it off for a run. Pictures are kept in pdfmd's cache by
1042
+ their content. (An HTML file that is not self-contained points at the cache; use `--self-contained` to carry them.)
1043
+ Not yet: LaTeX pieces Pandoc cannot read (tikz, chemfig) as pictures in HTML, HTML drawn as a picture, Word XML as
1044
+ anything but Word XML.
1045
+
1046
+ **PDF images in HTML.** A browser does not show a PDF in `<img>`, an SVG it does. For an HTML build (a web page, an
1047
+ EPUB, a PDF through WeasyPrint) every image that is a PDF, `![fig](plot.pdf)` or `<img src="plot.pdf">`, is converted to
1048
+ an SVG with poppler's `pdftocairo` (or `mutool`, `pdf2svg`, `inkscape`) and stays vector; the first page is used and the
1049
+ SVG is kept by the PDF's content. It is on by default, since it only changes what would not have shown; `--no-auto
1050
+ pdfimages` turns it off. LaTeX and Typst read PDFs themselves, and Word has its own route.
1051
+
848
1052
  ### Not just Markdown
849
1053
 
850
1054
  ```sh
@@ -853,9 +1057,24 @@ pdfmd paper.tex # compiled directly with a LaTeX engine: reruns until
853
1057
  # no .aux/.log clutter (--keep-aux keeps them)
854
1058
  pdfmd minutes.docx # Word/PowerPoint/Excel/ODF: converted by LibreOffice
855
1059
  pdfmd analysis.qmd # handed to Quarto, so code chunks actually run
856
- pdfmd page.html # anything else Pandoc can read (give the extension)
1060
+ pdfmd page.html # built by WeasyPrint, or a browser if the page runs scripts: no Pandoc
1061
+ pdfmd note.typ # compiled by Typst itself: the page setup in the file is kept
1062
+ pdfmd notes.rst # anything else Pandoc can read (give the extension)
857
1063
  ```
858
1064
 
1065
+ A finished `.typ` or `.html` file goes straight to its own engine, because Pandoc would read it into its own model
1066
+ and write it out again, and the page size, the styles and the scripts would not survive the trip. For a page that is
1067
+ WeasyPrint first (it is quiet and needs no browser); a page with `<script>` goes to Chrome, Chromium, Edge or Brave
1068
+ (headless, printing the page), as does one WeasyPrint cannot draw, and wkhtmltopdf, Prince, pagedjs-cli and LibreOffice
1069
+ come after. `-e edge` (or `weasyprint`, `chromium`...) picks one. As with an Office file, such a document gets none of
1070
+ pdfmd's defaults, since it is finished; `--apply-defaults` (also in `pdfmd --setup`) gives it the title, author, date,
1071
+ language, font, font size, paper and margin of its `metadata.yaml`, ahead of its own settings so those win. A `.tex`
1072
+ file that no LaTeX engine can compile is tried through Pandoc, with a warning.
1073
+
1074
+ The reader comes from the file's extension, as in Pandoc, and a bare name is looked up as `<name>.md`, so give the
1075
+ extension for anything else. The automatic decisions about Markdown (`READER`, `TITLE`, `citeproc`, `crossref` below)
1076
+ apply to Markdown files only.
1077
+
859
1078
  **A plain-text file as Markdown (opt-in).** `pdfmd notes.txt --text-to-markdown` reads a `.txt` file the way a person typed it
860
1079
  and guesses its structure: headings (capitals, `1.2 Title`, `====` underlines), bullet and numbered lists, tables from
861
1080
  columns separated by runs of spaces, indented blocks as code, hard-wrapped lines joined into paragraphs. The words never
@@ -871,16 +1090,19 @@ Most of these print an `AUTO` line, and each can be switched off individually.
871
1090
 
872
1091
  | `AUTO` kind | When | What happens |
873
1092
  |---|---|---|
874
- | `READER` | no YAML front matter | reads the file as GitHub-flavoured Markdown (content-sized table columns, relaxed blank-line rules) |
875
- | `TITLE` | no front matter, first line is `# Title` | that heading becomes the document title, and the remaining headings move up one level |
1093
+ | `READER` | a Markdown file with no YAML front matter | reads the file as GitHub-flavoured Markdown (content-sized table columns, relaxed blank-line rules) |
1094
+ | `TITLE` | a Markdown file with no front matter, first line is `# Title` | that heading becomes the document title, and the remaining headings move up one level |
876
1095
  | `MARGIN` | no margin or geometry set anywhere | 1-inch margins instead of LaTeX's wide defaults |
877
1096
  | `MAINFONT` | no `mainfont:` and no `-f` | STIX Two Text (Times New Roman if it isn't installed), or a serif that has the letters when the document is mostly in a script STIX Two Text lacks (Kazakh Cyrillic, say); retried with DejaVu Serif if a glyph is still missing. A font you name is never changed except by `fallback: document` |
878
1097
  | `UNICODE` | text the main font cannot draw (Arabic, Han, Greek with accents, rare symbols...) | sets each run in an installed font for its script (see *Other scripts*), instead of printing boxes |
879
1098
  | `MONOFONT` | the document contains code | JetBrains Mono for code (Menlo or another installed monospace font if it isn't installed) |
880
- | `tablewidth` | a wide pipe table | balances column widths so the table fits the page, and leaves narrow tables at their natural width |
1099
+ | `tablewidth` | a pipe table with plain `---` separators and long lines | picks the column widths that give the fewest lines within the text width (a column never narrower than its longest word), and gives a table that fits its natural width back; unequal dashes (`--|-----`) are kept, and `table-widths: keep` in `pdfmd-options` leaves every table as written |
1100
+ | `svg`, `remoteimages` | an SVG, or an image from the web, in a LaTeX build | the SVG is converted to a PDF (once), the remote image is fetched and kept (`--no-auto svg`, `--no-auto remoteimages`) |
1101
+ | `typstdirect`, `htmldirect` | a `.typ` or `.html` file | built by Typst / WeasyPrint or a browser, not through Pandoc (`--no-auto typstdirect` for the old route) |
1102
+ | `codewrap` | code blocks in a LaTeX build | long lines wrap at the margin (`--no-code-wrap` or `--no-auto codewrap` for the old behaviour) |
881
1103
  | `YAML` / `TEX` / `LUA` | project files found | attaches `metadata.yaml`, `preamble.tex`, `<name>.lua` (see below) |
882
- | `citeproc` | `@key` / `[@key, p. 90]` citations | adds `--citeproc`, so citations and the reference list render from your `bibliography:` without any flag (`--no-citeproc` turns it off) |
883
- | `crossref` | `@fig:`/`@tbl:` references | adds the `pandoc-crossref` filter, ahead of citeproc |
1104
+ | `citeproc` | `@key` / `[@key, p. 90]` citations (as Pandoc reads them: `@key` in a code span or an e-mail address is none) | adds `--citeproc`, so citations and the reference list render from your `bibliography:` without any flag (`--no-citeproc` turns it off) |
1105
+ | `crossref` | `@fig:`/`@tbl:` references or `{#fig:...}` labels | adds the `pandoc-crossref` filter, ahead of citeproc |
884
1106
  | `papersize` | `pagesize: a4` (a common typo) | converts it to Pandoc's real `papersize:` |
885
1107
 
886
1108
  `-v` explains each decision and prints the exact command it runs:
@@ -1093,15 +1315,16 @@ One shared metadata file can also be **symlinked** into many folders. A
1093
1315
  relative `bibliography: refs.bib` inside it then finds the `refs.bib`
1094
1316
  next to the file's real copy, so you never need an absolute path.
1095
1317
 
1096
- ## Build stamps and snapshots
1318
+ ## Build stamps, history and snapshots
1097
1319
 
1098
- Both are off by default.
1320
+ All are off by default.
1099
1321
 
1100
1322
  - **`--stamp`** keeps a `BUILD NOTES` HTML comment at the end of the `.md`
1101
1323
  up to date. It records when the document was compiled and with which
1102
1324
  `pdfmd` version, plus the versions of any LaTeX packages you name with
1103
1325
  `--stamp-packages`. The comment is invisible in the PDF. `--stamp-mode history` also keeps a list of past compiles.
1104
- - **`--backup`** saves a timestamped copy of the source into `backup/`
1326
+ - **`--backup`** saves a timestamped copy of the source into `.backups/` (a hidden folder; an existing `backup/` is kept
1327
+ using, and pdfmd says where the first copy went)
1105
1328
  after every successful build. A copy is skipped when nothing changed,
1106
1329
  and `keep: 30` limits how many are kept.
1107
1330
 
@@ -1110,16 +1333,45 @@ Both can be turned on for a whole folder from `metadata.yaml`:
1110
1333
  ```yaml
1111
1334
  pdfmd-options:
1112
1335
  stamp: true
1113
- backup: { dir: backup, keep: 30 }
1336
+ backup: { dir: .backups, keep: 30 }
1337
+ ```
1338
+
1339
+ **History in a file instead of in the document.** `--stamp-store file` (or `stamp: {store: file}`) writes each compile
1340
+ to `NAME.hst` in the backup folder, and the document itself is not edited by a build. The file is one line per entry,
1341
+ newest first, so it reads in any editor, two of them join with `cat`, and `pdfmd --merge-history a.hst b.hst -o all.hst`
1342
+ keeps every entry once:
1343
+
1344
+ ```
1345
+ # pdfmd history of report.md -- one entry per line, newest first: WHEN | KIND | TEXT [| key=value ...]
1346
+ 2026-10-09 11:22:01 | compiled | with nulabreport v1.27.7, pdfmd v3.25.7 | sha=3fa91c0d4b21 out=report.pdf
1114
1347
  ```
1115
1348
 
1349
+ `pdfmd --history-to-file report.md` moves the whole `BUILD NOTES` block that pdfmd owns into that file (the compiles as
1350
+ entries, anything written by hand inside it as one `note` entry), and `--history-to-notes` builds the block again (both
1351
+ back the document up first, `--dry-run` shows). A document may carry several
1352
+ `BUILD NOTES` blocks (yours, an AI agent's): pdfmd writes only into the one that already holds its own lines, or the
1353
+ only one there is, or starts one of its own when there are several and none is its; the rest is never touched, and a
1354
+ line `pdfmd: ignore` in a block keeps pdfmd out of it. The file travels with the document: `--embed-metadata` folds it
1355
+ in (`hst`), `--unpack` writes it out, and `--attach-source` stores it in the PDF for `--restore`.
1356
+
1357
+ **Going back.** `pdfmd --history report.md` lists every version it can find, newest first: the backups (in `.backups`,
1358
+ and in an older `backup/`, `backups/`... beside the document, whatever naming each file has), the git commits that
1359
+ changed the file (the repository may be a folder above), and the compiles recorded in its history. In a terminal the
1360
+ list is navigable: a number shows what differs, `d 3` the diff, `r 3` restores. Without one, `--history-diff` and
1361
+ `--history-restore` take a number, a backup's timestamp (any start of it: `20261003`), a file name, a commit hash,
1362
+ `latest`, or `previous` (the newest that is not the file as it is). A restore backs the file up first, so nothing is
1363
+ ever lost; it keeps the build notes and history of the file as it is now, and adds a `Restored version ...` entry
1364
+ (`stamp: {restored-note: false}` or `--no-restored-note` leave it out; `--dry-run` shows what would change).
1365
+ `pdfmd --init-backups report.md` turns all of this on for a document: backups and a history file, set in its front
1366
+ matter under an `AUTO GENERATED` comment (`--global` for every document), and a first copy.
1367
+
1116
1368
  Separately, when `pypdf` is installed, every PDF built by `pdfmd` gets two
1117
1369
  hidden metadata keys, `PdfmdVersions` and `PdfmdBuildDate`, which you can
1118
1370
  read with `pdfinfo -meta`. Turn this off with `--no-stamp-pdf-metadata`.
1119
1371
 
1120
1372
  ## Reference
1121
1373
 
1122
- - [`docs/recipes.md`](https://github.com/aliperdehan/pdfmd/blob/main/docs/recipes.md) has short "how do I..." answers: a paper in several scripts, a scanned PDF to Markdown, a folder with a house style, a book from many files.
1374
+ - [`docs/recipes.md`](https://github.com/aliperdehan/pdfmd/blob/main/docs/recipes.md) is the task-by-task manual: fifteen chapters of "how do I..." with the commands (the basics, a house style, long documents, tables, code and images, raw HTML/LaTeX/Typst, other inputs and outputs, the PDF that carries its source, history, fonts and scripts, speed, the editor and VS Code, and what to do when something looks wrong), plus an option reference by task.
1123
1375
  - `pdfmd --help` lists every flag.
1124
1376
  - The docstring at the top of [`pdfmd.py`](https://github.com/aliperdehan/pdfmd/blob/main/pdfmd.py) is the full reference
1125
1377
  for each behaviour and its edge cases.