pdfmd-cli 3.31.46__tar.gz → 3.32.12__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 (348) hide show
  1. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/CHANGELOG.md +273 -0
  2. {pdfmd_cli-3.31.46/pdfmd_cli.egg-info → pdfmd_cli-3.32.12}/PKG-INFO +364 -6
  3. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/README.md +363 -5
  4. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/docs/recipes.md +3 -0
  5. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd.py +1028 -94
  6. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12/pdfmd_cli.egg-info}/PKG-INFO +364 -6
  7. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_cli.egg-info/SOURCES.txt +24 -0
  8. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_cli.egg-info/top_level.txt +1 -0
  9. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_help/__init__.py +2 -2
  10. pdfmd_cli-3.32.12/pdfmd_kits/install.py +367 -0
  11. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_kits/kitfile.py +20 -2
  12. pdfmd_cli-3.32.12/pdfmd_lua/cellalign.lua +110 -0
  13. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/diagram.lua +69 -8
  14. pdfmd_cli-3.32.12/pdfmd_lua/limited_run.py +65 -0
  15. pdfmd_cli-3.32.12/pdfmd_lua/linebreak.lua +110 -0
  16. pdfmd_cli-3.32.12/pdfmd_lua/md_macro.lua +187 -0
  17. pdfmd_cli-3.32.12/pdfmd_ranking/__init__.py +12 -0
  18. pdfmd_cli-3.32.12/pdfmd_ranking/choose.py +254 -0
  19. pdfmd_cli-3.32.12/pdfmd_ranking/rules.py +459 -0
  20. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_setup/inventory.py +8 -2
  21. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_setup/registry.py +57 -5
  22. pdfmd_cli-3.32.12/pdfmd_tables/ascii.py +497 -0
  23. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pyproject.toml +1 -1
  24. pdfmd_cli-3.32.12/tests/test_cellalign.py +110 -0
  25. pdfmd_cli-3.32.12/tests/test_diagram_timeout.py +124 -0
  26. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_diagrams.py +49 -0
  27. pdfmd_cli-3.32.12/tests/test_kit_install.py +315 -0
  28. pdfmd_cli-3.32.12/tests/test_kit_no_auto.py +143 -0
  29. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_kit_texinputs.py +32 -1
  30. pdfmd_cli-3.32.12/tests/test_linebreak.py +127 -0
  31. pdfmd_cli-3.32.12/tests/test_md_macro.py +133 -0
  32. pdfmd_cli-3.32.12/tests/test_ranking_bare.py +129 -0
  33. pdfmd_cli-3.32.12/tests/test_ranking_generated.py +188 -0
  34. pdfmd_cli-3.32.12/tests/test_ranking_layers.py +220 -0
  35. pdfmd_cli-3.32.12/tests/test_ranking_lists.py +163 -0
  36. pdfmd_cli-3.32.12/tests/test_ranking_rules.py +315 -0
  37. pdfmd_cli-3.32.12/tests/test_ranking_which.py +117 -0
  38. pdfmd_cli-3.32.12/tests/test_reader.py +218 -0
  39. pdfmd_cli-3.32.12/tests/test_scoop_bucket.py +43 -0
  40. pdfmd_cli-3.32.12/tests/test_slide_notes.py +162 -0
  41. pdfmd_cli-3.32.12/tests/test_table_ascii.py +314 -0
  42. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_tables.py +12 -2
  43. pdfmd_cli-3.31.46/tests/test_reader.py +0 -73
  44. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/LICENSE +0 -0
  45. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/MANIFEST.in +0 -0
  46. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/docs/agents.md +0 -0
  47. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_ansi/__init__.py +0 -0
  48. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_ansi/highlight.py +0 -0
  49. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_ansi/mathbox.py +0 -0
  50. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_ansi/native.py +0 -0
  51. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_ansi/render.py +0 -0
  52. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_ansi/text.py +0 -0
  53. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_buildinfo/__init__.py +0 -0
  54. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_buildinfo/record.py +0 -0
  55. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_buildinfo/timing.py +0 -0
  56. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_check/__init__.py +0 -0
  57. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_check/lint.py +0 -0
  58. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_chem/__init__.py +0 -0
  59. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_chem/__main__.py +0 -0
  60. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_chem/batch.py +0 -0
  61. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_chem/render.py +0 -0
  62. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_chem/siunitx.py +0 -0
  63. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_cli.egg-info/dependency_links.txt +0 -0
  64. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_cli.egg-info/entry_points.txt +0 -0
  65. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_cli.egg-info/requires.txt +0 -0
  66. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_crop/__init__.py +0 -0
  67. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_crop/images.py +0 -0
  68. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_css/__init__.py +0 -0
  69. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_direct/__init__.py +0 -0
  70. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_direct/defaults.py +0 -0
  71. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_direct/html.py +0 -0
  72. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_direct/typst.py +0 -0
  73. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_docs/__init__.py +0 -0
  74. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_edit/__init__.py +0 -0
  75. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_flat/__init__.py +0 -0
  76. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_flat/asciify.py +0 -0
  77. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_flat/keep.py +0 -0
  78. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_history/__init__.py +0 -0
  79. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_history/git.py +0 -0
  80. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_history/hst.py +0 -0
  81. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_history/versions.py +0 -0
  82. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_images/__init__.py +0 -0
  83. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_images/remote.py +0 -0
  84. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_images/scan.py +0 -0
  85. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_images/svg.py +0 -0
  86. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/LICENSE +0 -0
  87. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/VENDORED.md +0 -0
  88. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/__init__.py +0 -0
  89. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/_kerning_data.py +0 -0
  90. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/assets/fonts/DejaVuSans-LICENSE.txt +0 -0
  91. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/assets/fonts/DejaVuSans.ttf +0 -0
  92. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/ast.py +0 -0
  93. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/cidfont.py +0 -0
  94. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/embedded.py +0 -0
  95. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/embedded_metrics.py +0 -0
  96. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/emoji.py +0 -0
  97. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/emoji_font.py +0 -0
  98. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/fonts.py +0 -0
  99. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/html_filter.py +0 -0
  100. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/image_loader.py +0 -0
  101. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/layout.py +0 -0
  102. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/parser.py +0 -0
  103. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/pdf.py +0 -0
  104. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/py.typed +0 -0
  105. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/render.py +0 -0
  106. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/truetype.py +0 -0
  107. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_inkmd/url_filter.py +0 -0
  108. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_kits/__init__.py +0 -0
  109. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_kits/discovery.py +0 -0
  110. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_kits/preamble.py +0 -0
  111. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_kits/selection.py +0 -0
  112. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_labels/__init__.py +0 -0
  113. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_labels/replay.py +0 -0
  114. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_labels/scan.py +0 -0
  115. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/__init__.py +0 -0
  116. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/ascii.lua +0 -0
  117. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/calc.lua +0 -0
  118. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/chem.lua +0 -0
  119. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/chem_client.lua +0 -0
  120. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/code.lua +0 -0
  121. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/code_wrap.tex +0 -0
  122. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/cover.lua +0 -0
  123. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/csv_table.lua +0 -0
  124. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/ebook.lua +0 -0
  125. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/ebook_input.lua +0 -0
  126. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/flat.lua +0 -0
  127. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/graphicx.tex +0 -0
  128. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/graphviz.cjs +0 -0
  129. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/images.lua +0 -0
  130. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/indent.lua +0 -0
  131. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/katex.cjs +0 -0
  132. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/markup.lua +0 -0
  133. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/mathjax.cjs +0 -0
  134. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/metadata_append.lua +0 -0
  135. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/pagebreak.lua +0 -0
  136. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/pdf_images.lua +0 -0
  137. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/raw.lua +0 -0
  138. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/select.lua +0 -0
  139. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/smiles.lua +0 -0
  140. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/table_caption.lua +0 -0
  141. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/table_width.lua +0 -0
  142. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/title_meta.lua +0 -0
  143. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/typst.lua +0 -0
  144. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_lua/weasyprint.lua +0 -0
  145. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_mhchem/LICENSE +0 -0
  146. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_mhchem/__init__.py +0 -0
  147. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_mhchem/parser.py +0 -0
  148. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_office/__init__.py +0 -0
  149. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_office/docx.py +0 -0
  150. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_office/docx_post.py +0 -0
  151. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_office/fonts.py +0 -0
  152. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_office/fragments.py +0 -0
  153. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_office/labels.py +0 -0
  154. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_office/odt.py +0 -0
  155. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_office/office.lua +0 -0
  156. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_office/properties.py +0 -0
  157. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_office/spec.py +0 -0
  158. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_office/units.py +0 -0
  159. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_raw/__init__.py +0 -0
  160. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_setup/__init__.py +0 -0
  161. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_setup/fancy.py +0 -0
  162. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_setup/plain.py +0 -0
  163. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_setup/userpath.py +0 -0
  164. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_smiles/__init__.py +0 -0
  165. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_smiles/__main__.py +0 -0
  166. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_smiles/batch.py +0 -0
  167. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_tables/__init__.py +0 -0
  168. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_tables/captions.py +0 -0
  169. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_tables/convert.py +0 -0
  170. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_tables/scan.py +0 -0
  171. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_tables/sheets.py +0 -0
  172. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_tables/verify.py +0 -0
  173. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/__init__.py +0 -0
  174. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/article/__name__.md +0 -0
  175. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/article/description.txt +0 -0
  176. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/article/next.txt +0 -0
  177. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/article/refs.bib +0 -0
  178. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/book/__name__.md +0 -0
  179. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/book/description.txt +0 -0
  180. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/book/next.txt +0 -0
  181. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/book/parts/10-introduction.md +0 -0
  182. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/book/parts/20-methods.md +0 -0
  183. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/book/parts/30-results.md +0 -0
  184. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/notes/__name__.md +0 -0
  185. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/notes/description.txt +0 -0
  186. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/notes/next.txt +0 -0
  187. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/report/__name__.md +0 -0
  188. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/report/data.csv +0 -0
  189. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/report/description.txt +0 -0
  190. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/report/next.txt +0 -0
  191. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/slides/__name__.md +0 -0
  192. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/slides/description.txt +0 -0
  193. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_templates/data/slides/next.txt +0 -0
  194. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_unicode/__init__.py +0 -0
  195. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_unicode/_catalog.py +0 -0
  196. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_unicode/_scripts.py +0 -0
  197. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_unicode/_tessdata_catalog.py +0 -0
  198. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_unicode/colorfont.py +0 -0
  199. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_unicode/emoji.py +0 -0
  200. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_unicode/fonts.py +0 -0
  201. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_unicode/install.py +0 -0
  202. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_unicode/plan.py +0 -0
  203. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_unicode/scripts.py +0 -0
  204. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_unicode/tessdata.py +0 -0
  205. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/pdfmd_unicode/translit.py +0 -0
  206. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/setup.cfg +0 -0
  207. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/setup.py +0 -0
  208. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_00_environment.py +0 -0
  209. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_ansi.py +0 -0
  210. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_api.py +0 -0
  211. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_apple_emoji.py +0 -0
  212. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_ascii.py +0 -0
  213. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_atomic.py +0 -0
  214. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_attach.py +0 -0
  215. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_attach_format.py +0 -0
  216. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_attach_layers.py +0 -0
  217. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_auto_states.py +0 -0
  218. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_autolog.py +0 -0
  219. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_backup_summary.py +0 -0
  220. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_bopen.py +0 -0
  221. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_browser_engine.py +0 -0
  222. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_budget.py +0 -0
  223. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_build_log.py +0 -0
  224. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_build_record.py +0 -0
  225. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_build_time.py +0 -0
  226. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_cache_location.py +0 -0
  227. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_calc.py +0 -0
  228. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_calibre.py +0 -0
  229. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_calibre_markdown.py +0 -0
  230. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_calibre_targets.py +0 -0
  231. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_check.py +0 -0
  232. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_check_source.py +0 -0
  233. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_chem.py +0 -0
  234. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_code_blocks.py +0 -0
  235. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_command_words.py +0 -0
  236. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_compat.py +0 -0
  237. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_completion.py +0 -0
  238. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_config.py +0 -0
  239. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_cover.py +0 -0
  240. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_crop.py +0 -0
  241. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_css.py +0 -0
  242. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_css_v2.py +0 -0
  243. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_csv_switch.py +0 -0
  244. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_csv_table.py +0 -0
  245. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_diagram_shim.py +0 -0
  246. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_direct.py +0 -0
  247. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_display_path.py +0 -0
  248. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_doc.py +0 -0
  249. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_docs_consistency.py +0 -0
  250. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_doctor.py +0 -0
  251. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_docx_tables.py +0 -0
  252. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_ebook_input.py +0 -0
  253. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_edit.py +0 -0
  254. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_edit_pdf.py +0 -0
  255. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_embedding.py +0 -0
  256. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_engine_chain.py +0 -0
  257. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_engine_filters.py +0 -0
  258. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_flat.py +0 -0
  259. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_folder_settings.py +0 -0
  260. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_formula.py +0 -0
  261. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_header_includes.py +0 -0
  262. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_help.py +0 -0
  263. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_history.py +0 -0
  264. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_images.py +0 -0
  265. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_indent.py +0 -0
  266. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_indent_office.py +0 -0
  267. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_install_calibre.py +0 -0
  268. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_install_core_tex.py +0 -0
  269. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_install_diagram.py +0 -0
  270. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_install_ocr.py +0 -0
  271. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_install_python.py +0 -0
  272. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_interrupt.py +0 -0
  273. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_jobs.py +0 -0
  274. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_katex_scale.py +0 -0
  275. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_keep_source.py +0 -0
  276. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_kit_carry.py +0 -0
  277. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_kit_preamble.py +0 -0
  278. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_kit_selection.py +0 -0
  279. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_kits.py +0 -0
  280. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_labels.py +0 -0
  281. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_latex_errors.py +0 -0
  282. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_lookup.py +0 -0
  283. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_lua_missing.py +0 -0
  284. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_lua_trust.py +0 -0
  285. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_markdown_features.py +0 -0
  286. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_markup_appendix.py +0 -0
  287. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_markup_callouts.py +0 -0
  288. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_markup_center.py +0 -0
  289. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_markup_highlight.py +0 -0
  290. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_markup_keep.py +0 -0
  291. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_markup_landscape.py +0 -0
  292. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_markup_space.py +0 -0
  293. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_markup_toc.py +0 -0
  294. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_markup_word.py +0 -0
  295. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_mathfont.py +0 -0
  296. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_mathjax.py +0 -0
  297. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_metadata_append.py +0 -0
  298. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_mhchem.py +0 -0
  299. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_native.py +0 -0
  300. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_office.py +0 -0
  301. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_office_latex.py +0 -0
  302. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_old_python_syntax.py +0 -0
  303. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_package_helper.py +0 -0
  304. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_packaging.py +0 -0
  305. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_pagebreak.py +0 -0
  306. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_pan_tec.py +0 -0
  307. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_paper.py +0 -0
  308. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_partial_history.py +0 -0
  309. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_partial_provenance.py +0 -0
  310. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_path_display.py +0 -0
  311. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_pdf_input.py +0 -0
  312. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_picture_cache_protocol.py +0 -0
  313. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_plot_cache.py +0 -0
  314. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_polish.py +0 -0
  315. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_presets.py +0 -0
  316. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_probes.py +0 -0
  317. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_raw.py +0 -0
  318. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_rawcode.py +0 -0
  319. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_readonly_home.py +0 -0
  320. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_remote_csl.py +0 -0
  321. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_rewrite.py +0 -0
  322. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_sections.py +0 -0
  323. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_setup.py +0 -0
  324. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_setup_folder.py +0 -0
  325. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_show_comments.py +0 -0
  326. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_smiles.py +0 -0
  327. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_soffice_parts.py +0 -0
  328. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_soffice_timeout.py +0 -0
  329. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_spreadsheets.py +0 -0
  330. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_standalone_source.py +0 -0
  331. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_stdin.py +0 -0
  332. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_svg_profile.py +0 -0
  333. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_symlinked_parts.py +0 -0
  334. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_table_captions.py +0 -0
  335. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_table_keep.py +0 -0
  336. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_table_widths.py +0 -0
  337. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_templates.py +0 -0
  338. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_tessdata.py +0 -0
  339. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_tex_bin.py +0 -0
  340. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_tex_cause.py +0 -0
  341. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_texpackages.py +0 -0
  342. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_text_input.py +0 -0
  343. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_tool_locations.py +0 -0
  344. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_translit.py +0 -0
  345. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_typst_input.py +0 -0
  346. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_unicode.py +0 -0
  347. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_user_path.py +0 -0
  348. {pdfmd_cli-3.31.46 → pdfmd_cli-3.32.12}/tests/test_versions.py +0 -0
@@ -19,6 +19,279 @@ same commit as the change.
19
19
 
20
20
  ---
21
21
 
22
+ ## v3.32.12c — 2026-11-03
23
+
24
+ Tests only; `PDFMD_VERSION` stays 3.32.12. The second CI run (41546953982) failed in three tests of the 3.31.x-3.32.8 commits, which had never run on CI before; none is a bug in pdfmd:
25
+
26
+ - `test_tables`: a document with no front matter used to be read as gfm, so its grid and simple tables were "left as they are" with a NOTE. Since 3.32.5 such a table switches the reader to Pandoc's Markdown, and the tables are read (and skipped, if they cannot be CSV) like any other. The gfm test now asks for `--from gfm+fenced_divs` explicitly, and a new test pins the switch (no NOTE, the two `SKIP` lines).
27
+ - `test_cellalign`: Pandoc's Typst writer gives a cell its own alignment (`table.cell(align: ...)`) only from 3.1.13, so the Typst half of the test is its own test and is skipped on older Pandoc (`needs_pandoc(3, 1, 13)`); the HTML half runs everywhere.
28
+ - `test_md_macro`: Pandoc before 3.1.7 wraps a heading as `\texorpdfstring{Head with\n\emph{em}}{...}`; the test looks for `Head with` followed by white space and `\emph{em}`, which both forms satisfy.
29
+
30
+ ## v3.32.12b — 2026-11-03
31
+
32
+ Tests and lint only; `PDFMD_VERSION` stays 3.32.12. The first CI run of the pushed 3.31.47-3.32.12 commits (run 41540900210) failed in the `native` jobs (no Pandoc), the Windows `which` test and `lint`:
33
+
34
+ - The end-to-end ranking tests (`test_ranking_bare`, `_layers`, `_lists`, `_generated`) run `pdfmd --stop-at markdown`, which still needs Pandoc: they are skipped where there is none (the `native` jobs). `--which`, the watch pin and the engine tests need none and still run there.
35
+ - `test_ranking_which` compared `.pdfmd/ranking.yaml` where Windows prints `.pdfmd\ranking.yaml`: it builds the path with `Path`.
36
+ - `ruff --select F` (the `lint` job): three unused imports from the kits commits (`io` and `dataclasses.field` in `pdfmd_kits/install.py`, `Source` in `tests/test_kit_install.py`) removed.
37
+
38
+ ## v3.32.12 — 2026-11-03
39
+
40
+ Pre-edit state: commit `1bb68be`. Entry 3eu (the author: "isn't which already taken? if not, let's use it. whatever. it can just become multi-purpose if needed at some point in future"). Kept in 3.32. Not pushed. Last of the four commits of the line.
41
+
42
+ `pdfmd --which` explains a choice and builds nothing.
43
+
44
+ - **`pdfmd --which`** in a folder: `WHICH bare pdfmd in . builds report.final.md`, one row per Markdown file (what it says: its `priority`, its name's suffix; what happened to it: `BUILT`, `left: name: draft`, `left: priority: never`, `left: older`, `tied`; when it last changed), then `RULES`: the files the settings came from (nearest first, ending in the built-in default), `names`, `by`, and the classes low to high (`pdfmd_ranking.Ranking.describe()`). The tie WARN is printed as in a build; a choice that would stop says so (`would stop: ...`, exit 1). `--newest`, `--all` and `--no-auto priority` act in it as they do in a build.
45
+ - **`pdfmd --which NAME ...`**: which file each name finds, by the same lookup a build uses (`report -> report.md`), and the lookup's own error for one it cannot find. Meant to grow: the author wants `--which` to be the one place that says what pdfmd would decide.
46
+ - `--which` is a command in `pdfmd_setup/inventory.py` and in the `modes` topic of `--help`. Tests: `tests/test_ranking_which.py` (rows, rules and their origin, a tie, a stop, `--newest` / `--all`, one file, names, a mistake in the ranking). README, module docstring.
47
+
48
+ ## v3.32.11 — 2026-11-03
49
+
50
+ Pre-edit state: commit `fada070`. Entry 3eu (the author: "yes, but there should be a new key like `-b all` or smth that will override never keys" and "pdfmd --newest will look at the modification time and render the newest thing"). Kept in 3.32. Not pushed. Third of four commits of the line.
51
+
52
+ `never` leaves the folder lists, and two flags.
53
+
54
+ - **`priority: never` (or another word of a class with `exclude`, or a negative number) in `-b`, `-r` and the viewer**: the document is left out of what a folder gives, with one `NOTE` naming what was left out. `draft` and the numbers do not matter there (they only choose one document). A document named on the command line (`pdfmd NAME`, `-r a.md b.md`) is always built. `--no-auto priority` switches the leaving-out off with the rest.
55
+ - **`--all`** (alias `--include-never`; `-b all` could not be the spelling: `-b` takes paths and would read `all` as a file): the `never` documents count again. `-b`, `-r` and `--view` include them; a bare `pdfmd` ranks them as if they had written nothing.
56
+ - **`--newest`**: a bare `pdfmd` (or `pdfmd '#section'`) builds the most recently changed file of the folder, by modification time alone (priority and names are not consulted; `never` documents stay out unless `--all`), with no tie warning: it was asked for. It is honoured even with `--no-auto priority`. With a named file, `-b` or `-r` it does nothing, and says so (a WARN). The default `ranking: {by: [priority, newest]}` uses the time only for documents of equal priority.
57
+ - A `never` in a file name (`report_ignore.md` beside `report.md`) hides it from a bare `pdfmd` only; the lists look at the `priority:` key (reading every name of a big `-b -r` tree for it was not worth it).
58
+ - Both flags are `RUN` entries of `pdfmd_setup/inventory.py`. Tests: `tests/test_ranking_lists.py`. README (*Several documents in a folder*, *A whole folder*), module docstring, `--help`.
59
+
60
+ ## v3.32.10 — 2026-11-03
61
+
62
+ Pre-edit state: commit `5702fb0`. Entry 3eu UPDATE 2 (the author: "let's make it possible to define ranking.yaml somewhere globally ... living in .pdfmd per directory or in parent directory's .pdfmd" and "all depend on proximity to the file itself"). Kept in 3.32. Not pushed. Second of four commits of the line.
63
+
64
+ The words of `priority`, and their order, are settings.
65
+
66
+ - **`ranking`**: classes of words on a ladder (`classes: {fruit: {words: [cherry, banana], above: numbers}}`: banana beats cherry, every fruit beats every number, `final` still beats them all), `ladder:` (a nested list is one level), `names: family | folder | off` (whether an inferred `final` beats an unrelated document: the author's "let's make it adjustable"), `by:` (what settles equal priority: `newest`, `oldest`, `name`; `[priority]` makes a tie the error of 3.32.9 again, `[newest]` ignores priority). A class takes `ordered: false`, `degrees`, `exclude`, `names: false`, `above:` / `below:`; a word may hold `{n}`. YAML's `names: off` (read as `false`) works, and `by` may be a comma list (`priority, oldest`), which is what the setup row stores.
67
+ - **Where it is read, nearest first**: the documents' own `pdfmd-options: {ranking: ...}` and a metadata file named after one (classes and ladder only; `by`, `names` and `inherit` are the folder's: a WARN), then folder by folder from theirs upward `.pdfmd/ranking.yaml` > the folder's `metadata.yaml` > the folder settings' `options.ranking`, then the global `ranking.yaml` (beside the config file) and the config's `options.ranking`. `inherit: false` stops the climb. A nearer `ladder`/`names`/`by` replaces a farther one, classes merge by name. Nothing is read, or parsed, until bare `pdfmd` has several documents to choose from, so a broken file never spoils another build.
68
+ - **Two documents that define a class (or the ladder) differently**: a WARN naming both; the newer one's is used. **Mistakes** (a word in two classes, an unknown class on the ladder, a bad `above:`) stop the choice with the file that defined it; a class on no ladder is a WARN and its words are ignored.
69
+ - **`--setup`**: two rows, *Equal priority, when bare pdfmd must choose a document* and *Names that rank versions of a document*, also in a folder's setup; `pdfmd_setup/inventory.py` lists `ranking.by` and `ranking.names` as rows and `ranking.ladder` / `ranking.classes` as left out on purpose (a file's lists). The tie WARN and error now name the `by` setting.
70
+ - Tests: `tests/test_ranking_layers.py` (through pdfmd itself: every place, the order of the places, `inherit`, documents, strict ties, `names`, a custom ladder, mistakes, nothing read for one file), more in `tests/test_ranking_rules.py`. README (*Several documents in a folder*: the settings), module docstring.
71
+
72
+ ## v3.32.9 — 2026-11-03
73
+
74
+ Pre-edit state: commit `8c8293c`. Entry 3eu (the author's idea of 2026-11-03: "a small pdfmd-option called ignore or whatever that will exclude a document from autodiscovery ... actually, let's make it `priority` with different tiers"). Kept in 3.32. Not pushed. First of four commits of the line: the choice and the `priority` key (next: custom classes and the `ranking` settings, `--newest` and `--all`, `--which`).
75
+
76
+ Bare `pdfmd` in a folder with several Markdown files chooses one instead of stopping with the list.
77
+
78
+ - **`priority:`** at the root of a document's front matter or in its `pdfmd-options` (the second wins, with a WARN when both are set and differ). A number (higher wins, floats too), `final` / `last` / `max` (above every number; degrees of lastness: `final final`, `FINAL FINAL!!!`, `final2` and `final67` each beat the one before), `draft` or `0` (loses to every other document, builds when alone), `never` / `ignore` / `skip` / `exclude` or a negative number (not in the list), and nothing at all (`none`, `null`, `nil`, `nill`, `~`, blank: normal, between `draft` and `1`). A value that is neither a number nor a word is a WARN and counts as unset.
79
+ - **Names**: `report.final.md`, `report.rewritten.md`, `report_v3.md` beat `report.md`; `report_draft.md`, `report.old.md` lose to it. They act only inside a family (a base name plus trailing known words, compared ignoring case and separators), so `report_draft.md` beside an unrelated `notes.md` is just another document and `lab2.md` is never a version of `lab.md`; `final_draft` counts as final. A `priority` written in any member of a family switches the names off for it.
80
+ - **Equal tops**: the newest file (modification time) is built, with a WARN that names them all; identical times stop the run with the list and what raised each. The `AUTO MD` line now says what the chosen document beat and why (`over report.md [name: bare name], notes.md [priority: draft]`).
81
+ - **Unchanged**: one Markdown file in the folder; an exact name (`pdfmd report`, still the override); `-b`, `-r` and the viewer. **New kind** `--no-auto priority` brings the old "Multiple Markdown files found" list back.
82
+ - **The rules are pure and in their own package**, `pdfmd_ranking` (words and classes in `rules.py`, the choice in `choose.py`), written as a ladder of word classes from the start: the built-in behaviour is its default setting (`DEFAULT_RANKING`), so the customisation of the next commits adds layers, not new logic.
83
+ - `priority` is a document-only `pdfmd-options` key (`pdfmd_setup/inventory.py`: Omitted, "document"); the `--no-auto` kind has its `--setup` text.
84
+ - **Fixed before the release** (this line is not on PyPI yet; the fixes are one commit after `c19582d`, so they go into the entry of the version that had the bugs, as the versioning rule says): (1) pdfmd's own Markdown output (`X.assembled.md`, `X.gfm.md`, `X.ascii.md`, `X.ascii.gfm.md` beside `X.md`, any assembled file, hidden files such as the temporary `.name.pdfmd-*.md`) was a candidate, so "the newest wins" would have built the last build's output on the next run: `source_markdown()` leaves them out (`--which` names them in a NOTE); (2) `pdfmd -w` re-ran the original command line, so a bare `pdfmd -w` chose again at every rebuild: `pinned_watch_argv()` puts the chosen document in the re-run (and drops `--newest`); (3) `no-auto: [priority]` / `auto: {priority: off}` from a folder or the config file did nothing, only `--no-auto priority` worked: `priority_enabled(folder)` reads the same layers as `effective_no_auto()` (command line, folders, config) for the folder; the module-global `PRIORITY_PICK` is gone, `NO_AUTO_CLI` takes its place and reaches `-j` workers (`tests/test_jobs.py` caught the first). Tests: `tests/test_ranking_generated.py`.
85
+ - Tests: `tests/test_ranking_rules.py` (the engine alone: values, names, classes, ladders, errors, the choice) and `tests/test_ranking_bare.py` (through pdfmd itself, `--stop-at markdown`). README section *Several documents in a folder*, the module docstring and the `--no-auto` help.
86
+
87
+ ## v3.32.8 — 2026-11-03
88
+
89
+ Pre-edit state: commit `1d992bd`. `[kits]`, entry 3et UPDATE 2 (the author: "let's do it. no-auto geometry"). Kept in 3.32. Not pushed.
90
+
91
+ A kit can take pdfmd's own margin, font and table-width defaults over with `no-auto:` in its `.kit` file.
92
+
93
+ - **The key**: `no-auto: [margin]` (a word or a list of `margin`, `mainfont`, `monofont`, `mathfont`, `font`, `tablewidth`). Before, a class kit had to write `geometry: " "` into its metadata to stop the automatic `geometry:margin=...` from clashing with the class's own page; now the kit says what it means, and the metadata can stay about the document.
94
+ - **Where it ranks**: under the command line, the document and the folders' files, over the config file (the same place a kit's metadata has). So a document can turn the default back on with `pdfmd-options: {auto: {margin: on}}`, and `--no-auto` and `-y` still mean what they meant. Applied to a single document and to a report or book (`-r`).
95
+ - **What a kit cannot name**: a kit is chosen from the layers and from the files pdfmd found, so it cannot switch off the finding of metadata, Lua filters, preambles or kits themselves; those kinds, and `true` for everything, are a WARN naming the kind and are ignored.
96
+ - **Not before**: an older pdfmd reads the key as an unknown one (a WARN) and goes on, so a kit that has it still builds there.
97
+ - The kits' own `active_kits` cache is keyed on the two `--no-auto` kinds that decide the kit search (`kit`, `kpsewhich`) instead of the whole list, so one run makes one choice of kits, and prints a kit's warnings once, whatever else is switched off.
98
+ - `pdfmd --kits NAME` shows the kit's `no-auto`. The module docstring now has a short Kits paragraph (it had none), the README's Kits section the key and its ranking.
99
+ - Tests: `tests/test_kit_no_auto.py`, through pdfmd itself (a real build with a kit that has no `geometry:`).
100
+
101
+ ## v3.32.7 — 2026-11-03
102
+
103
+ Pre-edit state: commit `d14c00a`. `[kits]`, entry 3et UPDATE 1 (the author: "make it possible for `pdfmd --install kit` to fetch an arbitrary git repo ... it'll look at all folders of it so nulabreport, which has `.kit` at root, and this one, pdfmd-kits, which has kits in child dirs, would work"). Kept in 3.32. Not pushed.
104
+
105
+ `pdfmd --install kit:SOURCE` installs the kits of any repository.
106
+
107
+ - **Sources**: `owner/repo` (GitHub, its default branch; the tarball over https, no git needed), `owner/repo@REF` (a tag, branch or commit), `#NAME` after either picks one kit, any git URL (https, ssh, scp-like; `git clone --depth 1` with only the https, ssh and file transports, `ext::` refused), `file:///path` (a local git repository, committed state), `./x` `~/x` `/x` (a folder, copied as it is), and a bare `NAME` (a kit of that name in the repositories of `kit-sources`). Plain `http://` and `git://` are refused. `pdfmd --install kit` alone lists the installed kits; `pdfmd --uninstall kit:NAME` removes one.
108
+ - **What it finds**: a folder with `.kit` or `NAME.kit` is a kit; the repository root first, then every folder below it down to `kit-search-depth` (3) levels, hidden folders skipped, and a kit's own sub-folders are the kit's, never searched. So a repository that is one kit (the root shape of a package like nulabreport) and one with a kit per folder (a collection) both work. Each kit is checked with the kit loader; a faulty one is skipped with a WARN and the rest installed.
109
+ - **Where it goes**: `kits/NAME/` beside the config file (kit discovery already reads it), the whole kit folder, with `.pdfmd-install.json` (source, ref, commit, SHA-256 of the archive, path in the repository, date). `pdfmd --kits` shows where an installed kit came from. Installing again updates it (a staged copy, then a swap); a folder there that pdfmd did not install is never replaced; a kit of another source needs `--yes`.
110
+ - **Safe by construction**: nothing of the repository is run (no script, no hook, no kit Lua filter). The archive is read as data: a name that leaves the folder stops the install, links, devices and fifos are dropped, and the files and bytes are capped by `kit-install-max-files` (5000) and `kit-install-max-mb` (200). The install lists the kits that carry a Lua filter and says to read it: pdfmd runs it when a document selects the kit.
111
+ - **Settings** (`options:` of the config file, read at install time, no `--setup` row; the inventory lists them as omitted): `kit-search-depth`, `kit-install-max-mb`, `kit-install-max-files`, `kit-sources` (the repositories a bare name is looked for in).
112
+ - New module `pdfmd_kits/install.py` (pure; the downloader is handed in), `install_kits()` and `uninstall_kit()` in `pdfmd.py`, `kit` in `INSTALL_KINDS`.
113
+ - Tests: `tests/test_kit_install.py` (the forms of a source, both repository shapes, depth and `#NAME`, a faulty kit, the commit from the tarball's folder, update and refusals, uninstall, hostile tarballs, caps, a folder with links, a real local git repository with a tag). Checked through pdfmd itself with a throw-away config: the author's kits repository (ten kits in child folders) and the real nulabreport repository (one kit at the root) were installed, listed, used for a build and uninstalled.
114
+ - README: "Getting a kit" in the Kits section; `--help` and `--install`'s error text name `kit:SOURCE`.
115
+
116
+ ## v3.32.6 — 2026-11-03
117
+
118
+ Pre-edit state: commit `f528e53`. `[kits]`, entry 3et (the author: "yes, follow pdfmd repo rules"). Kept in 3.32 as the author asked on 2026-11-02, though `CLAUDE.md` still names the kits line 3.31.x. Not pushed.
119
+
120
+ A kit's folders reach Tectonic.
121
+
122
+ - **The bug**: a kit puts its folder and its `carry:` folders on `TEXINPUTS`, which Tectonic does not read. With `-e tectonic` a kit that ships a LaTeX class (the apa7 kit of the kits repository, a class with its `config/` files) was never loaded: Tectonic built, without a word, with the copy of that class in its own bundle, or failed when its bundle had none. Found with a copy of the class that stops when it is loaded: xelatex stopped, Tectonic built.
123
+ - **The fix**: for the engine `tectonic`, each chosen kit's folder and every folder under the `carry:` entries that are folders go to Tectonic as `-Zsearch-path=DIR` (`tectonic_search_folders()`; the option names one folder, not a tree, so a carried tree is listed folder by folder, hidden folders left out). The Pandoc route passes them as `--pdf-engine-opt=-Zsearch-path=DIR`; the direct route (`.tex` files, drawn fragments) gets them through the environment `tex_search_env()` already builds (`PDFMD_TECTONIC_SEARCH`) and `latex_engine_command()`. Other engines and a document with no kit are unchanged. Needs a Tectonic that has `-Z search-path` (0.17 has it).
124
+ - Checked through pdfmd itself: the marker copy now stops under `-e tectonic` and the real apa7 kit builds; xelatex and lualatex were never affected.
125
+ - Tests: `tests/test_kit_texinputs.py` (the folders one by one, no hidden folder, no walk of the kit's whole folder, nothing without a kit, the command line of the direct route for Tectonic only).
126
+ - README: the paragraph "A kit needs no install" says it. No new setting.
127
+
128
+ ## v3.32.5 — 2026-11-02
129
+
130
+ Pre-edit state: commit `b5cd684`. Entry 3eo, step 2a of the Obsidian flavour line (the author: "any Pandoc or whatever detected syntax switches the reader, unless those are like examples in fenced code blocks"). Not pushed.
131
+
132
+ - **No more "gfm leaves X as text" NOTE: pdfmd acts on what it finds.** A file with no front matter was read as gfm and, when it used `H~2~O`, `x^2^`, `{#id}` attributes, raw LaTeX or `:::` divs, a NOTE said gfm printed them as text. Now a table of detectors (`READER_NEEDS`, `reader_needs()`) decides, and each syntax needs one of two things: an extension Pandoc accepts on gfm, which is added to the reader (`gfm+subscript`, `+superscript`, `+attributes+bracketed_spans`, `+fenced_divs`, `+definition_lists`, `+fancy_lists`, `+raw_attribute`; the definition-list and `.csv` div cases were added on need before), or Pandoc's own Markdown reader, which the file is switched to (`^[inline footnotes]`, raw LaTeX, grid tables, simple tables, `(@)` example lists, as `@citations`, Org captions and `\md{}` already did). `--verbose` says which syntax decided: `reading as gfm+subscript (it uses subscripts (H~2~O))`, or `it uses raw LaTeX (...), which gfm cannot read; keeping the default markdown reader`.
133
+ - **Only prose is looked at**: fenced code, inline code, math (`$..$`, `$$..$$`; `$5 or $10` is not math) and HTML comments are taken out first, so an example of the syntax in a code block changes nothing. The line that opens a fence is the one exception (a fence with attributes, ```` ```{.smiles} ````, needs `+attributes`). Lettered and Roman-numeral lists count only as two items in a row (`a.` `b.`, `(i)` `(ii)`): `I. Introduction` alone stays text, as in GFM. Not looked for: indented code blocks, line blocks, multiline tables, inline `^x^` inside words (listed in the notes).
134
+ - **Cost, accepted by the author**: Pandoc's Markdown reader sizes pipe-table columns differently from gfm (the reason gfm was chosen); a file with raw LaTeX or an inline footnote and no front matter now gets that reader, so its tables size as they do in a file with front matter.
135
+ - Removed with it: `reader_notice()`, `gfm_blind_spots()`, `GFM_BLIND_SPOTS`, `FENCE_ATTRIBUTES`, `has_definition_list()` (the table replaces them); the NOTE is gone from the output.
136
+ - Tests: `tests/test_reader.py`: the old blind-spot tests became `ReaderNeeds` (the extension each syntax needs, what only Pandoc's reader reads, code and math and comments not counting, a fence's attributes, lettered lists) and the command-line tests (nothing said but under `-v`, the extension added and `<sub>` in the output, a switch to Pandoc's reader for an inline footnote and for raw LaTeX, the same syntax in a code block changes nothing). Checked through the whole `pdfmd` on the three notes of the Obsidian test vault (all read as plain gfm, nothing to add) and on small files.
137
+ - README: the "It decides per document" paragraph and the `READER` row say what is added and what switches.
138
+
139
+ ## v3.32.4 — 2026-11-02
140
+
141
+ Pre-edit state: commit `834e135`. Entry 3eo, step 1 of the Obsidian flavour line: the gfm-or-Pandoc choice made reliable. Not pushed on its own (see the last bullet).
142
+
143
+ - **The global metadata no longer decides the reader.** The file `pdfmd --setup` writes (`metadata.yaml` beside the config, and the presets) was counted as "a linked metadata file", so on a machine that has one every file with no front matter was read as Pandoc's Markdown and the gfm rule never fired: the same file read differently on another machine (found with the author's own notes: `AUTO READER ... metadata.yaml is linked; keeping the default markdown reader instead of gfm` for a file that had none). Now only a metadata file of the document (beside it, `-y`, a folder's) counts. Everything the global file sets still applies: Pandoc reads a metadata file's strings with its own Markdown whatever the reader (measured with Pandoc 3.13: `title`, a `header-includes` macro and `H~2~O` in an `abstract` come out the same under `-f gfm` and `-f markdown`), a global `pdfmd-options: {reader: markdown}` still wins, and `promote_bare_title()` is unchanged (pinned by a test).
144
+ - **`has_yaml_frontmatter()` says what Pandoc says.** It was "the first line is `---`", so a file that opens with a thematic break (`---`, a blank line, text) counted as having front matter and was read as Pandoc's Markdown. Now: blank lines may come first, then `---` and a line that is not blank, and a later `---` or `...` closes it; `---` straight after `---` is an empty block and still counts (the documented way to ask for Pandoc's reader); a BOM and CRLF are fine. Measured against `pandoc -f markdown -t json` for 14 shapes. About twenty other places in `pdfmd.py` read a front-matter block with their own regex (`papersize`, margins, `pdfmd-options` ...); they all require a closing line, so they differ from this only for a file that opens with a rule and has another rule later. Left as they are, listed in the notes.
145
+ - Tests: `tests/test_reader.py` (+8): the truth table both ways, and through the whole `pdfmd` with a config and a global `metadata.yaml` (gfm is chosen and the NOTE is printed; the global title, a raw-LaTeX `header-includes` and Markdown in a metadata string still arrive; a global `reader:` still wins; a `metadata.yaml` beside the document still means Pandoc's Markdown; a leading rule is not front matter; a bare `# Title` is left alone). Run with the modules that use a global file (`test_presets`, `test_setup_folder`, `test_standalone_source`, `test_path_display`, `test_mathfont`, `test_config`, `test_typst_input`, `test_setup`).
146
+ - README: "It decides per document" and the `READER` row say what counts.
147
+ - **Behaviour change to know about:** on a machine with a global metadata file, a file with no front matter that uses `H~2~O` or `x^2^` now prints the existing NOTE and shows them as text, instead of silently rendering them as Pandoc does (a file with `@citation` syntax or a `metadata.yaml` beside it still keeps Pandoc's reader). A document with front matter (every `nulabreport` report has some) is untouched. Step 2 of the line (the `pdfmd` flavour) adds subscripts, superscripts and the other Pandoc blocks to the gfm reader so the NOTE goes away; that is why this patch is not pushed alone.
148
+
149
+ ## v3.32.3 — 2026-11-02
150
+
151
+ Pre-edit state: commit `4613a5a`. Entry 3en, the second look at 3.32.1 and 3.32.2.
152
+
153
+ - `diagram-timeout` without a runner: a copy of pdfmd with no `pdfmd_lua/limited_run.py`, or a Python that does not know its own path (`sys.executable` empty), made every diagram fail with "does the source parse?". Now the filter is told nothing about a limit, the tools run as before, and pdfmd prints one NOTE saying the setting is not applied. (A wheel and the zipapp both carry the file: a wheel ships a package's `.py` files, the zipapp unpacks to real files.)
154
+ - `limited_run.py` waits at most 5 s after it has stopped a tool for the pipes to close (a grandchild in a session of its own can hold one open). It is a constant, not a setting: a safety stop in a helper that decides nothing about the output, and nothing a user would tune.
155
+ - `tests/test_slide_notes.py`: the header reaches the `.tex` of a deck (`--stop-at tex`, no LaTeX needed) with the deck's own `aspectratio=169` and `header-includes` macro still there (3 tests: the header and the deck's own settings, `off`, the setting in a `-y` metadata file). Also checked by hand: a `metadata.yaml` found beside the deck. `tests/test_diagram_timeout.py` (+3): the limit and runner reach the filter, `0` turns diagrams off, a negative number passes no limit, no interpreter means no limit and a NOTE.
156
+
157
+ ## v3.32.2 — 2026-11-02
158
+
159
+ Pre-edit state: commit `c9d0f0a`. Entry 3en (the author: "the setting --- yes, and document it" for a named slide-notes setting).
160
+
161
+ Speaker notes in a Beamer deck. A `::: notes` block was dropped by `pdfmd -p` (0 note lines in the PDF); Pandoc has the feature, Beamer's `show notes`, but it was reachable only through a variable and undocumented.
162
+
163
+ - `slide-notes: off | show | only` (`pdfmd-options` key, config key, `--setup` row "Speaker notes ..." under Output; default `off`, today's behaviour). `show`: a notes page after each slide. `only`: the notes pages alone, for printing. `true` and `on` mean `show`; a bad word stops the build and names the three, like `md-macro`.
164
+ - Written as a header file (`\setbeameroption{show notes}` / `{show only notes}`, cached by mode under the cache's `tex/`), added next to the other pdfmd headers for a `-p` build with a LaTeX engine, NOT as `-V classoption=notes=show`: measured on 3.32.0, that variable replaces the deck's own `classoption`, and a 16:9 deck (`aspectratio=169`, 454 x 255 pt) came out 4:3 (363 x 272 pt). With the header the size stays.
165
+ - Other builds (not `-p`, other writers, a non-LaTeX engine) ignore the setting without a message: a config-level `slide-notes: show` is meant for decks and would otherwise talk on every other document. Pandoc's own revealjs already shows notes.
166
+ - `slide_notes_mode()` and `slide_notes_args()`; `tests/test_slide_notes.py` (7 tests: the default, `show` / `only` / `true`, a bad word, a header only for a deck; and, when `lualatex` and poppler are installed, a 16:9 deck built three ways: 3 pages and no notes by default, 5 pages with `show`, 2 with `only`, the page size 454 x 255 pt each time). README: "Speaker notes" under Slides, with an example; `docs/recipes.md` 7.4 has a line. The `--help` text has no new flag.
167
+ - Not done: Beamer's `show notes on second screen=right` (notes beside the slide, for a presenter view), which would be a fourth value; the native tier and a Typst deck (pdfmd has none).
168
+
169
+ ## v3.32.1 — 2026-11-02
170
+
171
+ Pre-edit state: commit `c52dd09`. Entry 3en (the review of two research reports on Markdown-to-PDF pain points; the author: "diagram limit on at 120 s. the setting --- yes, and document it").
172
+
173
+ A diagram tool that never answered hung the build with no message: a stub `mmdc` that sleeps was still being waited for after 60 s. `pandoc.pipe`, which `pdfmd_lua/diagram.lua` ran the tools with, has no time limit.
174
+
175
+ - `diagram-timeout` (`pdfmd-options` key, config key, `--setup` row "Time limit of one diagram tool run" under Checks and limits): seconds one run of `mmdc`, `dot`, `d2`, or of the `rsvg-convert` / `inkscape` that converts their SVG, may take. Default 120, ON. `0`: no diagram is drawn (the fences stay as code, one WARN naming the setting; it overlaps `--no-auto diagrams`, kept so the value means what `soffice-timeout: 0` means). A negative number: no limit, and no runner.
176
+ - New `pdfmd_lua/limited_run.py`, started by the filter under the limit with the interpreter pdfmd runs on (so no `timeout` command is needed, which macOS and Windows lack): it passes standard input and output through as bytes (a picture written to standard output stays intact), leaves the tool's error output where it was, and when the time is up stops the tool with every process it started (a process group; `taskkill /T` on Windows), prints a marker and exits 124. 127 for a missing program.
177
+ - The filter: a stopped tool leaves its diagram as code with a WARN that says which program did not finish in how many seconds and names the setting (`--strict` makes it an error, like any undrawable diagram), and the tool is not tried again in the build, with one WARN for the first skipped fence: a browser that cannot start would otherwise cost the limit once per diagram. A stopped `dot` is not asked a second time for an SVG to convert. Nothing from a stopped run reaches the cache.
178
+ - Known cost, not fixed: the Word and OpenDocument route runs Pandoc twice, so there a hung tool costs the limit twice (each run remembers on its own).
179
+ - `diagram_timeout_from()` and `diagram_timeout_for()` (the document's key, its metadata files', the config's); the filter gets `pdfmd-diagram-timeout`, `-python` and `-runner`, or `pdfmd-diagram-off`, in the metadata map it already had.
180
+ - `tests/test_diagram_timeout.py` (6 tests: the value as seconds, a document's own limit, bytes through the runner, exit code and error output through the runner, a run stopped with its child, a missing program) and four in `tests/test_diagrams.py` (a hanging `dot` is stopped and the second fence does not start it again, nothing in the cache, `--strict` fails; a hung Graphviz is not asked for an SVG next; `0` runs nothing; `-1` lets a slow tool finish). Not tested on Windows: the runner uses `taskkill /T` and `shutil.which` for `mmdc.cmd`; the end-to-end tests there use shell-script stand-ins and are skipped, as the others in that file.
181
+ - README: "Diagram time limit" beside the LibreOffice one, and a sentence in the diagrams section. The `--help` text has no new flag.
182
+
183
+ ## v3.32.0 — 2026-11-02
184
+
185
+ Pre-edit state: commit `394e482`. Opens the `\md{}` feature line, entry 3dc (queued 2026-10-26; the author, 2026-11-02: "i guess it is a good time to create that \md{} feature we were thinking of").
186
+
187
+ Markdown inside raw LaTeX. Raw LaTeX in a Markdown file reaches LaTeX untouched, so `*emphasis*`, `$x^2$` or `[@key]` inside a `\textbf{...}`, a `\caption{...}` or a hand-written `tabular` stayed as typed.
188
+
189
+ - `\md{...}` (one line or several) and `\begin{md}...\end{md}` hold Markdown: new `pdfmd_lua/md_macro.lua` splits the raw TeX Pandoc hands over into [raw TeX, the argument read as Markdown, raw TeX] with `pandoc.read`. It is the first of pdfmd's Lua filters, before pandoc-crossref and `--citeproc`, so a citation, an `@fig:x` reference, math or a footnote in the argument belongs to the one document.
190
+ - Where: a raw inline (`\textbf{\md{x}}`, a paragraph, heading, list item, table cell, caption) for every writer; a raw block such as a whole `tabular` or `figure` as one Plain block for LaTeX, Beamer and ConTeXt (the other writers drop that raw block as before); `\begin{md}` as real blocks (paragraphs, lists, tables) for every writer, also inside another raw environment. Several paragraphs in an inline `\md{}` are joined with a line break.
191
+ - The argument's braces must balance; a backslash escapes the next character (`\{`, `\}`), `%` and `#` are Markdown, not a TeX comment or parameter. A `\md` followed by a letter (`\mdseries`) is another command. An unbalanced `\md{` is read by Pandoc as plain text; the filter says so once with a WARN. `\begin{md}` has no brace counting, which is the way to write a code span with a lone brace.
192
+ - `md-macro: on` (the default) | `off` in `pdfmd-options`, with a `--setup` row (Input). The filter is loaded only for a document that has a macro outside code; a document that defines `\md` itself (`\newcommand`, `\def`, `\newenvironment{md}`) keeps its own and gets one NOTE.
193
+ - `contains_citations()` asks Pandoc with the filter on, so `--citeproc` is added for a document whose only citations are inside `\md{}`. A file with no front matter that uses the macro is read with Pandoc's `markdown` reader, not `gfm` (no raw LaTeX there), with the usual notice.
194
+ - Not done: the native (no-Pandoc) tier, a `.tex` source compiled directly, and the identity `.sty` for `~/dev/tex` (so the same `.tex` compiles without pdfmd), which is a step in the other repository.
195
+ - `tests/test_md_macro.py` (14 tests: detection outside code and own definitions, a macro inside `\textbf`, in a heading / bare line / list / table cell, in a raw `tabular` for LaTeX and HTML, the environment for tex / html / typst / md and inside `center`, citations resolved and listed, no front matter, `off`, a bad word, an own definition, an unbalanced brace, `\mdseries`). README: "Markdown inside raw LaTeX".
196
+
197
+ ## v3.31.52 — 2026-11-02
198
+
199
+ Pre-edit state: commit `bd497d7`. Still under 3.31. `[tables]`, entry 3el (the author: "it shows that some features we've added are thin ... record it and add todo line to revise the full functionality ... and start with all those three").
200
+
201
+ Three things the author's own example showed missing: a caption above a table that needs no repair, the `#+` lines of Org, and a cell's own alignment.
202
+
203
+ - `#+CAPTION:` (any case) and `#+NAME: tbl:id` above ANY pipe table become its caption, one that needed no repair included (with or without outer bars: `1 | 2 | 3` and `:-|:-:|-:`). That table is otherwise not touched, and nothing is printed for it unless a `#+` line was dropped.
204
+ - `#+ATTR_*:` lines directly above an Org or rule-less table are consumed: `:align lcr` (letters l, c, r; `|` and other characters ignored) sets the alignment when no cookie row does; every other option is dropped with a WARN. Above a valid pipe table its separator row decides and `:align` is reported as not used. `#+TBLFM:` lines directly below are dropped with a WARN naming them (the cells hold the result; nothing is calculated).
205
+ - A cell that starts with `<l>`, `<c>` or `<r>` keeps that alignment: `pdfmd_lua/cellalign.lua` cuts the tag (and the space after it) off. HTML, Typst, Word and the rest use the cell's alignment; Pandoc's LaTeX writer ignores it, so LaTeX and Beamer get raw TeX, `\multicolumn{1}{c}{...}` in a column of natural width and `{\centering ...\par}` in a column with a width, which is why the filter goes in after the table-width filter (a new `cellalign_args()` after every `width_filter_args` call). The Markdown writers keep the text; a cell with more than one block is left alone. `pdfmd-options: cell-align: on|off` (default on, a `--setup` row), loaded only for a document that has such a cell.
206
+ - `tests/test_cellalign.py` (9 tests: detection, natural and wrapped LaTeX columns, Typst, HTML, `off`, a bad word, the Markdown writers, no filter without a tag, the author's example whole); `tests/test_table_ascii.py` (40 tests: captions above valid tables, ATTR and TBLFM, `#+` lines in code, others kept). README: the cell-alignment section and the Org bullet.
207
+ - Not done: the native tier; `#+TBLFM:` is never evaluated. TODO: a line to revise the thin features of this line (the pre-pass kinds, line breaks, table captions, `<c>` cells, Org extras) against unusual input during the documentation programme.
208
+
209
+ ## v3.31.51 — 2026-11-02
210
+
211
+ Pre-edit state: commit `70963c6`. Still under 3.31. `[tables]`, entry 3el (the author, asked whether Org's alignment cookies and `#+CAPTION:` would be useful: "let's do it").
212
+
213
+ An Org table keeps its alignment and its caption.
214
+
215
+ - A row of alignment cookies (`| <l> | <r> | <c> |`, with a width `<r10>`, or `<10>` alone) is dropped from the table and sets the separator row: `:----`, `----:`, `:---:`. Every separator cell has the same width when any column is aligned, because Pandoc's `markdown` reader takes unequal dashes for a choice of column widths. A width alone sets no alignment.
216
+ - `#+CAPTION: text` (also `#+CAPTION[short]:`; several lines are joined) directly above a repaired Org or rule-less table becomes a `: text` line below it; `#+NAME: tbl:id` adds `{#tbl:id}`. A plain `#+NAME:` is dropped (before Pandoc 3.8.2 a plain `{#id}` would show as words in the caption). Other `#+` lines (`#+ATTR_LATEX:`, `#+TBLFM:`) stay as written, and a `#+CAPTION:` that is not directly above such a table stays.
217
+ - A caption needs Pandoc's `markdown` reader (gfm has no table captions), so a file with no front matter that has a `#+CAPTION:` line is read with `markdown` instead of `gfm`, with the usual notice, unless `table-ascii` is `note` or `off`.
218
+ - `pdfmd_tables/ascii.py` (`org_caption`, `COOKIE`, `assemble(aligns=)`), `pdfmd.py` (`ORG_CAPTION_RE`, the reader choice), the `--setup` row text, README. Tests: `tests/test_table_ascii.py` (cookies, caption and name lines, a build with no front matter).
219
+
220
+ ## v3.31.50 — 2026-11-02
221
+
222
+ Pre-edit state: commit `fe19049`. Still under 3.31. `[tables]`, entry 3el (the author, after the explanation of Org-mode: "do the orgmode then").
223
+
224
+ Org-mode tables, and `|` lines with no separator row, are read as pipe tables, with the setting of 3.31.47 (`table-ascii`).
225
+
226
+ - Org: `| a | b |` lines with a rule `|---+---|` or `|-` (a lone `|---|` is a one-column pipe table's separator and stays). Pandoc's `markdown` reader reads the `+` rule, `gfm` and `commonmark_x` make a paragraph of it, so pdfmd rewrites it for both. The rows above the first rule are the header (several are joined like a wrapped header), later rules only group rows and are dropped, leading and trailing rules too; one line is one row (Org has no wrapped cells). A row with another number of cells than the header is fitted, with a WARN of its own.
227
+ - `|` lines with no separator row (an Org table without a rule, what some chat models write): Pandoc reads a paragraph (`gfm`) or a line block (`markdown`). Every line must start and end with an unescaped `|`, have two cells or more and the same number as the others, at least two lines, and none may be a separator row; the first row is the header. A real pipe table, a line block (`| roses`), a lone line and a table with a separator row are never touched.
228
+ - The table keeps its indent (a table inside a list item). `pdfmd_tables/ascii.py` (`org_table`, kinds `org` and `pipe`), the `--setup` row text, README (two more bullets). Tests: `tests/test_table_ascii.py` (header above the first rule, group rules, a ragged row, no separator row, an indent, real pipe tables and line blocks untouched, a build under both readers).
229
+ - Not done: Org's alignment-cookie rows and `#+CAPTION:` lines stay as written; the no-Pandoc native renderer does not do it.
230
+
231
+ ## v3.31.49 — 2026-11-02
232
+
233
+ Pre-edit state: commit `765ce9e`. Still under 3.31. `[tables]`, entry 3el (the author: "`<br>` ... `\par` destroys table, and `<br>` is ignored in latex route. let's do it"; "let's not limit it to `<br>` html only and make it interconvertable, like pagebreak syntax").
234
+
235
+ One line break for every writer.
236
+
237
+ - Pandoc reads `<br>` as raw HTML, which every writer but HTML drops: `one<br>two` printed `onetwo` in LaTeX, and a table cell, where a blank line or `\par` breaks the table, could not hold two lines. `pdfmd_lua/linebreak.lua` (new, in the manner of `pagebreak.lua`) reads `<br>`, `<br/>`, `<br />` (any case), a raw TeX `\newline`, `\linebreak`, `\linebreak[n]`, a raw Typst `#linebreak()`, a raw Word break run and a raw ConTeXt `\crlf`, and gives the target Pandoc's LineBreak (LaTeX `\\`, in a cell a box of lines; Typst `\`; Word a break run; HTML `<br />`).
238
+ - A spelling already in the target's own language stays as written; the Markdown writers keep everything, except pdfmd's flat Markdown (`--to gfm`, raw HTML off), where `<br>` would be dropped and becomes a hard break. A paragraph or cell of nothing but breaks is left alone (the `space` markup kind reads a lone `<br>`); a break at the very start or end of a run of text is dropped.
239
+ - Mirrors pagebreak, with another default (the author: "2. equivalent of auto ... everything else mirrors pagebreaks, with all and families"). Families: `html` (`<br>`, `<br/>`, `<br />`), `tex` (`\\newline`, `\\linebreak[n]`), `typst` (`#linebreak()`), `word` (a raw break run), `context` (`\\crlf`). `pdfmd-options: linebreak:` not set or `auto` carries every family inside table cells only; `true` / `all` every family everywhere; a list those families everywhere; `false` none. `--linebreak [KIND ...]` (bare: all, everywhere) and `--no-linebreak` for a run; a `--setup` row (a multi choice of the families, in Universal markup; unset is `auto`) and the inventory entries. pdfmd passes the families and where as `-M pdfmd-linebreak=html,tex` and `-M pdfmd-linebreak-where=cells|all`; the filter is added only for a document that has a spelling (`LINEBREAK_RE`). A word that is no family is said and ignored. Not done: the native (no-Pandoc) tier.
240
+ - README: "A line break inside a table cell". Tests: `tests/test_linebreak.py` (the default in cells, `true`, the target's own spelling, Typst and Word, families, `false` and the command line, a bad word, the Markdown writers, lone and trailing breaks).
241
+
242
+ ## v3.31.48 — 2026-11-02
243
+
244
+ Pre-edit state: commit `6253c34`. Still under 3.31. `[tables]`, entry 3el (the author: "yes, build all of it as 3.31.48").
245
+
246
+ More text tables are read as pipe tables, with the setting of 3.31.47 (`table-ascii`).
247
+
248
+ - Lazy ASCII forms: a border as short as `+-+` (no inner `+`), rows without outer bars (`1 | 2`), middle borders left out. The table must be bordered at both ends and have a line with two cells. With no border between the body lines, a line whose first cell is empty continues the row above and any other line starts a row; with a border between rows, the lines between two borders are one row, as before.
249
+ - Box-drawing tables (`┌─┬─┐ │ ├─┼─┤ └─┴─┘`, double, rounded and heavy): cells split on `│ ┃ ║`, a `|` inside a cell escaped; the first rule that contains `═` or `━` and is not the first or last is the header rule.
250
+ - psql output: the header line (no outer bars) above `----+----`, rows with as many bars, the `(N rows)` line dropped with the table.
251
+ - MySQL console output: a real grid table, no `=` rule, exactly three rules, a one-line header and two or more body lines, which Pandoc read as one joined row; each line is a row now. A body line with an empty first cell leaves the table alone, so a real grid table with a wrapped row is not touched; any other real grid table is never touched.
252
+ - The WARN names the form (`a box-drawing table was read as a pipe table (2 columns, 2 rows)`); the `--setup` row and the README section ("Text tables Pandoc cannot read") list the four spellings. Not done: the native tier, `<br>` in cells, org `|---+---|` and a pipe table without a separator row (queue items).
253
+ - Tests: `tests/test_table_ascii.py` (`Forms`, and a build for each of box, psql and lazy).
254
+
255
+ ## v3.31.47 — 2026-11-02
256
+
257
+ Pre-edit state: commit `4761d60`. Still under 3.31. `[tables]`, entry 3el (the author pasted a table that NotebookLM wrote; "just implement it now under 3.31").
258
+
259
+ An ASCII table with no `+` at its column boundaries is read as a pipe table.
260
+
261
+ - Chat models write a "plain-text table" with `+-----+` borders that have no inner `+`, no `+===+` under the header, and `|` bars that drift by a character. Pandoc read it as one column without a header (every line a cell, the text off the page), and `table_width.lua` had nothing to balance. `pdfmd_tables/ascii.py` (new) repairs it before Pandoc sees it: a row is split on `|` (the bars' positions are not trusted), the lines between two borders are one row (wrapped cell lines joined with a space), the first row is the header (every row above a `+===+` line, if there is one), and the result is a pipe table with equal columns, which pdfmd's own width filter balances as it does any other. Rows with another number of cells than the header are padded or cut, each with a WARN.
262
+ - A real grid table (an inner `+`), a grid table of one column (no line with two cells), and anything inside a fenced or indented code block, an HTML comment or the YAML front matter are left alone. A literal `|` in a cell must be written `\|`.
263
+ - The text is changed in memory: `prepared_title_source()` (the document and a section built alone) and `scaffold_inputs()` (every part; the new `transform` argument) hand Pandoc a temporary copy, the file is never touched. One `WARN table-ascii: FILE, line N: ...` for each table. Not done: the native (no-Pandoc) tier.
264
+ - `pdfmd-options: table-ascii: repair` (the default) | `note` (leave it, say so once for each table) | `off`; a `--setup` row (`pdfmd_setup/registry.py`) and its inventory entry. A word that is none of them stops the build. No number is a threshold.
265
+ - README: "A plain-text table from a chat model". Tests: `tests/test_table_ascii.py` (the function, then real builds: the default, `note`, `off`, a bad word, a real grid table, a part).
266
+
267
+ ## v3.31.46f — 2026-11-02
268
+
269
+ Pre-edit state: commit `f47c019`. No shipped code changes (a manifest, a script, a workflow and docs; none of it is in the PyPI package), so no version bump. Entry 3ej.
270
+
271
+ A Scoop bucket for Windows, in this repository.
272
+
273
+ - `bucket/pdfmd.json`: depends on Python, Pandoc and Typst (suggests Tectonic); its install script makes a virtual environment in the app folder and has pip install `pdfmd-cli==<version>` into it; `pdfmd.exe` is the shim. `scoop bucket add pdfmd https://github.com/aliperdehan/pdfmd`, then `scoop install pdfmd/pdfmd`.
274
+ - `scripts/bump_scoop.py` (shares the PyPI lookup with `bump_formula.py`): changes the manifest's `version` and nothing else; `tests/test_scoop_bucket.py` checks the manifest and the script.
275
+ - `.github/actions/scoop-test` installs Scoop on a Windows runner, installs pdfmd from the manifest, builds a document with Typst and uninstalls it. `scoop.yml` runs it by hand; the new `scoop` job of `publish.yml` points the manifest at the release, runs it, and commits the manifest to `main` as the bot, next to the Homebrew job (both pushes now pull and try again, since they can meet).
276
+ - README: the Scoop install in the install section.
277
+
278
+ ## v3.31.46e — 2026-11-02
279
+
280
+ Pre-edit state: commit `418ac50`. No shipped code changes (a Dockerfile, a workflow and docs; none of it is in the PyPI package), so no version bump. Entry 3ej, the author's wish: "let's try docker and scoop", with Tectonic and Typst instead of a full TeX Live and Calibre and LibreOffice optional.
281
+
282
+ A container image, `ghcr.io/aliperdehan/pdfmd`.
283
+
284
+ - `docker/Dockerfile`: one file, four variants by build argument. `latest` is Python, pdfmd from PyPI, Pandoc and Typst (`--install full`), Tectonic (`--install core:tex`), the default fonts, and one warm-up build so Tectonic's own files are in the image and a run needs no network (0.8 GB). `TEX=1` adds TeX Live's LuaTeX and XeTeX for documents that set `engine: lualatex`; `OFFICE=1` adds Calibre (`--install calibre`, with the Qt libraries it needs) and LibreOffice (3.4 GB); both are `full` (4.4 GB). The tools and caches are in `/opt/pdfmd`, open to every user, so `docker run --user` works. The default fonts come from a CTAN mirror that sometimes stalls, so the build gives that step a time limit and tries again.
285
+ - `docker/smoke.sh`: what CI runs on every image before it is pushed, as another user than root and with no network: the default engine, Typst, Tectonic (and lualatex for TeX Live); Word, EPUB and ODT output, Calibre and LibreOffice for the office variants. It caught a missing Qt library of Calibre in the first office image.
286
+ - `.github/workflows/docker.yml`: the four variants for amd64 and arm64 (on the native runners, no emulation), the smoke test, a push by digest and one multi-platform tag per variant (`latest`, `tex`, `office`, `full`, and `X.Y.Z[-variant]`). `publish.yml` calls it after the PyPI upload; run by hand from the Actions tab it builds and tests without pushing, or publishes the images of a release that is already on PyPI.
287
+ - README: the container in the install section. `CLAUDE.md`: the release also builds the images.
288
+
289
+ ## v3.31.46d — 2026-11-02
290
+
291
+ Pre-edit state: commit `50e7ed1`. No shipped code changes (a docs file only), so no version bump.
292
+
293
+ - `CLAUDE.md` (Releasing): after a release the `homebrew` job has committed the formula bump to `main`, so the local `main` must be pulled (`git pull --ff-only`) before the next push.
294
+
22
295
  ## v3.31.46c — 2026-11-02
23
296
 
24
297
  Pre-edit state: commit `119003b`. No shipped code changes (tests only), so no version bump. The first push of the 3.31.4x commits showed what the CI saw and the machine of the author did not.