aboutsummaryrefslogtreecommitdiff
#!/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'