Skip to content
This document describes intent at the time it was written. It is part of the design record, not user documentation, and may not reflect the current behaviour of the code.

005 - pdf / pdf-pptx / pdf-docx commands

Purpose: Export Office files to PDF via AppleScript (macOS only).

Status: Implemented (2026-05-07)

  • mdd pdf-pptx [dir] finds PPTX files needing export, uses PowerPoint via AppleScript
  • mdd pdf-docx [dir] finds DOCX files needing export, uses Word via AppleScript
  • mdd pdf-docx updates every table of contents, and best-effort every other field, before export, because Word does not evaluate fields on open and a TOC would otherwise be empty in the PDF; mdd pdf-docx --no-update-fields [dir] exports without the update. mdd pdf always updates
  • mdd pdf-docx first closes, unsaved, any copy of the document Word already has open, because Word’s open returns that in-memory copy instead of re-reading the file
  • The .docx is closed without saving, so the field update never changes the source or its mtime
  • mdd pdf [dir] runs both
  • Staleness: only export if PDF missing or source is newer than PDF
  • Excludes symlinks and files in templates/ directory
  • Skips (with a warning) a source whose .pdf sibling is a symlink. The destination handed to the Office app is the resolved directory plus the .pdf name, never the resolved .pdf path, so the app cannot be pointed at a link target; a .pdf that is a symlink after the export counts as a failure. The [dir] argument itself may be a symlink
  • Skips (with a warning) files whose name contains control characters
  • Double-extension output: file.pptx.pdf, file.docx.pdf
  • Defaults to current directory if no [dir] argument
  • Commands in src/mdd/commands/pdf*.py; shared helpers in src/mdd/utils/pdf_export.py
  • AppleScript invoked via subprocess.run(['osascript', '-e', script, '--', src, pdf]); the script is a fixed constant with an on run argv handler that reads the source and PDF paths as POSIX file (item N of argv), so file names are data, never part of the program text. The Word script is assembled from fixed fragments by build_docx_applescript(update_fields=...)
  • Tables of contents are updated through Word’s tables of contents collection, not fields: pandoc wraps the TOC field in a content control, which fields does not enumerate, and iterating fields can fail outright with error -1708, so the general field pass runs inside try
  • macOS only — fails gracefully on other platforms (osascript not found)

Ported from quarto4sbp (cmd_pdf, cmd_pdf_pptx, cmd_pdf_docx). The cmd_*(args) entrypoint shape was superseded by S35’s register(subparsers, parents) convention; the three modules now expose register() and _run_* handlers in src/mdd/commands/pdf*.py.

Site built 2026-10-26.