#!/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%.md}.conf"
#
# Utility functions
#
SEEN_SLUGS="$(mkstemp)"
slugify_once() {
SLUG="$(printf '%s' "$1" | slugify)${2:+-$2}"
if grep -q "^$SLUG$" "$SEEN_SLUGS"; then
N="${2:-0}"
N=$((N + 1))
slugify_once "$1" "$N"
else
printf '%s\n' "$SLUG" >> "$SEEN_SLUGS"
printf '%s' "$SLUG"
fi
}
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%.md}.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%.md}.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_once "$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
)
}
emit_body() {
< "${FILENAME%.md}.content" \
markdown_to_html |
extract_plaintext_snippets |
add_line_numbers |
add_headings_anchors
}
envsubst < src/lib/preamble.html
emit_body | tee "${FILENAME%.md}.htmlbody"
envsubst < src/lib/postamble.html