aboutsummaryrefslogblamecommitdiff
path: root/v2/src/development/genhtml.sh
blob: cb8fd7387eac7af0c40b60a61001eda30941b9f8 (plain) (tree)
1
2
3


         
































































                                                                                     
                        

                 
                                           
 
 
                        




                   












                                                      
















                                                              
                                                                            







                                                                               
                                                           







                                                              
                                                                                                                                              


















































                                                                                                                                                                                             
                                                                





                                      
                                             






                                            








                                    
                           


                                                                                  

                                                                              
 
                                       

                                                     


                                                                  
 

                                                     




                    
                                                            
                                                             





                       
                             
                      










                                                                                  




                                                                                                                 
                                                                                              






                        
                                                                                                                                     
                                                    

                     
                                                                                                                             
                                                                                   


                     
                                                                                                                                                                                                                                                                                                                                    




                     












                                                                         
#!/bin/sh
set -eu

usage() {
	cat <<-'EOF'
		Usage:
		  genhtml.sh FILENAME
		  genhtml.sh -h
	EOF
}

help() {
	cat <<-'EOF'

		Options:
		  -h, --help    show this message

		  FILENAME      the name of the input file, to also be used as
		                URL


		Process the FILENAME, and generate a full HTML page.

		The FILENAME is used to infer the output URL, by removing the
		`src/content/` prefix, and replacing the trailing `.md` with
		`.html`.  This URL is used to build the self-referencing
		"canonical" link, extracting plaintext snippets, etc.


		Examples:

		  Generate the HTML for a pastebin:

		    $ sh genhtml.sh src/content/a-paste.md > src/content/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/development/lib.sh

FILENAME="${1:-}"
eval "$(assert_arg "$FILENAME" 'FILENAME')"


. "${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
}

markdown_to_html() {
	md2html
}

extract_plaintext_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 '^<pre><code.*>'; then
				IN_BLOCK=1
				OUT="${FILENAME%.md}.html.$BLOCK_NUMBER.txt"
				BLOCK_NUMBER=$((BLOCK_NUMBER + 1))
				printf '%s\n' "$line" |
					sed 's|^\(<pre><code.*>\)\(.*\)$|\2|' |
					htmlesc -d > "$OUT"
			fi
		done < "$F"

		BLOCK_NUMBER=0
		while read -r line; do
			printf '%s\n' "$line"

			if [ "$line" = '</code></pre>' ]; then
				printf '<p class="plaintext-link"><a href="%s.%s.txt">plaintext</a></p>\n' "$(url-for "$URL")" "$BLOCK_NUMBER"
				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 '^<h[2-6]>'; then
				printf '%s\n' "$line"
				continue
			fi
			LVL="$(printf '%s' "$line" | sed 's|^<h\(.\)>.*|\1|')"
			HEADING="$(printf '%s' "$line" | sed 's|^<h.>\(.*\)</h.>$|\1|')"
			SLUG="$(slugify_once "$HEADING")"
			printf '<h%s class="header-anchor" id="%s">%s<a href="#%s" aria-hidden="true"><img class="svg-icon" src="%s" /></a></h%s>\n' \
				"$LVL"     \
				"$SLUG"    \
				"$HEADING" \
				"$SLUG"    \
				"$(url-for 'static/link.svg')" \
				"$LVL"
		done
	)
}

emit_body() {
	cat "${FILENAME%.md}.entry-content" |
		markdown_to_html           |
		extract_plaintext_snippets |
		add_line_numbers           |
		add_headings_anchors
}





#
# Main: generate the HTML to STDOUT.
#

cat <<-EOF
	<!DOCTYPE html>
	<html lang="$lang">
	  <head>
	    <meta charset="UTF-8" />
	    <meta name="viewport" content="width=device-width, initial-scale=1" />
	    <link rel="stylesheet" type="text/css"      href="$style_url" />
	    <link rel="icon"       type="image/svg+xml" href="$favicon_url" />

	    <title>$$title_html</title>

	    <meta name="author" content="EuAndreh" />
	    <meta property="og:site_name" content="$site_name" />
	    <meta property="og:locale"    content="$lang" />
	    <meta property="og:title"     content="$title_html" />

	    <link rel="canonical"      href="$url" />
	    <meta property="og:url" content="$url" />
	  </head>
	  <body>
	    <header>
	      <nav>
	        <ul>
	          <a href="$(url-for "$lang/")">EuAndreh</a>
	          <a href="$(url-for 'about.html')">About</a>
	        </ul>
	      </nav>
	      <hr />
	    </header>
	    <main>
	      <article>
	        \$(emit_body)
	        <hr />
EOF
exit


.md.rehtml:
        F="$<"; . "$${F%.md}.conf"; envsubst < src/lib/reamble."$$lang".html  > $@

.md.osthtml:
        F="$<"; . "$${F%.md}.conf"; envsubst < src/lib/ostamble."$$lang".html > $@


	        <p class="post-footer">
	          <a href="mailto:~euandreh/public-inbox@lists.sr.ht?Subject=Re%3A%20$URI_TITLE">Comment</a>
	          and see
	          <a href="https://lists.sr.ht/~euandreh/public-inbox?search=$URI_TITLE">existing discussions</a>
	          |
	          <a href="https://euandre.org/git/euandre.org/tree/$FILENAME">view source</a>
	        </p>
	      </article>
	    </main>
	    <footer>
	      <hr />
	      <ul>
	        <li>
	          <img class="svg-icon" src="$(url-for 'static/envelope.svg')" alt="a envelope icon representing an email address" />
	          <a href="mailto:$email">$email</a>
	        </li>
	        <li>
	          <img class="svg-icon" src="$(url-for 'static/lock.svg')" alt="a lock icon representing a GPG public key" />
	          <a href="$(url-for 'static/public.asc.txt')">81F90EC3CD356060</a>
	        </li>
	      </ul>
	      <p>
	        The content for this site is licensed under <a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a>.  The <a href="https://euandre.org/git/euandre.org">code</a> is <a rel="license" href="https://euandre.org/git/euandre.org/tree/COPYING">AGPLv3 or later</a>.  Patches welcome.
	      </p>
	    </footer>
	  </body>
	</html>
EOF

# FIXMEs:
# - feeds
# - link to next and/or previous in <head>
# - translation support
# - validate input variables: regex for date (same as _plugins/linter.rb)
# - `date -d` isn't POSIX
# - parse commonmark and use a custom HTML emitter over <pre><code> regex
# - handle mixture of personal scripts
# - sitemap?  How does it even work?
# - dark mode
# - generate security.txt dynamically
# - config.env should depend on dynamic.mk?