# mdpdf -- Markdown to PDF in one word. A shell front end to md_to_pdf.py. # # mdpdf notes.md # writes notes.pdf beside it # mdpdf notes # the .md may be left off # mdpdf notes.md out.pdf --page-numbers # # This file is SOURCED, not run: `mdpdf` has to be a shell function so that # TAB completion can be attached to it (compdef and complete both work on # functions and commands, never on aliases). env/runtime.env sources it, so # a user who has the Klammertext environment at all has the command; sourcing # it by hand is only for a shell that does not load runtime.env: # # source "$KLAMMERTEXT_HOME/sks/tns/mdpdf.sh" # # It is plain POSIX shell rather than zsh, and works under bash, zsh and dash # alike. Nothing here needs zsh -- and runtime.env is sourced from bash # profiles too, so a zsh-only file would break for those users at the source, # with a syntax error rather than a message. # # WHAT THE FUNCTION ADDS over calling md_to_pdf.py directly: the house font # and wrapping defaults, tolerance of a bare basename, and completion. Each # default is a variable, so a user overrides one in their profile without # copying the function: # # MDPDF_SERIF, MDPDF_SANS, MDPDF_MONO font-store names # MDPDF_MATCH average | xheight | capheight # MDPDF_WRAP columns for --wrap-code; # auto = measure, 0 = off # MDPDF_BROWSER path to a Chromium-based browser # # They are read at CALL time, not here, so setting one after this file is # sourced still takes effect. Any further md_to_pdf.py option may be given on # the command line and wins over the default, since argparse takes the last # occurrence of an option. # # No particular browser is required. md_to_pdf.py finds one from its own # list -- Brave, then Chrome, then Chromium, on Linux and macOS -- because # they all speak the same DevTools protocol; MDPDF_BROWSER is for a browser # installed somewhere unusual, not for choosing a brand. mdpdf() { if [ -z "$KLAMMERTEXT_HOME" ]; then printf 'mdpdf: KLAMMERTEXT_HOME is not set -- source env/runtime.env\n' >&2 return 1 fi if [ "$#" -lt 1 ]; then printf 'usage: mdpdf [output.pdf] [md_to_pdf.py option ...]\n' >&2 return 1 fi _mdpdf_in="$1" shift # A bare basename is accepted, but only as a fallback: a file that exists # under the name given is never reinterpreted. if [ ! -f "$_mdpdf_in" ] && [ -f "$_mdpdf_in.md" ]; then _mdpdf_in="$_mdpdf_in.md" fi if [ ! -f "$_mdpdf_in" ]; then printf 'mdpdf: no such file: %s\n' "$_mdpdf_in" >&2 unset _mdpdf_in return 1 fi # Prepended, so an explicit --browser on the command line still wins. if [ -n "$MDPDF_BROWSER" ]; then set -- --browser "$MDPDF_BROWSER" "$@" fi python3 "$KLAMMERTEXT_HOME/sks/tns/md_to_pdf.py" "$_mdpdf_in" \ --serif "${MDPDF_SERIF:-eb-garamond}" \ --sans "${MDPDF_SANS:-source-sans-3}" \ --mono "${MDPDF_MONO:-inconsolata}" \ --match "${MDPDF_MATCH:-xheight}" \ --wrap-code "${MDPDF_WRAP:-auto}" \ "$@" _mdpdf_status=$? unset _mdpdf_in return $_mdpdf_status } # Completion, where the shell has it. In zsh compdef exists only after # compinit has run, so its absence is not an error; in bash the form is the # one doc/argument_completion.md gives for the other commands, plus -d so # directories can still be descended into. if [ -n "$ZSH_VERSION" ]; then whence compdef >/dev/null 2>&1 && compdef '_files -g "*.md"' mdpdf elif [ -n "$BASH_VERSION" ]; then complete -f -d -X '!*.md' mdpdf fi # Sourced from runtime.env, whose own exit status must stay 0: without this, # a shell where the completion test failed would report failure for # `source runtime.env`. true