This snapshot carries sks/tns/, the translation directory, into the
distribution for the first time, together with the two default font
families its stylesheet names.
sks/tns/ holds two converters in opposite directions. md_to_sks.py
converts Markdown to Klammertext, recording what it cannot convert exactly
as "#[MD ... ]#" markers so a draft carries its own worklist. md_to_pdf.py
renders Markdown straight to PDF through a headless Chromium driven over the
DevTools Protocol, bypassing Klammertext entirely -- the route for a
document that is not ready to convert, and a permanent one for Markdown that
Klammertext cannot represent well. Neither is loaded by the SKS; md_to_pdf
needs markdown-it-py, which it keeps in a virtual environment of its own and
creates with --setup.
The everyday form of the second is the mdpdf command, a shell function in
sks/tns/mdpdf.sh that env/runtime.env sources, so anyone with the
Klammertext environment has it:
mdpdf notes.md # writes notes.pdf beside it
It supplies the house fonts, the size matching, and the code wrapping,
completes on *.md at the TAB key, and takes its defaults from MDPDF_*
variables so one can be changed in a shell profile without copying the
function. It is POSIX shell rather than zsh, since runtime.env is sourced
from bash profiles too.
Two things the stylesheet does that a print stylesheet usually cannot. Code
lines are wrapped to a column count MEASURED from the rendered page rather
than written down -- the browser is asked how many characters a code box
holds, over every box in the document, so the wrapping stays right when the
fonts, sizes or margins change. And the page number is a CSS Paged Media
margin box, which current Chromium implements, so it is set in the
document's own face instead of the browser's generic sans.
fnt/ gains EB Garamond and Source Sans 3, the serif and sans the stylesheet
asks for by default.
(from dev 97d4f244c737)
95 lines
3.9 KiB
Bash
95 lines
3.9 KiB
Bash
# 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 <file[.md]> [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
|