#!/bin/sh
set -eu
usage() {
cat <<-'EOF'
Usage:
html FILENAME
html -h
EOF
}
help() {
cat <<-'EOF'
Options:
-h, --help show this message
FILENAME the name of the input file .md file
Process the FILENAME, and generate a full HTML page.
Examples:
Generate the HTML for a pastebin:
$ html src/a-paste.md > src/a-paste.html
EOF
}
for f in "$@"; do
case "$f" in
--)
break
;;
--help)
usage
help
exit
;;
*)
;;
esac
done
while getopts 'h' flag; do
case "$flag" in
h)
usage
help
exit
;;
*)
usage >&2
exit 2
;;
esac
done
shift $((OPTIND - 1))
. src/lib.sh
FILENAME="${1:-}"
eval "$(assert_arg "$FILENAME" 'FILENAME')"
# shellcheck source=/dev/null
. "${FILENAME%.*}.conf"
#
# Utility functions
#
INDENT=' '
markdown_to_html() {
md2html | awk -vINDENT="$INDENT" '
BEGIN {
in_block = 0
}
{
if (in_block == 0) {
printf "%s", INDENT
}
print
}
/^<\/code><\/pre>$/ {
in_block = 0
}
/^<pre><code/ {
in_block = 1
}
'
}
extract_plaintext_snippets() (
SNIPPETS="${FILENAME%.*}.snippets"
printf '' > "$SNIPPETS"
F="$(mkstemp)"
cat > "$F"
IFS=''
BLOCK_NUMBER=0
IN_BLOCK=
while read -r line; do
if [ "$line" = '</code></pre>' ]; then
IN_BLOCK=
fi
if [ -n "$IN_BLOCK" ]; then
printf '%s\n' "$line" | htmlesc -d >> "$OUT"
fi
if printf '%s' "$line" | grep -q "^$INDENT<pre><code"; then
IN_BLOCK=1
OUT="${FILENAME%.*}.html.$BLOCK_NUMBER.txt"
BLOCK_NUMBER=$((BLOCK_NUMBER + 1))
printf '%s\n' "$line" |
sed "s|^\($INDENT<pre><code.*>\)\(.*\)$|\2|" |
htmlesc -d > "$OUT"
printf '%s\n' "$OUT" >> "$SNIPPETS"
fi
done < "$F"
BLOCK_NUMBER=0
while read -r line; do
printf '%s\n' "$line"
if [ "$line" = '</code></pre>' ]; then
printf '%s<p class="plaintext-link"><a href="%s">plaintext</a></p>\n' \
"$INDENT" \
"$(basename "${url_part:?}").$BLOCK_NUMBER.txt"
BLOCK_NUMBER=$((BLOCK_NUMBER + 1))
fi
done < "$F"
)
add_line_numbers() {
awk '
/^<\/code><\/pre>$/ {
in_block = 0
printf "</tbody></table>%s\n", $0
next
}
match($0, /^( +<pre><code.*>)(.*)$/, a) {
printf "%s<table rules=columns class=\"code-block\"><tbody>", a[1]
n = 1
block_count++
printf "<tr><td class=\"line-number\"><a id=\"B%s-L%s\" href=\"#B%s-L%s\">%s</a></td><td class=\"code-line\">%s</td></tr>\n", block_count, n, block_count, n, n, a[2]
in_block = 1
next
}
in_block == 1 {
n++
printf "<tr><td class=\"line-number\"><a id=\"B%s-L%s\" href=\"#B%s-L%s\">%s</a></td><td class=\"code-line\">%s</td></tr>\n", block_count, n, block_count, n, n, $0
next
}
{ print }
'
}
add_headings_anchors() (
IFS=''
while read -r line; do
if ! printf '%s' "$line" | grep -q "^$INDENT<h[2-6]>"; then
printf '%s\n' "$line"
continue
fi
LVL="$(printf '%s' "$line" | sed "s|^$INDENT<h\(.\)>.*|\1|")"
HEADING="$(printf '%s' "$line" | sed "s|^$INDENT<h.>\(.*\)</h.>$|\1|")"
SLUG="$(slugify "$HEADING")"
printf '%s<h%s class="header-anchor" id="%s">%s<a href="#%s" aria-hidden="true"><img class="svg-icon" src="%s" /></a></h%s>\n' \
"$INDENT" \
"$LVL" \
"$SLUG" \
"$HEADING" \
"$SLUG" \
"${icon_link_url:?}" \
"$LVL"
done
)
warn_duplicate_ids() {
F="$(mkstemp)"
tee "$F"
{
grep "^$INDENT<h[2-6] class=\"header-anchor\" id=\"" |
sed "s|^$INDENT<h[2-6] class=\"header-anchor\" id=\"\(.*\)\">.*<a href=.*$|\1|" |
sort |
uniq -c |
awk -v F="$FILENAME" '$1 != 1 {
printf "WARNING: duplicate header id: %s: %s\n", F, $2
}'
} >&2 < "$F"
rm "$F"
}
emit_body() {
< "${FILENAME%.*}.content" \
markdown_to_html |
extract_plaintext_snippets |
add_line_numbers |
add_headings_anchors |
warn_duplicate_ids
}
if [ -r "$FILENAME".prev ]; then
collection_head_prev_html="$(
printf ' <link rel="prev" type="text/html" href="%s" />' \
"$(url-for < "$FILENAME".prev)"
)"
export collection_head_prev_html
fi
if [ -r "$FILENAME".next ]; then
collection_head_next_html="$(
printf ' <link rel="next" type="text/html" href="%s" />' \
"$(url-for < "$FILENAME".next)"
)"
export collection_head_next_html
fi
envsubst < src/lib/preamble.html | sed '/^$/d'
emit_body | tee "${FILENAME%.*}.htmlbody"
envsubst < src/lib/postamble.html | sed '/^$/d'