pdfmd-cli 3.24.19__tar.gz → 3.26.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.
- {pdfmd_cli-3.24.19/pdfmd_cli.egg-info → pdfmd_cli-3.26.20}/PKG-INFO +564 -31
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/README.md +563 -30
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd.py +4053 -700
- pdfmd_cli-3.26.20/pdfmd_check/__init__.py +15 -0
- pdfmd_cli-3.26.20/pdfmd_check/lint.py +581 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20/pdfmd_cli.egg-info}/PKG-INFO +564 -31
- pdfmd_cli-3.26.20/pdfmd_cli.egg-info/SOURCES.txt +170 -0
- pdfmd_cli-3.26.20/pdfmd_cli.egg-info/top_level.txt +17 -0
- pdfmd_cli-3.26.20/pdfmd_direct/__init__.py +14 -0
- pdfmd_cli-3.26.20/pdfmd_direct/defaults.py +166 -0
- pdfmd_cli-3.26.20/pdfmd_direct/html.py +207 -0
- pdfmd_cli-3.26.20/pdfmd_direct/typst.py +34 -0
- pdfmd_cli-3.26.20/pdfmd_edit/__init__.py +284 -0
- pdfmd_cli-3.26.20/pdfmd_flat/__init__.py +81 -0
- pdfmd_cli-3.26.20/pdfmd_flat/asciify.py +315 -0
- pdfmd_cli-3.26.20/pdfmd_flat/keep.py +176 -0
- pdfmd_cli-3.26.20/pdfmd_help/__init__.py +182 -0
- pdfmd_cli-3.26.20/pdfmd_history/__init__.py +11 -0
- pdfmd_cli-3.26.20/pdfmd_history/git.py +86 -0
- pdfmd_cli-3.26.20/pdfmd_history/hst.py +133 -0
- pdfmd_cli-3.26.20/pdfmd_history/versions.py +99 -0
- pdfmd_cli-3.26.20/pdfmd_images/__init__.py +11 -0
- pdfmd_cli-3.26.20/pdfmd_images/remote.py +60 -0
- pdfmd_cli-3.26.20/pdfmd_images/scan.py +70 -0
- pdfmd_cli-3.26.20/pdfmd_images/svg.py +107 -0
- pdfmd_cli-3.26.20/pdfmd_labels/__init__.py +24 -0
- pdfmd_cli-3.26.20/pdfmd_labels/replay.py +73 -0
- pdfmd_cli-3.26.20/pdfmd_labels/scan.py +228 -0
- pdfmd_cli-3.26.20/pdfmd_lua/__init__.py +17 -0
- pdfmd_cli-3.26.20/pdfmd_lua/ascii.lua +135 -0
- pdfmd_cli-3.26.20/pdfmd_lua/code.lua +90 -0
- pdfmd_cli-3.26.20/pdfmd_lua/code_wrap.tex +15 -0
- pdfmd_cli-3.26.20/pdfmd_lua/csv_table.lua +443 -0
- pdfmd_cli-3.26.20/pdfmd_lua/diagram.lua +219 -0
- pdfmd_cli-3.26.20/pdfmd_lua/flat.lua +510 -0
- pdfmd_cli-3.26.20/pdfmd_lua/graphicx.tex +1 -0
- pdfmd_cli-3.26.20/pdfmd_lua/images.lua +68 -0
- pdfmd_cli-3.26.20/pdfmd_lua/pdf_images.lua +100 -0
- pdfmd_cli-3.26.20/pdfmd_lua/raw.lua +450 -0
- pdfmd_cli-3.26.20/pdfmd_lua/select.lua +92 -0
- pdfmd_cli-3.26.20/pdfmd_lua/table_width.lua +216 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_office/__init__.py +2 -2
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_office/docx_post.py +49 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_office/office.lua +84 -6
- pdfmd_cli-3.26.20/pdfmd_raw/__init__.py +92 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_setup/registry.py +28 -3
- pdfmd_cli-3.26.20/pdfmd_tables/__init__.py +8 -0
- pdfmd_cli-3.26.20/pdfmd_tables/convert.py +427 -0
- pdfmd_cli-3.26.20/pdfmd_tables/scan.py +382 -0
- pdfmd_cli-3.26.20/pdfmd_tables/verify.py +65 -0
- pdfmd_cli-3.26.20/pdfmd_templates/__init__.py +119 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/article/__name__.md +40 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/article/description.txt +1 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/article/next.txt +1 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/article/refs.bib +6 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/book/__name__.md +8 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/book/description.txt +1 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/book/next.txt +1 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/book/parts/10-introduction.md +4 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/book/parts/20-methods.md +7 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/book/parts/30-results.md +3 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/notes/__name__.md +25 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/notes/description.txt +1 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/notes/next.txt +1 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/report/__name__.md +32 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/report/data.csv +4 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/report/description.txt +1 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/report/next.txt +1 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/slides/__name__.md +20 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/slides/description.txt +1 -0
- pdfmd_cli-3.26.20/pdfmd_templates/data/slides/next.txt +1 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pyproject.toml +3 -1
- pdfmd_cli-3.26.20/tests/test_ascii.py +266 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_attach.py +28 -1
- pdfmd_cli-3.26.20/tests/test_budget.py +157 -0
- pdfmd_cli-3.26.20/tests/test_build_record.py +133 -0
- pdfmd_cli-3.26.20/tests/test_check.py +247 -0
- pdfmd_cli-3.26.20/tests/test_code_blocks.py +165 -0
- pdfmd_cli-3.26.20/tests/test_compat.py +124 -0
- pdfmd_cli-3.26.20/tests/test_csv_table.py +125 -0
- pdfmd_cli-3.26.20/tests/test_diagrams.py +303 -0
- pdfmd_cli-3.26.20/tests/test_direct.py +296 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_display_path.py +16 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_doctor.py +26 -2
- pdfmd_cli-3.26.20/tests/test_docx_tables.py +49 -0
- pdfmd_cli-3.26.20/tests/test_edit.py +129 -0
- pdfmd_cli-3.26.20/tests/test_embedding.py +209 -0
- pdfmd_cli-3.26.20/tests/test_flat.py +440 -0
- pdfmd_cli-3.26.20/tests/test_help.py +65 -0
- pdfmd_cli-3.26.20/tests/test_history.py +224 -0
- pdfmd_cli-3.26.20/tests/test_images.py +297 -0
- pdfmd_cli-3.26.20/tests/test_keep_source.py +212 -0
- pdfmd_cli-3.26.20/tests/test_labels.py +343 -0
- pdfmd_cli-3.26.20/tests/test_latex_errors.py +79 -0
- pdfmd_cli-3.26.20/tests/test_lua_trust.py +129 -0
- pdfmd_cli-3.26.20/tests/test_markdown_features.py +65 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_native.py +11 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_office_latex.py +77 -0
- pdfmd_cli-3.26.20/tests/test_raw.py +246 -0
- pdfmd_cli-3.26.20/tests/test_reader.py +73 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_sections.py +3 -3
- pdfmd_cli-3.26.20/tests/test_soffice_parts.py +81 -0
- pdfmd_cli-3.26.20/tests/test_table_widths.py +113 -0
- pdfmd_cli-3.26.20/tests/test_tables.py +532 -0
- pdfmd_cli-3.26.20/tests/test_templates.py +159 -0
- pdfmd_cli-3.26.20/tests/test_typst_input.py +80 -0
- pdfmd_cli-3.26.20/tests/test_versions.py +258 -0
- pdfmd_cli-3.24.19/pdfmd_cli.egg-info/SOURCES.txt +0 -81
- pdfmd_cli-3.24.19/pdfmd_cli.egg-info/top_level.txt +0 -5
- pdfmd_cli-3.24.19/tests/test_csv_table.py +0 -62
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/LICENSE +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_cli.egg-info/dependency_links.txt +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_cli.egg-info/entry_points.txt +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_cli.egg-info/requires.txt +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/LICENSE +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/VENDORED.md +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/__init__.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/_kerning_data.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/assets/fonts/DejaVuSans-LICENSE.txt +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/assets/fonts/DejaVuSans.ttf +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/ast.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/cidfont.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/embedded.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/embedded_metrics.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/emoji.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/emoji_font.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/fonts.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/html_filter.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/image_loader.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/layout.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/parser.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/pdf.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/py.typed +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/render.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/truetype.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_inkmd/url_filter.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_office/docx.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_office/fonts.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_office/fragments.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_office/labels.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_office/odt.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_office/spec.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_office/units.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_setup/__init__.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_setup/fancy.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_setup/plain.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_unicode/__init__.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_unicode/_catalog.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_unicode/_scripts.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_unicode/_tessdata_catalog.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_unicode/colorfont.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_unicode/emoji.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_unicode/fonts.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_unicode/install.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_unicode/plan.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_unicode/scripts.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_unicode/tessdata.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/pdfmd_unicode/translit.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/setup.cfg +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_api.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_apple_emoji.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_cache_location.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_completion.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_config.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_install_ocr.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_lookup.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_office.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_packaging.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_pdf_input.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_polish.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_setup.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_tessdata.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_text_input.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.20}/tests/test_translit.py +0 -0
- {pdfmd_cli-3.24.19 → pdfmd_cli-3.26.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.
|
|
3
|
+
Version: 3.26.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`
|
|
160
|
-
|
|
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.
|
|
227
|
+
OK batchocr 1.2.5
|
|
203
228
|
MISS tesseract: not found
|
|
204
229
|
MISS poppler: not found
|
|
205
230
|
|
|
@@ -208,6 +233,21 @@ MISS poppler: not found
|
|
|
208
233
|
brew install tesseract poppler
|
|
209
234
|
```
|
|
210
235
|
|
|
236
|
+
"Installed" is not "works": a LaTeX engine can be on the PATH and still fail on a missing package or font.
|
|
237
|
+
`pdfmd --doctor --deep` also builds a small page (maths, code, a table) with every engine it found, by running pdfmd
|
|
238
|
+
itself in a scratch folder, and says which one built it and how long that took, or why it could not:
|
|
239
|
+
|
|
240
|
+
```console
|
|
241
|
+
$ pdfmd --doctor --deep
|
|
242
|
+
...
|
|
243
|
+
Smoke test (a small page with maths, code and a table, built with each engine):
|
|
244
|
+
OK lualatex: built a PDF in 8.7 s
|
|
245
|
+
MISS xelatex: could not build it (! LaTeX Error: File `stix2.sty' not found.)
|
|
246
|
+
OK typst: built a PDF in 1.1 s
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
It takes a few seconds per engine (a minute or more if TeX has to fetch packages); without `--deep` nothing is built.
|
|
250
|
+
|
|
211
251
|
### Tab completion
|
|
212
252
|
|
|
213
253
|
`pdfmd --completion bash|zsh|fish` prints a completion script, generated from the command
|
|
@@ -219,6 +259,27 @@ pdfmd --completion bash > ~/.local/share/bash-completion/completions/pdfmd
|
|
|
219
259
|
pdfmd --completion fish > ~/.config/fish/completions/pdfmd.fish
|
|
220
260
|
```
|
|
221
261
|
|
|
262
|
+
### An older Pandoc, and a machine with no network
|
|
263
|
+
|
|
264
|
+
The oldest Pandoc `pdfmd` is tested with is **3.1.3** (what the claude.ai sandbox has); the whole test suite runs against
|
|
265
|
+
it. An older one may work, and the first build with it says so once; `pdfmd --doctor` lists what a given Pandoc does
|
|
266
|
+
without. With 3.1.3: Typst PDFs cannot show a picture `pdfmd` drew itself (before 3.2), a numbered equation in a Word file
|
|
267
|
+
sits in a plain table instead of a borderless one (before 3.4), and `--extract-tables` leaves a table whose caption has
|
|
268
|
+
a `{#tbl:id}` (before 3.8.2: Pandoc reads that as words, so the change could not be checked). A `pandoc-crossref` must be
|
|
269
|
+
the release built for the Pandoc you run; one built for another is not run, with a warning, because it would put `??` where
|
|
270
|
+
the numbers go.
|
|
271
|
+
|
|
272
|
+
Where `pip install pdfmd-cli` cannot reach the network (a sandbox with no DNS that only takes an upload), two ways:
|
|
273
|
+
|
|
274
|
+
```sh
|
|
275
|
+
python3 scripts/build_zipapp.py # on a machine with pdfmd's source: dist/pdfmd.pyz, 1.4 MB, PyYAML and pypdf inside
|
|
276
|
+
python3 pdfmd.pyz report.md # on the other: needs Python 3.9+, Pandoc and a PDF engine; unpacks itself once
|
|
277
|
+
# into ~/.cache/pdfmd/pyz/ because Pandoc has to open the Lua filters as files
|
|
278
|
+
|
|
279
|
+
pip download pdfmd-cli -d wheelhouse # or: a folder of wheels, carried over
|
|
280
|
+
pip install --no-index --find-links wheelhouse pdfmd-cli
|
|
281
|
+
```
|
|
282
|
+
|
|
222
283
|
### No Pandoc? The built-in fallback
|
|
223
284
|
|
|
224
285
|
On a machine with no Pandoc, or Pandoc but no PDF engine, `pdfmd` does not
|
|
@@ -322,6 +383,98 @@ letters, no tones, vowels left out where the script leaves them out. Names that
|
|
|
322
383
|
romanize alike (homophones) are listed as ambiguous, never picked between. The
|
|
323
384
|
same spelling rules find a section by its heading (`doc#tyche`).
|
|
324
385
|
|
|
386
|
+
### Check a document before you build it
|
|
387
|
+
|
|
388
|
+
```sh
|
|
389
|
+
pdfmd report --check # read report.md (a scaffold and its parts too) and list what is wrong; builds nothing
|
|
390
|
+
pdfmd a.md b.md --check # several files, one report each
|
|
391
|
+
pdfmd report --check --strict # warnings fail too (exit 1), for CI
|
|
392
|
+
pdfmd report --check --check-ignore heading-jump,link-missing
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
`--check` reads the source, with no Pandoc and no LaTeX, and prints compiler-style lines
|
|
396
|
+
(`report.md:12: error: image not found: figs/a.png [image-missing]`) that an editor can jump to, then
|
|
397
|
+
`CHECK report.md: 1 error(s), 2 warning(s)`. It exits 1 on an error, and on a warning too with `--strict`. It finds:
|
|
398
|
+
|
|
399
|
+
| check | |
|
|
400
|
+
|---|---|
|
|
401
|
+
| `image-missing`, `file-missing`, `link-missing` | an image (``, `<img>`, `\includegraphics`), a `file=` of a `.csv` div or a link to a local file that is not there |
|
|
402
|
+
| `anchor-missing` | `[x](#methods)` with no heading or `{#id}` of that name (the ids Pandoc and GitHub make from a heading count) |
|
|
403
|
+
| `id-duplicate`, `crossref-missing`, `ref-missing` | the same `{#id}` twice; a `@fig:x`, `@tbl:x`, `@eq:x`, `@sec:x`, `@lst:x` or `\ref{x}` nothing defines |
|
|
404
|
+
| `cite-missing`, `cite-no-bibliography`, `bibliography-missing` | a `@key` the `.bib`, CSL JSON or `references:` lacks (with a "did you mean"), citations with no bibliography set, a bibliography file that is missing |
|
|
405
|
+
| `footnote-missing`, `footnote-unused` | `[^1]` with no text, a `[^1]:` nobody uses |
|
|
406
|
+
| `heading-jump`, `heading-space`, `heading-empty` | `#` then `###`; `#Heading` (a paragraph); a heading with no text |
|
|
407
|
+
| `fence-open`, `comment-open`, `div-open`, `div-stray`, `math-open` | a code fence, `<!--`, `:::` div or `$$` that is never closed, or a stray `:::` |
|
|
408
|
+
| `front-matter`, `front-matter-duplicate` | YAML that does not parse (with its line) or never closes; a key set twice |
|
|
409
|
+
|
|
410
|
+
Code, comments, math and URLs are not read, so `@decorator` in a code block or `me@x.org` is not a citation. A
|
|
411
|
+
document in parts is checked as one: a link to `#methods` in the scaffold is found in a part. A file with no front
|
|
412
|
+
matter is taken for a fragment and its citations are not held against a missing bibliography, and neither are those of
|
|
413
|
+
a document with a Lua filter or `citation-engine` (something else may do the citing). A part checked on its own cannot
|
|
414
|
+
see the other parts' labels, so check the scaffold, not a part, to judge links across parts.
|
|
415
|
+
Leave a check out for the project with `pdfmd-options: {check-ignore: [heading-jump]}` (a document, a metadata file or
|
|
416
|
+
the config), or on one line with `<!-- pdfmd-check: ignore image-missing -->` on it or on the line above. `pdfmd --check`
|
|
417
|
+
is for Markdown; the build's own `WARN` and `--strict` still catch what only a build can see.
|
|
418
|
+
|
|
419
|
+
### A small editor
|
|
420
|
+
|
|
421
|
+
```sh
|
|
422
|
+
pdfmd --install tui # once: prompt_toolkit, about 1 MB
|
|
423
|
+
pdfmd --edit lecture # nano-like full screen; Ctrl-B saves and builds, Ctrl-P opens the PDF
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
`pdfmd --edit` (alpha) opens the Markdown file in a plain full-screen editor with the build one key away: Ctrl-S
|
|
427
|
+
saves, Ctrl-B saves and builds (what pdfmd said stays at the bottom), Ctrl-P opens the result, Ctrl-W / F3 find,
|
|
428
|
+
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
|
|
429
|
+
when there are unsaved changes); F1 lists them. Options given beside it (`pdfmd --edit lecture -e lualatex`) are used
|
|
430
|
+
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.
|
|
431
|
+
|
|
432
|
+
### In VS Code
|
|
433
|
+
|
|
434
|
+
`pdfmd --init-vscode` writes a `.vscode/tasks.json` here (build, build and open, watch, check, extract tables; Terminal > Run
|
|
435
|
+
Build Task). The [`vscode/`](https://github.com/aliperdehan/pdfmd/tree/main/vscode) folder of the repository is a small
|
|
436
|
+
extension over the same command line: build (`Cmd/Ctrl+Alt+B`), build and open, build as Word/HTML/Typst/slides, extract
|
|
437
|
+
tables (all, or chosen ones), file history, compare and restore, restore the source a PDF carries (right-click it). Every
|
|
438
|
+
command it runs is written to the *pdfmd* output panel. Install it with `npx @vscode/vsce package` and
|
|
439
|
+
`code --install-extension pdfmd-vscode-*.vsix`.
|
|
440
|
+
|
|
441
|
+
### A size budget for images and output
|
|
442
|
+
|
|
443
|
+
```sh
|
|
444
|
+
pdfmd report --max-asset-mb 5 --max-output-mb 20 # warn about an image over 5 MB and an output over 20 MB
|
|
445
|
+
pdfmd report --check --max-asset-mb 5 # list the images over 5 MB (asset-large), nothing is built
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
```yaml
|
|
449
|
+
pdfmd-options:
|
|
450
|
+
max-asset-mb: 5 # one image or data file
|
|
451
|
+
max-output-mb: 20 # the file that is made (a mail server's limit, a course site's upload limit)
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
There is no budget unless one is set. With one, a build says which image is over it before it starts
|
|
455
|
+
(`WARN report.md: figs/scan.png is 14.2 MB, over the 5 MB asset budget`) and, when the file made is over the output
|
|
456
|
+
budget, names it and the three largest images behind it. They are `WARN` lines, so `--strict` fails them. `--max-asset-mb 0`
|
|
457
|
+
switches a document's budget off for one run.
|
|
458
|
+
|
|
459
|
+
### Start from a template
|
|
460
|
+
|
|
461
|
+
```sh
|
|
462
|
+
pdfmd --init # the templates: article, report, notes, slides, book, and yours
|
|
463
|
+
pdfmd --init article my-paper # my-paper/my-paper.md + refs.bib, title, author and date filled in
|
|
464
|
+
pdfmd --init report . # into this folder, if none of its files exist yet
|
|
465
|
+
pdfmd --init notes week3 -V author="A. Author" -V title="Week 3"
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
Each template builds as it is (they are checked with `--check --strict` and built in the tests): an `article` with an
|
|
469
|
+
abstract, an equation, a table and a citation with its `.bib`; a `report` with a contents page, numbered sections and a
|
|
470
|
+
table read from a CSV file; `notes` (headings, math, a code block); `slides` (build with `-p`); and a `book`, a scaffold
|
|
471
|
+
with its chapters in `parts/`. The title comes from the name, the author from `-V author=` or `git config user.name`.
|
|
472
|
+
Nothing that exists is overwritten: pdfmd names the files in the way and writes nothing. Your own templates are a
|
|
473
|
+
folder (or a single `.md` file) in the `templates/` folder of pdfmd's config folder (`pdfmd --init` shows where), or any
|
|
474
|
+
folder or `.md` file named by its path. In their files and file names `{{name}}`, `{{title}}`, `{{author}}`, `{{date}}`
|
|
475
|
+
and `{{year}}` are replaced (`__name__.md` becomes `my-paper.md`); any other `{{...}}` stays as written. A
|
|
476
|
+
`description.txt` (one line, for the list) and a `next.txt` (what to type next) in a template folder are not copied.
|
|
477
|
+
|
|
325
478
|
### One section
|
|
326
479
|
|
|
327
480
|
`pdfmd doc#onlyapart` builds just the section whose heading is "Only a Part"
|
|
@@ -349,6 +502,113 @@ pdfmd lecture --to typst -o lecture.typ
|
|
|
349
502
|
pdfmd lecture -o lecture.tex # a complete, compilable .tex, not a fragment
|
|
350
503
|
```
|
|
351
504
|
|
|
505
|
+
### Plain Markdown: `--to gfm`
|
|
506
|
+
|
|
507
|
+
```sh
|
|
508
|
+
pdfmd report --to gfm # report.gfm.md, beside report.md, never over it
|
|
509
|
+
pdfmd report --to gfm -o README.md
|
|
510
|
+
pdfmd report --to gfm+raw # Pandoc's own gfm writer, with its HTML, as it was
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
`--to gfm` writes Markdown that any viewer shows as it is (GitHub, VS Code, Obsidian, a chat window): no HTML, no
|
|
514
|
+
`{#id .class}` braces, no Pandoc-only syntax. pdfmd runs everything it runs for any other target first (includes, parts,
|
|
515
|
+
`::: {.csv}` tables, pandoc-crossref, citations, your filters), then flattens what is left:
|
|
516
|
+
|
|
517
|
+
- the title block is written (`# Title`, an `*Author, Author — date*` line, the abstract), since the front matter is not;
|
|
518
|
+
- a table caption becomes `**Table 1.** text` above the table, a figure caption the same below the figure (the label
|
|
519
|
+
is split at the number pandoc-crossref wrote, in any language); `{#tbl:x}` and `{#fig:x}` are gone;
|
|
520
|
+
- `<div>`, `<span>`, `<figure>` and the bibliography's wrappers are unwrapped; section numbers (`number-sections`) are
|
|
521
|
+
written into the headings; a link to a heading points at the anchor GitHub gives it, a link to a vanished id is text;
|
|
522
|
+
- subscripts and superscripts are Unicode where every character has one (`H₂O`, `x²`, `CO₃²⁻`) and `_(..)` / `^(..)`
|
|
523
|
+
where not (`--gfm-scripts unicode`, the default; `html` keeps `<sub>`, `drop` writes the plain text, `ascii` always
|
|
524
|
+
writes `_2`, `^(q+z)`); math stays `$..$` and `$$..$$` (`--gfm-math fenced` writes ```` ```math ````);
|
|
525
|
+
- raw HTML and raw LaTeX are read into Markdown (`<b>x</b>` becomes `**x**`, `\textbf{x}` too); a raw Typst piece, a LaTeX
|
|
526
|
+
picture (`tikzpicture`, `\chemfig`, drawn with your preamble), a PDF image and an `<img src="x.pdf">` become SVG files in
|
|
527
|
+
`<name>_files/` beside the output, linked relatively;
|
|
528
|
+
- definition lists become a bold term and a paragraph; a table Markdown cannot hold (spans, several header rows, block
|
|
529
|
+
cells) is written as an HTML table, the one piece of HTML that stays, and counted in a `NOTE`;
|
|
530
|
+
- what no Markdown can carry (Word XML, a LaTeX macro nothing read) is left out, and a `WARN` counts it and shows the
|
|
531
|
+
first.
|
|
532
|
+
|
|
533
|
+
```yaml
|
|
534
|
+
pdfmd-options:
|
|
535
|
+
gfm: {scripts: unicode, math: dollars, title: true}
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
`-o notes.gfm.md` is `--to gfm` (it is also the name a flat file gets by default from `notes.md`); `-o notes.md` alone still means Pandoc's Markdown, so name the target (`--to gfm -o notes.md`) to get the flat one under that name. The paragraphs are single lines (`--wrap=none`; pass `--wrap=auto` to Pandoc to change it). Image links stay as the document wrote them, relative to the document's folder (a `NOTE` says so when the output is written elsewhere). The result is meant to be
|
|
539
|
+
final: what the flattening removes (ids, cross-reference numbers become text, citations become text) is not recoverable
|
|
540
|
+
from it.
|
|
541
|
+
|
|
542
|
+
#### The flat file that carries its source: `--keep-source`
|
|
543
|
+
|
|
544
|
+
Flattening cannot be undone (ids, cross-reference numbers, citations and scripts are text now). So a Markdown output
|
|
545
|
+
can end with its whole source in one HTML comment, the same set of files `--attach-source` puts into a PDF (the
|
|
546
|
+
assembled Markdown, a manifest of the layout, the `.csv` data), and `--restore` writes them back:
|
|
547
|
+
|
|
548
|
+
```sh
|
|
549
|
+
pdfmd report --to gfm --keep-source # report.gfm.md ends with the source, compressed (packed)
|
|
550
|
+
pdfmd report --to gfm --keep-source readable # the same, as escaped text you can read and diff
|
|
551
|
+
pdfmd --restore report.gfm.md --list # what it carries
|
|
552
|
+
pdfmd --restore report.gfm.md # writes report.gfm.restored/ (never overwrites anything)
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
```yaml
|
|
556
|
+
pdfmd-options:
|
|
557
|
+
keep-source: true # or readable; --no-keep-source turns it off for a run
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
Nothing in the source can close the comment early: `packed` is base64 of the compressed source (no `-`, `<` or `>`
|
|
561
|
+
in it), `readable` escapes every `>` (so no `-->` or `--!>`), a backslash, a carriage return and a line-initial `<` or `=`,
|
|
562
|
+
and undoes it exactly. A source with `<!-- a <!-- b --> c -->`, `-->` in a code block, CRLF line endings or the marker
|
|
563
|
+
itself comes back byte for byte. The comment also stores a hash of the Markdown above it, so `--restore` can tell
|
|
564
|
+
you the file was edited since. Comments are stripped from the kept copy unless `strip-comments` says otherwise (as for
|
|
565
|
+
`--attach-source`); a whole build keeps its source, a part or a section built alone does not; a kept source over 1 MB
|
|
566
|
+
gets a warning, since GitHub stops showing a Markdown file that large. It works for every Markdown output: `--to gfm`,
|
|
567
|
+
`gfm+raw`, `markdown`, `commonmark`.
|
|
568
|
+
|
|
569
|
+
### Plain text: `--to txt`
|
|
570
|
+
|
|
571
|
+
```sh
|
|
572
|
+
pdfmd report --to txt # report.txt; the same as -o report.txt
|
|
573
|
+
pdfmd report --to txt --columns=100 # Pandoc's wrapping, 72 columns unless you say otherwise
|
|
574
|
+
pdfmd report --to plain # Pandoc's own plain writer, as it was
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
`--to txt` is the flat build of `--to gfm` written by Pandoc's plain writer: includes, parts, `::: {.csv}` tables,
|
|
578
|
+
pandoc-crossref, citations, raw HTML and LaTeX and your filters all run first. What a text file shows: the title, the
|
|
579
|
+
author line and the abstract, then headings underlined with `=` (level 1) and `-` (level 2) and numbered when the
|
|
580
|
+
document numbers its sections; `Table 1. caption` above a table and `[Figure 1. caption]` for a figure; a link as
|
|
581
|
+
`words <https://address>` (just the words when they are the address, or the link points into the document); no `**` or
|
|
582
|
+
`_`; Unicode sub/superscripts (`H₂O`, `x²`, else `_(..)` / `^(..)`; `--gfm-scripts drop` or `ascii` change that, `html`
|
|
583
|
+
means `unicode` here); math as Pandoc's plain writer sets it (`E = mc²`). A picture cannot be shown: its caption stands
|
|
584
|
+
for it, and a Typst or LaTeX picture piece is left out with a `WARN`. `pdfmd-options: {txt: {scripts: unicode, title:
|
|
585
|
+
true}}` holds the settings. Until 3.26.7 `--to txt` and `-o x.txt` meant Pandoc's own plain writer; that is `--to plain`.
|
|
586
|
+
|
|
587
|
+
### ASCII only: `--to ascii`
|
|
588
|
+
|
|
589
|
+
```sh
|
|
590
|
+
pdfmd report --to ascii # report.ascii.txt: no byte above 127
|
|
591
|
+
pdfmd report --to ascii:gfm # report.ascii.gfm.md (also ascii:markdown, commonmark, rst, org, asciidoc, plain)
|
|
592
|
+
pdfmd report -o notes.ascii.txt # the name asks for it, as notes.gfm.md asks for --to gfm
|
|
593
|
+
pdfmd report -o notes.ascii.rst # any text ending after .ascii: .gfm.md, .md, .rst, .org, .adoc
|
|
594
|
+
pdfmd report --to ascii --ascii-missing escape # what has no ASCII form: \u65e5 instead of ?
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
For a terminal, an old mail gateway, a legacy system. The build is that of the format after the colon (`txt` when there
|
|
598
|
+
is none), with the words mapped to ASCII before the writer sees them, so the writer escapes what the new spelling needs:
|
|
599
|
+
a `−` at the start of a line that becomes `-` is written `\-`, not taken for a list; a table's columns are measured on the
|
|
600
|
+
ASCII text. What is mapped, in this order: punctuation and spaces (curly quotes, `—` as `--`, `…` as `...`, no-break
|
|
601
|
+
spaces, soft hyphens), symbols (`≤` `<=`, `±` `+/-`, `→` `->`, `°` `deg`, `½` `1/2`, `©` `(c)`), Greek letters by name
|
|
602
|
+
(`α` `alpha`, `Δ` `Delta`, `μm` `um`; a Greek word is spelt: `Σοφία` `Sophia`), Cyrillic with its case (`Привет`
|
|
603
|
+
`Privet`), accents (`é` `e`, `ß` `ss`, `ł` `l`), subscripts and superscripts (`H_2O`, `x^2`, `CO_3^(2-)`; `--gfm-scripts
|
|
604
|
+
drop` writes `H2O`), then the romanization packs for Hebrew, Arabic, Armenian, Georgian, Korean and Japanese kana, and
|
|
605
|
+
Chinese and the rest when `pypinyin` or `anyascii` is installed (`pdfmd --install translit`). Math stays TeX, with macros
|
|
606
|
+
(`$\alpha \geq 2$`); a link's address is percent-encoded (`%C3%A9`), not spelt. A character with no ASCII form is
|
|
607
|
+
counted and named in a `WARN`, and written as `?` (`--ascii-missing question`, the default), as `\uXXXX` (`escape`), as
|
|
608
|
+
nothing (`drop`), or the file is not written at all (`fail`); `pdfmd-options: {ascii: {missing: escape}}` sets it per
|
|
609
|
+
document. `--keep-source` on an ASCII file keeps the source packed (the readable form would be Unicode). It applies to text
|
|
610
|
+
formats only: `--to ascii:docx` is refused.
|
|
611
|
+
|
|
352
612
|
### Word and OpenDocument output
|
|
353
613
|
|
|
354
614
|
Plain Pandoc ignores `papersize`, `geometry`, `mainfont` and `fontsize` when it writes `.docx`
|
|
@@ -445,8 +705,9 @@ LaTeX. For `.docx` and `.odt` pdfmd adds a filter that makes it native where it
|
|
|
445
705
|
environment or macro behind each (`the tikzpicture environment`, `the macro \irspectrum`), without drawing or writing anything: a
|
|
446
706
|
quick way to see what is left to give a recipe (see the profile below).
|
|
447
707
|
|
|
448
|
-
`pdfmd-options: {office: {latex:
|
|
449
|
-
|
|
708
|
+
`pdfmd-options: {office: {latex: auto}}` is the default; `latex: images` draws everything LaTeX says as a picture
|
|
709
|
+
(formulas, `\ce` and units too, instead of making them native); `latex: off` or `--no-auto officelatex` skips all of it
|
|
710
|
+
(Pandoc's own behaviour). `office: {labels: off}` skips the PDF build (numbers are then counted).
|
|
450
711
|
|
|
451
712
|
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
713
|
keeps the page size, margins and fonts, shows equations and draws what LaTeX can; a **Typst or WeasyPrint run after LaTeX
|
|
@@ -570,12 +831,16 @@ style, a compound library, a shared bibliography and parts.
|
|
|
570
831
|
The TeX distribution's own packages, fonts and Pandoc are not carried.
|
|
571
832
|
- **Comments.** Notes to yourself do not travel: the attached source loses its
|
|
572
833
|
`<!-- -->` comments, the LaTeX preamble's `%` comments, the text between a
|
|
573
|
-
`.bib`'s entries
|
|
574
|
-
`strip-comments: [preamble, bibliography]` or
|
|
575
|
-
(`--strip-comments-in`, `--keep-comments-in`). Code
|
|
576
|
-
verbatim environments are never touched, and a
|
|
577
|
-
bare `%`, because it swallows the line break.
|
|
578
|
-
|
|
834
|
+
`.bib`'s entries, a CSL file's XML comments and the `#` comments of YAML
|
|
835
|
+
files. Choose per kind: `strip-comments: [preamble, bibliography]` or
|
|
836
|
+
`{markdown: false}` (`--strip-comments-in`, `--keep-comments-in`). Code
|
|
837
|
+
blocks, `\verb`, `\url` and verbatim environments are never touched, and a
|
|
838
|
+
`%` that closes a line keeps a bare `%`, because it swallows the line break.
|
|
839
|
+
With `strip-comments: false` (or `metadata` kept) the attached source gives
|
|
840
|
+
back your metadata files and the document's front matter byte for byte,
|
|
841
|
+
comments and quoting included; `--restore` of such a PDF is a full source
|
|
842
|
+
copy. The data files of `.csv` blocks (`tables/*.csv`) are always stored
|
|
843
|
+
with the source.
|
|
579
844
|
- **Only the bibliography entries you cite** are attached (and what they
|
|
580
845
|
cross-reference), not a shared file of hundreds; `attach-bibliography: all`
|
|
581
846
|
keeps it whole, and `nocite: '@*'` keeps every entry.
|
|
@@ -778,7 +1043,31 @@ The parts are joined in filename order into one Pandoc run, so the result is
|
|
|
778
1043
|
identical to the same text in a single file: labels, citations and numbering
|
|
779
1044
|
work across parts, and paths are written relative to the scaffold's folder
|
|
780
1045
|
whichever part they are in. A part rebuilt alone is much faster to compile
|
|
781
|
-
|
|
1046
|
+
and still shows the numbers of the others: before it is typeset, pdfmd has
|
|
1047
|
+
Pandoc write the LaTeX of the whole document once more (about a second, no
|
|
1048
|
+
images, no engine), reads which headings, captions, equations and labels it
|
|
1049
|
+
holds, and has LaTeX replay them at the start of the part. A reference to a
|
|
1050
|
+
section, figure, table or equation outside the part then prints its number
|
|
1051
|
+
(`Section 2`, `Equation (3)`, a `\cref` too), in the document's own number style
|
|
1052
|
+
(Roman sections, numbers per chapter), as a link that leads nowhere; the part's
|
|
1053
|
+
own sections, figures and equations continue from the parts before it. What the
|
|
1054
|
+
scan cannot count is whatever the document defines itself (a macro that opens
|
|
1055
|
+
a figure, say): that label stays `??`, and the build says the numbers are
|
|
1056
|
+
approximate. `\pageref` is always `??`. The last full build's `.aux` (cache on,
|
|
1057
|
+
below) is exact and is used first; the scan fills in what it does not know.
|
|
1058
|
+
`pdfmd-options: {seed-labels: auto|aux|scan|draft|off}` or `--seed-labels` picks
|
|
1059
|
+
the source (`draft` runs LaTeX once over the whole document without output, for
|
|
1060
|
+
exact numbers at about half a compile's cost); `off` brings back the `??`. A section of an ordinary document
|
|
1061
|
+
(`doc#results`) gets the same for the references it makes, but keeps numbering
|
|
1062
|
+
its own headings from 1.
|
|
1063
|
+
|
|
1064
|
+
For HTML, EPUB, Word, OpenDocument, Typst and PDF through an engine that is not LaTeX the
|
|
1065
|
+
same idea works differently: pdfmd hands Pandoc the whole document with each part in a
|
|
1066
|
+
marked div, lets pandoc-crossref number and resolve everything, and then keeps only the
|
|
1067
|
+
part you asked for (`select.lua`). Its headings, figures, tables and equations keep the
|
|
1068
|
+
full document's numbers, and `[@sec:x]`, `[@fig:y]` to the rest resolve (as links that
|
|
1069
|
+
lead nowhere). Raw LaTeX `\ref{..}` is a LaTeX-only reference: use pandoc-crossref's
|
|
1070
|
+
syntax for those writers. See
|
|
782
1071
|
[`examples/parts/`](https://github.com/aliperdehan/pdfmd/tree/main/examples/parts/).
|
|
783
1072
|
|
|
784
1073
|
#### Faster rebuilds: the cache
|
|
@@ -790,8 +1079,9 @@ pdfmd-options:
|
|
|
790
1079
|
|
|
791
1080
|
keeps LaTeX's cross-reference files between builds (in `~/.cache/pdfmd`), so
|
|
792
1081
|
an unchanged document is typeset once instead of two or three times, and a
|
|
793
|
-
part built on its own shows the
|
|
794
|
-
from the last full build
|
|
1082
|
+
part built on its own shows the exact numbers of the parts left out (taken
|
|
1083
|
+
from the last full build; without the cache they are counted from the
|
|
1084
|
+
sources, above). It never skips a build: Pandoc and
|
|
795
1085
|
LaTeX still process the whole document from the current sources and package
|
|
796
1086
|
every time, so a change shows in the next build. `cache: {plots: true}` (or
|
|
797
1087
|
`--cache-plots`, with nulabreport >= 1.26.0) additionally stores each plot as a
|
|
@@ -832,12 +1122,31 @@ Measured values:
|
|
|
832
1122
|
<img src="https://raw.githubusercontent.com/aliperdehan/pdfmd/main/docs/results.png" width="480" alt="A CSV file rendered as a table">
|
|
833
1123
|
</p>
|
|
834
1124
|
|
|
1125
|
+
Or write the data in the document itself, in a code block so that nothing in it is read as Markdown:
|
|
1126
|
+
|
|
1127
|
+
````markdown
|
|
1128
|
+
::: {.csv align="lrr"}
|
|
1129
|
+
```
|
|
1130
|
+
Compound,Mass (g),Price
|
|
1131
|
+
Water,18.015,1.20
|
|
1132
|
+
"Ethanol, dry",46.07,3.45
|
|
1133
|
+
```
|
|
1134
|
+
:::
|
|
1135
|
+
|
|
1136
|
+
: Masses and prices {#tbl:m}
|
|
1137
|
+
````
|
|
1138
|
+
|
|
835
1139
|
- Cells are read as Pandoc Markdown (`H~2~O`, `$x^2$`, `\ce{...}`, `[@key]`); `reader="gfm"` makes them plain GFM.
|
|
836
1140
|
- A caption is the line after the block (`: Caption {#tbl:id}`, or `Table: Caption`), or `caption="Caption"` inside the
|
|
837
1141
|
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
|
-
|
|
840
|
-
|
|
1142
|
+
- A relative `file=` is found beside the document (and along the resource path), wherever Pandoc runs. With both
|
|
1143
|
+
`file=` and data inside the block, the file is used.
|
|
1144
|
+
- The delimiter is `delimiter=";"` or its name (`semicolon`, `tab`, `pipe`, `space`, `colon`, `comma`); without one it
|
|
1145
|
+
comes from the extension (`.tsv` means tab) or from the first line (whichever of `,` `;` tab `|` it holds most of).
|
|
1146
|
+
- Columns are aligned with `align="lcr"` (or `align="left,center,right"`), or by a second row in the data made of
|
|
1147
|
+
`---`, `:--`, `:-:`, `--:` as in a pipe table; `align=` wins. If such a row is really data, say `separator="none"`.
|
|
1148
|
+
`widths="5,1,1"` sets relative widths, and a second row with unequal dashes does too. Without either, pdfmd picks
|
|
1149
|
+
widths that suit the contents.
|
|
841
1150
|
- The first row is the header unless you add `header="false"`.
|
|
842
1151
|
- Large files are capped at 10 rows × 7 columns, so a huge CSV can't
|
|
843
1152
|
silently fill 40 pages. `rows=all` or `cols=20` raise the cap. When a
|
|
@@ -845,6 +1154,152 @@ Measured values:
|
|
|
845
1154
|
|
|
846
1155
|
This works for every output format.
|
|
847
1156
|
|
|
1157
|
+
#### Turning tables into CSV blocks, and back
|
|
1158
|
+
|
|
1159
|
+
```
|
|
1160
|
+
pdfmd --extract-tables report.md # every table becomes a .csv block reading tables/<name>.csv
|
|
1161
|
+
pdfmd --expand-tables report.md # and back to ordinary tables
|
|
1162
|
+
```
|
|
1163
|
+
|
|
1164
|
+
`--extract-tables` rewrites the document in place, after copying the old one to the backup folder, and says so. Pipe,
|
|
1165
|
+
simple, multiline and grid tables are all read (the ones inside code blocks are not tables). The files are named after
|
|
1166
|
+
the captions (`Masses and prices` gives `tables/masses-and-prices.csv`), or `table1`, `table2` by position;
|
|
1167
|
+
`--table-names a,b,c` names them, and a list that does not match the number of tables is an error that changes nothing.
|
|
1168
|
+
`--table-numbers 1,3-4` extracts just those tables (by position in the document) and leaves the rest; the names then go to
|
|
1169
|
+
the chosen ones. In a document in parts the data goes to the report's `tables/` folder and an unnamed table is named after
|
|
1170
|
+
its part (`discussion-table1.csv`).
|
|
1171
|
+
The caption, the alignment and the widths the document chose stay as attributes of the block, and before anything is
|
|
1172
|
+
written Pandoc reads the old and the new document and the tables must come out the same. A table Pandoc cannot write
|
|
1173
|
+
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
|
|
1174
|
+
`.csv` block already in the document, and if the check fails the whole document is left untouched and the command exits
|
|
1175
|
+
with an error. A document with no front matter is built as `gfm`, which reads pipe tables only, so only those are
|
|
1176
|
+
touched there. `--tables-inline` puts the data
|
|
1177
|
+
inside the document (in a fenced block) instead of in files, `--tables-dir DIR` picks the folder, and `--dry-run` shows
|
|
1178
|
+
the change without making it. `--expand-tables` is the reverse, every row included.
|
|
1179
|
+
|
|
1180
|
+
A `.csv` block that holds its data inside the document stays as it is, unless you pass `--extract-inline-csv`, which moves
|
|
1181
|
+
that data to a file as well. To keep one table or block as it is whatever you run, put `<!-- pdfmd: ignore -->` on the
|
|
1182
|
+
line above it (or under its caption); the comment survives comment stripping, because pdfmd's own comments are kept.
|
|
1183
|
+
A comment between a table and its caption would stop Pandoc from reading the caption as one, so there is no such
|
|
1184
|
+
position.
|
|
1185
|
+
|
|
1186
|
+
### Code: wrapping and line numbers
|
|
1187
|
+
|
|
1188
|
+
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
|
|
1189
|
+
breaks where the line is full), and `{wrap=false}` on one block, `--no-code-wrap` or `code-wrap: false` in
|
|
1190
|
+
`pdfmd-options` lets it run on. Line numbers are off until you ask for them:
|
|
1191
|
+
|
|
1192
|
+
````markdown
|
|
1193
|
+
``` {.python .numberLines startFrom=10}
|
|
1194
|
+
def f(x):
|
|
1195
|
+
return x * 2
|
|
1196
|
+
```
|
|
1197
|
+
````
|
|
1198
|
+
|
|
1199
|
+
`--line-numbers` (or `pdfmd-options: {line-numbers: true}`, or the setting in `pdfmd --setup`) numbers every code block,
|
|
1200
|
+
`--line-numbers 5` numbers every fifth line, `{.noNumberLines}` leaves one block out, and `step=5` and `numbersep=8pt`
|
|
1201
|
+
adjust a single block.
|
|
1202
|
+
|
|
1203
|
+
### Images: SVG and remote ones
|
|
1204
|
+
|
|
1205
|
+
LaTeX reads PDF, PNG and JPEG, not SVG. In a LaTeX build pdfmd converts each SVG the document names, once, with
|
|
1206
|
+
whatever is installed (`rsvg-convert`, Inkscape, `cairosvg`, `svglib`, or LibreOffice, which most machines have), keeps
|
|
1207
|
+
the PDF by the file's content, and uses it where the document wrote the SVG: a Markdown image, a raw
|
|
1208
|
+
`\includegraphics{figure.svg}`, a raw `\includesvg{figure}`. A raw `\includegraphics` also gets `graphicx` loaded,
|
|
1209
|
+
which Pandoc only does for a Markdown image (a PNG in one used to stop the build with "undefined control sequence").
|
|
1210
|
+
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
|
|
1211
|
+
badge works, and a Pandoc built without HTTP support (Homebrew's is) no longer drops it; with no network there is one
|
|
1212
|
+
warning and the image's description stays. `--no-auto svg` and `--no-auto remoteimages` turn the two off, and
|
|
1213
|
+
`pdfmd --doctor` says which converter will be used.
|
|
1214
|
+
|
|
1215
|
+
### Diagrams written as code
|
|
1216
|
+
|
|
1217
|
+
````markdown
|
|
1218
|
+
```mermaid
|
|
1219
|
+
graph LR; Sample --> Reaction --> Product
|
|
1220
|
+
```
|
|
1221
|
+
|
|
1222
|
+
```{.dot #fig:flow caption="The *flow* of the experiment" width=60% engine=neato}
|
|
1223
|
+
digraph { sample -> reaction -> product }
|
|
1224
|
+
```
|
|
1225
|
+
|
|
1226
|
+
```d2
|
|
1227
|
+
sample -> reaction -> product
|
|
1228
|
+
```
|
|
1229
|
+
````
|
|
1230
|
+
|
|
1231
|
+
A fenced block whose class is `mermaid`, `d2`, `dot` or `graphviz` is drawn by the tool that reads that language and the
|
|
1232
|
+
picture takes its place: [Graphviz](https://graphviz.org) (`dot`), [D2](https://d2lang.com) (`d2`) and
|
|
1233
|
+
[Mermaid](https://github.com/mermaid-js/mermaid-cli) (`mmdc`). pdfmd asks each for the format the output takes: a PDF
|
|
1234
|
+
for LaTeX, an SVG for HTML (inside the file, so it can be sent on its own) and Typst (a PNG for Mermaid, whose SVG
|
|
1235
|
+
Typst cannot show), a PNG for Word and OpenDocument, and for flat Markdown (`--to gfm`) an SVG in the `_files/` folder
|
|
1236
|
+
beside the output, except a Mermaid block, which stays as it is because GitHub draws it. A text output keeps the source.
|
|
1237
|
+
Drawings are kept in the cache by their content, so a rebuild does not draw them again. `caption="..."` makes a figure
|
|
1238
|
+
(`{#fig:id}` with pandoc-crossref numbers it), `width=` sizes it, `engine=` picks the Graphviz layout (`dot`, `neato`,
|
|
1239
|
+
`fdp`, `sfdp`, `circo`, `twopi`), `theme=` the Mermaid theme, `layout=` the D2 layout (`dagre`, `elk`). A tool that is
|
|
1240
|
+
not installed leaves the block as code with one warning (`--strict` makes it an error) and says how to install it;
|
|
1241
|
+
a diagram the tool cannot parse stays as code too. `pdfmd --doctor` shows which tools are there, and
|
|
1242
|
+
`--no-auto diagrams` turns the whole thing off. The attributes need Pandoc's Markdown (a file with front matter); a file
|
|
1243
|
+
read as gfm takes the plain ```` ```dot ```` form. Mermaid needs Chrome (mermaid-cli downloads one); in a sandbox
|
|
1244
|
+
`PDFMD_MMDC_CONFIG=puppeteer.json` is handed to `mmdc -p`.
|
|
1245
|
+
|
|
1246
|
+
### Editable in LibreOffice, and one file that carries its data
|
|
1247
|
+
|
|
1248
|
+
`--hybrid` makes the PDF a LibreOffice *hybrid PDF*: besides its pages it carries an OpenDocument copy of the document
|
|
1249
|
+
(`Original.odt`, or `.odp`, `.ods`), and when LibreOffice opens the PDF it opens that copy as a document you can edit,
|
|
1250
|
+
instead of the pages in Draw. An Office file (`pdfmd minutes.docx --hybrid`) is converted by LibreOffice, so the copy is
|
|
1251
|
+
the file itself; a Markdown file gets an `.odt` built by pdfmd with its metadata, so what LibreOffice shows is the
|
|
1252
|
+
Word-route rendering of the source (not the LaTeX pages). `pdfmd --restore report.pdf` writes the ODF file back out.
|
|
1253
|
+
`pdfmd-options: {hybrid: true}` or `pdfmd --setup` makes it the default.
|
|
1254
|
+
|
|
1255
|
+
A single Markdown file can carry its data too: `pdfmd report.md --assemble-only --embed-metadata files -o report.one.md`
|
|
1256
|
+
folds in the images, CSV tables and included files the text points at (text as it is, anything else as base64), and the
|
|
1257
|
+
file builds on its own, in an empty folder; `pdfmd --unpack` writes them back byte for byte. It is left out of the default
|
|
1258
|
+
kinds because it can be big (`bundle-max-mb` caps it); for a PDF, `--bundle` stores the same files beside the source.
|
|
1259
|
+
|
|
1260
|
+
### HTML, LaTeX, Typst and Word pieces inside Markdown
|
|
1261
|
+
|
|
1262
|
+
Markdown can carry raw pieces: `<img>`, `<table>`, `<b>` and `<div>` (HTML), `\ce{...}` or a tikz picture (LaTeX), a
|
|
1263
|
+
`` ```{=typst} `` block, Word or OpenDocument XML. Pandoc keeps the ones written in the format it is writing and drops
|
|
1264
|
+
every other, silently, so a document that mixes them loses pieces in every build. `pdfmd-options.raw` (or `--raw`) says
|
|
1265
|
+
which syntaxes take part in each output family, and carries the foreign ones over:
|
|
1266
|
+
|
|
1267
|
+
```yaml
|
|
1268
|
+
pdfmd-options:
|
|
1269
|
+
raw:
|
|
1270
|
+
tex: [tex, html, typst] # LaTeX builds: PDF through lualatex, xelatex ...
|
|
1271
|
+
typst: [typst, html, tex] # Typst builds
|
|
1272
|
+
html: [html, tex, typst] # HTML, EPUB, PDF through weasyprint and the other HTML engines (-e html)
|
|
1273
|
+
office: [office, html] # Word and OpenDocument, and PDF through soffice
|
|
1274
|
+
```
|
|
1275
|
+
|
|
1276
|
+
```sh
|
|
1277
|
+
pdfmd report --raw # everything for every family
|
|
1278
|
+
pdfmd report --raw-for html=tex,typst --raw-for tex=html # or per family, on the command line
|
|
1279
|
+
```
|
|
1280
|
+
|
|
1281
|
+
A family takes the syntaxes it lists, in this way: its own syntax stays as written; **HTML** is read by Pandoc's HTML
|
|
1282
|
+
reader, so an `<img>` becomes the target's image (an SVG then goes through the image conversion below), a `<table>` a
|
|
1283
|
+
real table, `<b>...</b>` bold text and a `<div>` around Markdown a division, even when the opening and the closing tag
|
|
1284
|
+
sit in separate pieces; **LaTeX** is read by Pandoc's LaTeX reader (what it does not know, a custom macro, stays LaTeX
|
|
1285
|
+
and is lost outside LaTeX; Word builds keep their own LaTeX route, see
|
|
1286
|
+
[Word and OpenDocument output](#word-and-opendocument-output)); **Typst** is drawn by `typst compile` as a cropped
|
|
1287
|
+
vector picture, a PDF for LaTeX, Typst and Word, an SVG for HTML. A syntax a family does not list is dropped, its own
|
|
1288
|
+
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
|
|
1289
|
+
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
|
|
1290
|
+
their content. (An HTML file that is not self-contained points at the cache; use `--self-contained` to carry them.)
|
|
1291
|
+
A LaTeX picture Pandoc cannot read (a `tikzpicture`, `circuitikz`, `pgfpicture`, `forest`, `\chemfig`...) is drawn by a LaTeX
|
|
1292
|
+
engine with the `standalone` class, after the document's own preamble and `header-includes`, and placed as a vector picture
|
|
1293
|
+
in HTML, Typst and flat Markdown builds (an SVG for HTML and Markdown; a piece that does not compile is reported and left
|
|
1294
|
+
out). Not yet: HTML drawn as a picture, Word XML as
|
|
1295
|
+
anything but Word XML.
|
|
1296
|
+
|
|
1297
|
+
**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
|
|
1298
|
+
EPUB, a PDF through WeasyPrint) every image that is a PDF, `` or `<img src="plot.pdf">`, is converted to
|
|
1299
|
+
an SVG with poppler's `pdftocairo` (or `mutool`, `pdf2svg`, `inkscape`) and stays vector; the first page is used and the
|
|
1300
|
+
SVG is kept by the PDF's content. It is on by default, since it only changes what would not have shown; `--no-auto
|
|
1301
|
+
pdfimages` turns it off. LaTeX and Typst read PDFs themselves, and Word has its own route.
|
|
1302
|
+
|
|
848
1303
|
### Not just Markdown
|
|
849
1304
|
|
|
850
1305
|
```sh
|
|
@@ -853,9 +1308,24 @@ pdfmd paper.tex # compiled directly with a LaTeX engine: reruns until
|
|
|
853
1308
|
# no .aux/.log clutter (--keep-aux keeps them)
|
|
854
1309
|
pdfmd minutes.docx # Word/PowerPoint/Excel/ODF: converted by LibreOffice
|
|
855
1310
|
pdfmd analysis.qmd # handed to Quarto, so code chunks actually run
|
|
856
|
-
pdfmd page.html #
|
|
1311
|
+
pdfmd page.html # built by WeasyPrint, or a browser if the page runs scripts: no Pandoc
|
|
1312
|
+
pdfmd note.typ # compiled by Typst itself: the page setup in the file is kept
|
|
1313
|
+
pdfmd notes.rst # anything else Pandoc can read (give the extension)
|
|
857
1314
|
```
|
|
858
1315
|
|
|
1316
|
+
A finished `.typ` or `.html` file goes straight to its own engine, because Pandoc would read it into its own model
|
|
1317
|
+
and write it out again, and the page size, the styles and the scripts would not survive the trip. For a page that is
|
|
1318
|
+
WeasyPrint first (it is quiet and needs no browser); a page with `<script>` goes to Chrome, Chromium, Edge or Brave
|
|
1319
|
+
(headless, printing the page), as does one WeasyPrint cannot draw, and wkhtmltopdf, Prince, pagedjs-cli and LibreOffice
|
|
1320
|
+
come after. `-e edge` (or `weasyprint`, `chromium`...) picks one. As with an Office file, such a document gets none of
|
|
1321
|
+
pdfmd's defaults, since it is finished; `--apply-defaults` (also in `pdfmd --setup`) gives it the title, author, date,
|
|
1322
|
+
language, font, font size, paper and margin of its `metadata.yaml`, ahead of its own settings so those win. A `.tex`
|
|
1323
|
+
file that no LaTeX engine can compile is tried through Pandoc, with a warning.
|
|
1324
|
+
|
|
1325
|
+
The reader comes from the file's extension, as in Pandoc, and a bare name is looked up as `<name>.md`, so give the
|
|
1326
|
+
extension for anything else. The automatic decisions about Markdown (`READER`, `TITLE`, `citeproc`, `crossref` below)
|
|
1327
|
+
apply to Markdown files only.
|
|
1328
|
+
|
|
859
1329
|
**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
1330
|
and guesses its structure: headings (capitals, `1.2 Title`, `====` underlines), bullet and numbered lists, tables from
|
|
861
1331
|
columns separated by runs of spaces, indented blocks as code, hard-wrapped lines joined into paragraphs. The words never
|
|
@@ -871,16 +1341,19 @@ Most of these print an `AUTO` line, and each can be switched off individually.
|
|
|
871
1341
|
|
|
872
1342
|
| `AUTO` kind | When | What happens |
|
|
873
1343
|
|---|---|---|
|
|
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 |
|
|
1344
|
+
| `READER` | a Markdown file with no YAML front matter | reads the file as GitHub-flavoured Markdown (content-sized table columns, relaxed blank-line rules). If the file uses what only Pandoc's Markdown reads (`H~2~O`, `x^2^`, `{#id}` attributes, raw LaTeX, fenced divs), a `NOTE` says gfm leaves it as text; `--from markdown`, a front-matter block, or `reader:` below changes it |
|
|
1345
|
+
| `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
1346
|
| `MARGIN` | no margin or geometry set anywhere | 1-inch margins instead of LaTeX's wide defaults |
|
|
877
1347
|
| `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
1348
|
| `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
1349
|
| `MONOFONT` | the document contains code | JetBrains Mono for code (Menlo or another installed monospace font if it isn't installed) |
|
|
880
|
-
| `tablewidth` | a
|
|
1350
|
+
| `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 |
|
|
1351
|
+
| `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`) |
|
|
1352
|
+
| `typstdirect`, `htmldirect` | a `.typ` or `.html` file | built by Typst / WeasyPrint or a browser, not through Pandoc (`--no-auto typstdirect` for the old route) |
|
|
1353
|
+
| `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
1354
|
| `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 |
|
|
1355
|
+
| `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) |
|
|
1356
|
+
| `crossref` | `@fig:`/`@tbl:` references or `{#fig:...}` labels | adds the `pandoc-crossref` filter, ahead of citeproc |
|
|
884
1357
|
| `papersize` | `pagesize: a4` (a common typo) | converts it to Pandoc's real `papersize:` |
|
|
885
1358
|
|
|
886
1359
|
`-v` explains each decision and prints the exact command it runs:
|
|
@@ -893,7 +1366,7 @@ AUTO READER lecture.md: no YAML front matter; reading as gfm
|
|
|
893
1366
|
AUTO TITLE lecture.md: promoted leading '# ' heading to Pandoc title metadata
|
|
894
1367
|
AUTO MARGIN lecture.md: no geometry/margin set; using geometry:margin=1in on LaTeX-family engines
|
|
895
1368
|
AUTO MONOFONT lecture.md: has code but no monofont set; using JetBrains Mono on LaTeX-family engines
|
|
896
|
-
OK lecture.md
|
|
1369
|
+
OK lecture.md (lualatex)
|
|
897
1370
|
```
|
|
898
1371
|
|
|
899
1372
|
The second `CMD` line is the font fallback at work: STIX Two Text was
|
|
@@ -903,6 +1376,24 @@ file paths are shortened here.)
|
|
|
903
1376
|
**When a PDF doesn't look the way the Markdown suggests, run `-v` first.**
|
|
904
1377
|
The cause is usually one of these automatic decisions, and `-v` names it.
|
|
905
1378
|
|
|
1379
|
+
The closing line also names the engine that made the PDF. If an earlier one failed, the line says so, so a
|
|
1380
|
+
build that quietly fell back to Typst does not look like one that did not:
|
|
1381
|
+
|
|
1382
|
+
```console
|
|
1383
|
+
$ pdfmd paper
|
|
1384
|
+
WARN paper.md: lualatex failed (! Undefined control sequence.); trying xelatex...
|
|
1385
|
+
WARN paper.md: xelatex failed (! Undefined control sequence.); trying typst...
|
|
1386
|
+
OK paper.md (typst; lualatex, xelatex failed)
|
|
1387
|
+
```
|
|
1388
|
+
|
|
1389
|
+
When LaTeX itself stops, the warning also says where: Pandoc reports a line of the LaTeX it wrote, so pdfmd finds those
|
|
1390
|
+
words in your Markdown and prints `near line 9 of paper.md: ...has \badmacro`.
|
|
1391
|
+
|
|
1392
|
+
`--strict` (or `pdfmd-options: {strict: true}` in the document; `--no-strict` overrides it) makes that, and every other
|
|
1393
|
+
warning, an error for scripts and CI: a file whose build printed a `WARN` line, or about which Pandoc warned (an image
|
|
1394
|
+
or citation it could not find, a LaTeX reference left undefined), is reported `FAIL` with the first warnings listed and
|
|
1395
|
+
the exit code is 1. The output file is kept. In a batch only that file fails.
|
|
1396
|
+
|
|
906
1397
|
### Other scripts
|
|
907
1398
|
|
|
908
1399
|
<p align="center">
|
|
@@ -1016,6 +1507,10 @@ pdfmd-options:
|
|
|
1016
1507
|
---
|
|
1017
1508
|
```
|
|
1018
1509
|
|
|
1510
|
+
`reader:` fixes the Pandoc reader of a Markdown file (`markdown`, `gfm`, `commonmark_x`, ...; `auto` is the default
|
|
1511
|
+
choice described under *What it does automatically*). It is `--from` for one document, or for a whole folder or all your
|
|
1512
|
+
documents when it sits in `metadata.yaml` or the config file's `options:`.
|
|
1513
|
+
|
|
1019
1514
|
`pdf-engine:` takes an engine name (`lualatex`, `typst`, ...) or a family:
|
|
1020
1515
|
`tex`, `typst`, `html` or `office`. A family limits the fallback chain to
|
|
1021
1516
|
that kind of engine. For example, a document full of chemical structures
|
|
@@ -1089,19 +1584,28 @@ With a `metadata/` folder, a report's own folder can hold nothing but
|
|
|
1089
1584
|
`bibliography: refs.bib`) resolve from `metadata/`, and image paths in the
|
|
1090
1585
|
document still resolve from the document's own folder.
|
|
1091
1586
|
|
|
1587
|
+
**A Lua filter can run any command**, so pdfmd tells you about the ones it picks up by itself. The first build with a
|
|
1588
|
+
`<name>.lua` (or `nulabreport.lua`) it has not run before prints one `NOTE`, and so does the first build after the file
|
|
1589
|
+
changed; the filter runs all the same, and there is never a prompt, so a filter you edit every day, `-j`, `-w`, CI and the
|
|
1590
|
+
Python API are not held up. `pdfmd --trust-lua ~/work/reports` marks a folder you work in (or one filter, as it is now):
|
|
1591
|
+
nothing under it is noted again. Only `--strict` skips a new or edited filter outside such a folder. pdfmd remembers
|
|
1592
|
+
each filter's path and SHA-256 in `known-lua.txt` beside its config. This is a notice, not a lock: it does not protect
|
|
1593
|
+
the first build of a folder you have just downloaded, so read its `.lua` first.
|
|
1594
|
+
|
|
1092
1595
|
One shared metadata file can also be **symlinked** into many folders. A
|
|
1093
1596
|
relative `bibliography: refs.bib` inside it then finds the `refs.bib`
|
|
1094
1597
|
next to the file's real copy, so you never need an absolute path.
|
|
1095
1598
|
|
|
1096
|
-
## Build stamps and snapshots
|
|
1599
|
+
## Build stamps, history and snapshots
|
|
1097
1600
|
|
|
1098
|
-
|
|
1601
|
+
All are off by default.
|
|
1099
1602
|
|
|
1100
1603
|
- **`--stamp`** keeps a `BUILD NOTES` HTML comment at the end of the `.md`
|
|
1101
1604
|
up to date. It records when the document was compiled and with which
|
|
1102
1605
|
`pdfmd` version, plus the versions of any LaTeX packages you name with
|
|
1103
1606
|
`--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/`
|
|
1607
|
+
- **`--backup`** saves a timestamped copy of the source into `.backups/` (a hidden folder; an existing `backup/` is kept
|
|
1608
|
+
using, and pdfmd says where the first copy went)
|
|
1105
1609
|
after every successful build. A copy is skipped when nothing changed,
|
|
1106
1610
|
and `keep: 30` limits how many are kept.
|
|
1107
1611
|
|
|
@@ -1110,16 +1614,45 @@ Both can be turned on for a whole folder from `metadata.yaml`:
|
|
|
1110
1614
|
```yaml
|
|
1111
1615
|
pdfmd-options:
|
|
1112
1616
|
stamp: true
|
|
1113
|
-
backup: { dir:
|
|
1617
|
+
backup: { dir: .backups, keep: 30 }
|
|
1114
1618
|
```
|
|
1115
1619
|
|
|
1620
|
+
**History in a file instead of in the document.** `--stamp-store file` (or `stamp: {store: file}`) writes each compile
|
|
1621
|
+
to `NAME.hst` in the backup folder, and the document itself is not edited by a build. The file is one line per entry,
|
|
1622
|
+
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`
|
|
1623
|
+
keeps every entry once:
|
|
1624
|
+
|
|
1625
|
+
```
|
|
1626
|
+
# pdfmd history of report.md -- one entry per line, newest first: WHEN | KIND | TEXT [| key=value ...]
|
|
1627
|
+
2026-10-09 11:22:01 | compiled | with nulabreport v1.27.7, pdfmd v3.25.7 | sha=3fa91c0d4b21 out=report.pdf
|
|
1628
|
+
```
|
|
1629
|
+
|
|
1630
|
+
`pdfmd --history-to-file report.md` moves the whole `BUILD NOTES` block that pdfmd owns into that file (the compiles as
|
|
1631
|
+
entries, anything written by hand inside it as one `note` entry), and `--history-to-notes` builds the block again (both
|
|
1632
|
+
back the document up first, `--dry-run` shows). A document may carry several
|
|
1633
|
+
`BUILD NOTES` blocks (yours, an AI agent's): pdfmd writes only into the one that already holds its own lines, or the
|
|
1634
|
+
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
|
|
1635
|
+
line `pdfmd: ignore` in a block keeps pdfmd out of it. The file travels with the document: `--embed-metadata` folds it
|
|
1636
|
+
in (`hst`), `--unpack` writes it out, and `--attach-source` stores it in the PDF for `--restore`.
|
|
1637
|
+
|
|
1638
|
+
**Going back.** `pdfmd --history report.md` lists every version it can find, newest first: the backups (in `.backups`,
|
|
1639
|
+
and in an older `backup/`, `backups/`... beside the document, whatever naming each file has), the git commits that
|
|
1640
|
+
changed the file (the repository may be a folder above), and the compiles recorded in its history. In a terminal the
|
|
1641
|
+
list is navigable: a number shows what differs, `d 3` the diff, `r 3` restores. Without one, `--history-diff` and
|
|
1642
|
+
`--history-restore` take a number, a backup's timestamp (any start of it: `20261003`), a file name, a commit hash,
|
|
1643
|
+
`latest`, or `previous` (the newest that is not the file as it is). A restore backs the file up first, so nothing is
|
|
1644
|
+
ever lost; it keeps the build notes and history of the file as it is now, and adds a `Restored version ...` entry
|
|
1645
|
+
(`stamp: {restored-note: false}` or `--no-restored-note` leave it out; `--dry-run` shows what would change).
|
|
1646
|
+
`pdfmd --init-backups report.md` turns all of this on for a document: backups and a history file, set in its front
|
|
1647
|
+
matter under an `AUTO GENERATED` comment (`--global` for every document), and a first copy.
|
|
1648
|
+
|
|
1116
1649
|
Separately, when `pypdf` is installed, every PDF built by `pdfmd` gets two
|
|
1117
1650
|
hidden metadata keys, `PdfmdVersions` and `PdfmdBuildDate`, which you can
|
|
1118
1651
|
read with `pdfinfo -meta`. Turn this off with `--no-stamp-pdf-metadata`.
|
|
1119
1652
|
|
|
1120
1653
|
## Reference
|
|
1121
1654
|
|
|
1122
|
-
- [`docs/recipes.md`](https://github.com/aliperdehan/pdfmd/blob/main/docs/recipes.md)
|
|
1655
|
+
- [`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
1656
|
- `pdfmd --help` lists every flag.
|
|
1124
1657
|
- The docstring at the top of [`pdfmd.py`](https://github.com/aliperdehan/pdfmd/blob/main/pdfmd.py) is the full reference
|
|
1125
1658
|
for each behaviour and its edge cases.
|