Skip to content

Instantly share code, notes, and snippets.

@cartok
Last active February 5, 2026 22:12
Show Gist options
  • Select an option

  • Save cartok/0c5c625086602f5d8bd04ecd3e2b5806 to your computer and use it in GitHub Desktop.

Select an option

Save cartok/0c5c625086602f5d8bd04ecd3e2b5806 to your computer and use it in GitHub Desktop.
[cli] Generate .pdf or .html from .md
#!/usr/bin/env zsh
function md-to-pdf() {
-md-to "$1" pdf
}
function md-to-html() {
-md-to "$1" html
}
function -md-to() {
if (( "${#funcstack[@]}" == 0 )); then
echo "Use md-to-pdf or md-to-html instead."
return 1
fi
local tempFiles=()
function cleanup() {
(( ${#tempFiles[@]} )) && rm -f -- "${tempFiles[@]}"
}
trap cleanup EXIT INT TERM HUP
local inputFilePath="$1"
local outputFormat="$2"
if [[ -z "$inputFilePath" ]]; then
echo "Bad parameters"
echo "\n"
echo "Usage: md-to-$outputFormat <file>"
echo "Hint: Supply pandoc arguments via inline yaml inside the markdown file. Therefore read \`man pandoc\` and search for \" Variables\"."
echo ""
echo "Example markdown file that includes YAML configuration header:"
echo ""
echo "\t" '---'
echo "\t" 'title: Tale of the Utterly Gutsy Shinobi'
echo "\t" 'author: Jiraiya'
echo "\t" 'fontsize: 12pt'
echo "\t" 'mainfont: Cantarell'
echo "\t" '---'
echo ""
echo "\t" '## Hidden Leaf Stories'
echo ""
echo "\t" '## Chapter 1.'
echo ""
echo "\t" 'In the dense forests surrounding Konoha, Naruto Uzumaki prepared his next jutsu.'
echo "\t" 'The wind whispered through the trees, carrying the scent of chakra and danger.'
echo ""
echo "\t" 'Naruto takes a deep breath.'
echo "\t" '"Shadow Clone Jutsu!" he shouts.'
echo "\t" 'Suddenly, five perfect copies of him vanish into the mist, ready to fight anything!'
return 1
fi
if [[ "${inputFilePath##*.}" != "md" ]]; then
echo "Error: Input file must have .md extension"
return 1
fi
local outputFilePathWithBaseName="${inputFilePath%.md}"
local outputFilePath="${outputFilePathWithBaseName}.${outputFormat}"
local modifiedInputFilePath="$(mktemp)"
tempFiles+=($modifiedInputFilePath)
cp -- "$inputFilePath" "$modifiedInputFilePath"
local pandocArguments=(
"$modifiedInputFilePath"
--output "$outputFilePath"
--standalone
)
local latexHeaderFilePath="$(mktemp)"
tempFiles+=($latexHeaderFilePath)
# TODO: Parse yaml header of the markdown file to allow overwriting some of the here set variables, like `fontsize`. Otherwise the parameters here take precedence, thus its impossible to define them in markdown. Implement it by reading the lines between `---` into a string pass it throuhg `yaml2json` and use `jq` and read those variables of those below which shall still be configurable. Could then also stip the yaml of the markdown file, write the combined yaml and then the markdown content. This way I could define such default parameters as a multiline yaml string here.
if [[ "$outputFormat" == "pdf" ]]; then
pandocArguments+=(
--from markdown+hard_line_breaks+raw_tex
--pdf-engine=xelatex
--variable documentclass=scrartcl
--variable papersize=a4
--variable geometry=margin=1in
--variable fontsize=11pt
--include-in-header "$latexHeaderFilePath"
)
print -r -- "\usepackage{sectsty}" >> "$latexHeaderFilePath"
print -r -- "\subsectionfont{\Large\bfseries}" >> "$latexHeaderFilePath"
elif [[ "$outputFormat" == "html" ]]; then
sd -f i '^\\newpage\s*$' '' "$modifiedInputFilePath"
# TODO: Check if there is a usefull application of latex commands for HTML generation. If so make GFM a commandline argument instead. As for PDF generation its mandatory to me that pagebreaks must be supported but I also would like to have GFM, I now only use GFM for HTML output.
pandocArguments+=(
--from gfm+hard_line_breaks
--variable fontsize=12pt
--variable maxwidth=52em
)
fi
pandoc "${pandocArguments[@]}" 2>/dev/null
cleanup
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment