#!/bin/sh BASE_URL=https://ieks.cc/ TITLE=ieks.cc AUTHOR='Lucas Ieks' EMAIL=lucas@ieks.cc # TODO handle image links STYLE=' html { font-family: "Helvetica", "Arial", "Nimbus Sans L", sans-serif; background: #181408; color: #eeeeee; } body { max-width: 50rem; margin: 0 auto 25vh; } main { background: #eeeeee; color: #080808; padding: 1rem; } main a { color: darkblue; } @media (prefers-color-scheme: dark) { main { background: inherit; color: inherit; a { color: lightblue; } } } a { color: lightblue; text-decoration: none; } a:hover { color: grey; } h1 a, h2 a, h3 a, sup a { color: inherit; } nav, h1, h2, h3 { margin: 1rem 0; font-variant-caps: small-caps; text-wrap: balanced; } nav { margin-left: 1rem; padding-left: 0; } nav h1 { font-variant-caps: normal; } nav ul { margin: 0; padding: 0; } nav ul a::after { content: "\a0\2192"; } small { font-size: 0.75em; } nav ul, nav ol { list-style-type: none; padding: 0; margin: 0 0.5rem; } h1 { font-size: 2.618rem; } h2 { font-size: 1.618rem; } h3 { font-size: 1rem; } p, div, li, blockquote { line-height: 1.5; text-align: justify; hyphens: auto; text-wrap: pretty; } p { margin: 0; margin-top: 0.75rem; } img { width: 100%; } blockquote { margin: 0.5rem 1rem; } p:first-child, h1:first-child { margin-top: 0; } pre { padding-left: 1rem; line-height: 1.5; overflow-x: auto; } sup { line-height: 0; font-size: 0.618em; } footer { padding: 1rem; } footer p { font-size: 0.618rem; } ' # relpath file dir # slightly adjusted from https://stackoverflow.com/a/14914070 (CC BY-SA 3.0) relpath () { current="${2:+"$1"}" target="${2:-"$1"}" [ "$target" = . ] && target=/ target="/${target##/}" [ "$current" = . ] && current=/ current="${current:="/"}" current="/${current##/}" appendix="${target##/}" relative='' while appendix="${target#"$current"/}" [ "$current" != '/' ] && [ "$appendix" = "$target" ] do if [ "$current" = "$appendix" ]; then relative="${relative:-.}" printf '%s\n' "${relative#/}" return 0 fi current="${current%/*}" relative="$relative${relative:+/}.." done relative="$relative${relative:+${appendix:+/}}${appendix#/}" printf '%s\n' "$relative" } TABLE_OF_CONTENTS=' function esc(i) { gsub(/&/, "\\&", i) gsub(/, "\\<", i) gsub(/>/, "\\>", i) gsub(/"/, "\\"", i) return i } function rep(i) { gsub(/&/, "\\&", i) gsub(/---/, "\\—", i) gsub(/--/, "\\–", i) gsub(/->/, "\\→", i) gsub(/, "\\<", i) gsub(/>/, "\\>", i) gsub(/"/, "\\"", i) return i } BEGIN { print "
"; MODE = "code"; next }
MODE != "list" && /^\*/ { if (MODE == "par") print ""; print ""; MODE = "list" }
/^\*/ {
sub(/^\*[[:space:]]*/, "")
$0 = rep($0)
gsub(/\[[[:lower:]]+\]/, "&")
print "- " $0 "
"
next
}
MODE == "list" { print "
"; MODE = "text" }
/^###/ {
sub(/^###[[:space:]]*/, "")
h3++
LINK = h1 "." h2 "." h3
print "" rep($0) "
"
next
}
/^##[^#]/ { sub(/^##[[:space:]]*/, "")
h2++
h3 = 0
LINK = h1 "." h2
print "" rep($0) "
"
next
}
/^#[^#]/ { sub(/^#[[:space:]]*/, "")
h1++
h2 = 0
LINK = h1
print "" rep($0) "
"
next
}
/^[[:space:]]*$/ { if (MODE == "par") print ""; MODE = "text"; next }
/^>/ {
if (MODE == "par") print ""
sub(/^>[[:space:]]*/, "")
print "" rep($0) "
"
MODE = "text"
next
}
MODE == "par" { print "
" }
MODE == "text" { printf ""; MODE = "par" }
/^\[[[:lower:]]+\]/ {
match($0, /\[[[:lower:]]+\]/)
letter = substr($0, RSTART, RLENGTH)
printf "%s", LINK, letter, rep($0)
next
}
/^---/ { printf "%s", rep($0); next }
/^=>/ && $2 ~ /\.(jpg|png)$/ {
href = esc($2)
sub(/^=>[[:space:]]*[^[:space:]]+[[:space:]]*/, "")
if (match($0, /\[[[:lower:]]+\]/)) {
letter = substr($0, RSTART, RLENGTH)
$0 = "" rep($0) ""
} else if (/^---/) {
$0 = "" rep($0) ""
} else {
$0 = "
"
}
print "" $0 ""
next
}
/^=>/ {
href = esc($2)
if (href !~ /^gemini:\/\//) sub(/\.gmi$/, ".html", href)
sub(/^=>[[:space:]]*[^[:space:]]+[[:space:]]*/, "")
if (match($0, /\[[[:lower:]]+\]/)) {
letter = substr($0, RSTART, RLENGTH)
$0 = "" rep($0) ""
} else if (/^---/) {
$0 = "" rep($0) ""
} else {
$0 = rep($0)
}
print "" $0 ""
next
}
{
$0 = rep($0)
gsub(/\[[[:lower:]]+\]/, "&")
printf "%s", $0
MODE = "par"
}
END { if (MODE == "par") print "
" }
'
rm -rf .out/www .out/gmi
mkdir -p .out/www .out/gmi
find . ! \( -path '*/.*' -prune \) ! \( -name '*.gmi' -o -name '*.html' -o -name '*.css' -o -name '*.js' \) -type f | while read file; do
mkdir -p ".out/gmi/$(dirname "$file")" ".out/www/$(dirname "$file")"
printf 'copy %s\n' "$file" >&2
cp "$file" .out/gmi/"$file"
cp "$file" .out/www/"$file"
done
find . ! \( -path '*/.*' -prune \) -name '*.gmi' -type f | while read file; do
published=$(sed -n 's/^Written:[[:space:]]*//p' "$file")
updated=$(sed -n 's/^Revised:[[:space:]]*//p' "$file")
[ "$updated" ] || updated=$published
[ "$published" ] || [ "$(basename "$file")" = index.gmi ] || continue
mkdir -p ".out/www/$(dirname "$file")" ".out/gmi/$(dirname "$file")"
printf 'gmi %s\n' "$file" >&2
(
printf '=> / %s\n' "$TITLE"
if [ "$(basename "$file")" != index.gmi ]; then
printf '=> index.gmi up\n'
elif [ "$(dirname "$file")" != . ]; then
printf '=> ../ up\n'
fi
printf '\n'
cat "$file"
printf '\nCopyright © %s' "${published%-*-*}"
[ "${published%-*-*}" != "${updated%-*-*}" ] && printf '–%s' "${updated%-*-*}"
printf ' by Lucas Ieks.\n'
printf 'Licensed under CC-BY-SA 4.0, unless stated otherwise.\n'
printf 'Some rights reserved.\n'
) > ".out/gmi/$file"
printf 'www %s\n' "${file%.gmi}.html" >&2
(
lang=$(sed -n 's/^Language:[[:space:]]*//p' "$file")
printf ''
printf '\n'
printf '\n' "$TITLE" "${BASE_URL}atom.xml"
printf '%s \n' "$(sed -n 's/^#[^#][[:space:]]*//p' "$file" | head -1)"
printf '' "$STYLE" "${lang:-en}"
printf ''
printf ''
awk "$BODY" "$file"
printf ' '
printf ''
) > ".out/www/${file%.gmi}.html"
done
find . ! \( -path '*/.*' -prune \) -name '*.html' -type f | while read file; do
mkdir -p ".out/www/$(dirname "$file")"
printf 'copy %s\n' "$file" >&2
cp "$file" .out/www/"$file"
done
(
printf '=> / %s\n\n' "$TITLE"
printf '# %s\n' "$TITLE"
find . ! \( -path '*/.*' -prune \) -name '*.gmi' -type f | while read file; do
published=$(sed -n 's/^Written:[[:space:]]*//p' "$file")
updated=$(sed -n 's/^Revised:[[:space:]]*//p' "$file")
[ "$updated" ] || updated=$published
[ "$published" ] || continue
printf 'gmi feed %s\n' "$file" >&2
url="$(relpath "$PWD" "$(realpath "${file%.gmi}.html")")"
title=$(sed -n 's/^#[^#][[:space:]]*//p' "$file" | head -1)
printf '=> %s %s — %s\n' "$url" "$updated" "$title"
done
) > .out/gmi/feed.gmi
(
printf ''
printf ''
printf '%s ' "$BASE_URL"
printf '%s ' "$TITLE"
printf '%s ' "$(date -Iseconds)"
printf '' "${BASE_URL}atom.xml"
printf ''
printf '%s ' "$AUTHOR"
printf '%s ' "$EMAIL"
printf ' '
printf '%s ' "${BASE_URL}$(relpath "$PWD" "$(realpath "$0")")" "$0"
find . ! \( -path '*/.*' -prune \) -name '*.gmi' -type f | while read file; do
published=$(sed -n 's/^Written:[[:space:]]*//p' "$file")
updated=$(sed -n 's/^Revised:[[:space:]]*//p' "$file")
[ "$updated" ] || updated=$published
url="${BASE_URL}$(relpath "$PWD" "$(realpath "${file%.gmi}.html")")"
[ "$published" ] || continue
printf 'www feed %s\n' "$file" >&2
printf ''
printf '%s ' "$(sed -n 's/^#[^#][[:space:]]*//p' "$file" | head -1)"
printf '' "$url"
printf '%s ' "$url"
printf '%s ' "$(date -Iseconds -d "$published")"
printf '%s ' "$(date -Iseconds -d "$updated")"
printf ' '
done
printf ' '
) > .out/www/atom.xml
cp gmiweb .out/gmi/gmiweb
cp gmiweb .out/www/gmiweb
(
cd .out/www
tar -cz * > ../www.tar.gz
)
(
cd .out/gmi
tar -cz * > ../gmi.tar.gz
)