summaryrefslogtreecommitdiff
path: root/bin/wag
diff options
context:
space:
mode:
Diffstat (limited to 'bin/wag')
-rwxr-xr-xbin/wag288
1 files changed, 288 insertions, 0 deletions
diff --git a/bin/wag b/bin/wag
new file mode 100755
index 0000000..d6e3121
--- /dev/null
+++ b/bin/wag
@@ -0,0 +1,288 @@
+#!/bin/sh
+
+## wag is a tool to generate static web sites
+
+unset CDPATH
+export LC_ALL=C IFS='
+'
+
+cmd=$(command -v "$0")
+
+## help prints this program documentation
+help() { awk '/^## / {print substr($0, 4)}' "$cmd"; }
+
+lipsum='Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
+nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
+reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
+pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
+culpa qui officia deserunt mollit anim id est laborum.'
+
+# An overly simplified http request parser for static web sites.
+http_request() {
+ read -r cmd uri proto
+ case $uri in */) uri="${uri}index.html" ;; esac
+ while true; do
+ read -r line || break
+ [ ${#line} = 0 ] && break
+ done
+ printf 'HTTP/1.1 200 OK\n\n' && cat "${uri#/}"
+}
+
+md2h() { want="$2" got=$(echo "$1" | md2html -); }
+
+md2html() {
+ tmp=$(mktemp -u)
+ trap "rm -f '$tmp'" EXIT
+ {
+ cat "${1:--}" | tee "$tmp" | awk '/^[ ]*\[[^]]+\]:/'
+ cat "$tmp"
+ } |
+ awk '
+ function newblock(nblock) {
+ if (text)
+ print "<" block ">" text "</" block ">"
+ text = ""
+ out = 1
+ block = nblock ? nblock : "p"
+ }
+
+ function subinline(tgl, inl) {
+ while (match($0, tgl)) {
+ if (inline[ni] == inl)
+ ni -= sub(tgl, "</" inl ">")
+ else if (sub(tgl, "<" inl ">"))
+ inline[++ni] = inl
+ }
+ }
+
+ function dolink(href, lnk) {
+ # Undo escaped html in uris
+ gsub(/&amp;/, "\\&", href)
+ gsub(/&lt;/, "<", href)
+ gsub(/&gt;/, ">", href)
+ # & can be tricky, and not standard:
+ gsub(/&/, "\\\\\\&", href)
+ gsub(/&/, "\\\\\\&", lnk)
+ return "<a href=\"" href "\">" lnk "</a>"
+ }
+
+ BEGIN {
+ ni = 0 # inlines
+ nl = 0 # nested lists
+ out = 0 # 0 if no output so far
+ text = ""
+ block = "p"
+ }
+
+ # Skip front matter.
+ out == 0 && $0 == "---" {
+ do
+ getline
+ while ($0 != "---")
+ next
+ }
+
+ # Escape HTML.
+ esc != "false" {
+ gsub("&", "\\&amp;")
+ gsub("<", "\\&lt;")
+ gsub(">", "\\&gt;")
+ }
+
+ # Internal references.
+ match($0, /^[ ]*\[[^]]+\]:/) > 0 {
+ k = substr($0, RSTART+1, RLENGTH-3)
+ v = substr($0, RLENGTH+1)
+ sub(/^[ ]/, "", v)
+ sub(/[ ]$/, "", v)
+ ref[substr($0, RSTART+1, RLENGTH-3)] = v
+ next
+ }
+
+ # Horizontal rules.
+ /^[ ]*([-*_] ?)+[ ]*$/ && text == "" {
+ print "<hr>"
+ next
+ }
+
+ # Tables. Syntax:
+ # Right Align| Center Align |Left Align
+ /([ ]\|)|(\|[ ])/ {
+ if (block != "table")
+ newblock("table")
+ nc = split($0, cells, "|")
+ $0 = "<tr>\n"
+ for (i = 1; i <= nc; i++) {
+ align = "left"
+ if (sub(/^[ ]+/, "", cells[i])) {
+ if (sub(/[ ]+$/, "", cells[i]))
+ align = "center"
+ else
+ align = "right"
+ }
+ sub(/[ ]+$/, "", cells[i])
+ $0 = $0 "<td align=\"" align "\">" cells[i] "</td>\n"
+ }
+ $0 = $0 "</tr>"
+ }
+
+ # Ordered and unordered (possibly nested) lists.
+ /^[ ]*([*+-]|(([0-9]+[.-]?)+))[ ]/ {
+ newblock("li")
+ nnl = 1
+ while (match($0, /^[ ]/)) {
+ sub(/^[ ]/, "")
+ nnl++
+ }
+ while (nl > nnl)
+ print "</" list[nl--] ">"
+ while (nl < nnl) {
+ list[++nl] = "ol"
+ if (match($0, /^[*+-]/))
+ list[nl] = "ul"
+ print "<" list[nl] ">"
+ }
+ sub(/^([*+-]|(([0-9]+[.-]?)+))[ ]/, "")
+ }
+
+ # Multi line list items.
+ block == "li" {
+ sub(/^( *)|( *)/, "")
+ }
+
+ # Code blocks.
+ /^( | )/ {
+ if (block != "code")
+ newblock("code")
+ sub(/^( | )/, "")
+ text = text $0 "\n"
+ next
+ }
+
+ # Paragraphs.
+ /^$/ {
+ newblock()
+ while (nl > 0)
+ print "</" list[nl--] ">"
+ }
+
+ # Headers.
+ /^#+ / {
+ newblock()
+ match($0, /#+/)
+ n = RLENGTH
+ if (n > 6)
+ n = 6
+ text = substr($0, RLENGTH + 1)
+ sub(/^ */, "", text)
+ block = "h" n
+ next
+ }
+
+ # Alternate headers (underlined).
+ /^=+$/ {
+ block = "h" 1
+ next
+ }
+
+ /^-+$/ {
+ block = "h" 2
+ next
+ }
+
+ {
+ # Images.
+ while (match($0, /!\[[^]]+\]\([^)]+\)/)) {
+ split(substr($0, RSTART, RLENGTH), a, /(!\[)|\)|(\]\()/)
+ sub(/!\[[^]]+\]\([^)]+\)/, "<img src=\"" a[3] "\" alt=\"" a[2] "\">")
+ }
+ # Links.
+ while (match($0, /\[[^]]+\]\([^)]+\)/)) {
+ split(substr($0, RSTART, RLENGTH), a, /[[)]|(\]\()/)
+ sub(/\[[^]]+\]\([^)]+\)/, dolink(a[3], a[2]))
+ }
+ # Internal references.
+ while (match($0, /\[[^]]+\]/)) {
+ k = substr($0, RSTART+1, RLENGTH-2)
+ sub(/\[[^]]+\]/, dolink(ref[k], k))
+ }
+ # Auto links (uri matching is poor).
+ na = split($0, a, /(^\()|[ ]|([,.)]([ ]|$))/)
+ for (i = 1; i <= na; i++)
+ if (match(a[i], /^(((https?|ftp|file|news|irc):\/\/)|(mailto:)).+$/))
+ sub(a[i], dolink(a[i], a[i]))
+ # Inline.
+ subinline("(\\*\\*)|(__)", "strong")
+ subinline("\\*", "em")
+ subinline("`", "code")
+ text = text (text ? " " : "") $0
+ }
+
+ END {
+ while (ni > 0)
+ text = text "</" inline[ni--] ">"
+ newblock()
+ while (nl > 0)
+ print "</" list[nl--] ">"
+ }'
+}
+
+serve() { while true; do nc -l -p 1500 -e "$cmd http_request"; done; }
+
+test() {
+ fail=0 pass=0 skip=0 tfilter="$*"
+
+ test_run md2h 'abc __def__ ghi' '<p>abc <strong>def</strong> ghi</p>'
+ test_run md2h 'abc **def** ghi' '<p>abc <strong>def</strong> ghi</p>'
+ test_run md2h 'abc *def* ghi' '<p>abc <em>def</em> ghi</p>'
+ test_run md2h 'abc ***def*** ghi' '<p>abc <strong><em>def</strong></em> ghi</p>'
+ test_run md2h 'abc `def` ghi' '<p>abc <code>def</code> ghi</p>'
+ test_run md2h '# h1' '<h1>h1</h1>'
+ test_run md2h '## h2' '<h2>h2</h2>'
+ test_run md2h 'h1
+==' '<h1>h1</h1>'
+ test_run md2h 'h2
+--' '<h2>h2</h2>'
+ test_run md2h 'abc [github] def' '<p>abc <a href="">github</a> def</p>'
+ test_run md2h 'abc [github](https://github.com) def' '<p>abc <a href="https://github.com">github</a> def</p>'
+ test_run md2h 'abc [github] def
+
+[github]: https://github.com' '<p>abc <a href="https://github.com">github</a> def</p>'
+ test_run md2h '---
+Title: front matter test
+---
+
+Hello [world].
+
+---
+Bye.
+
+[world]: http://example.com' '<p>Hello <a href="http://example.com">world</a>.</p>
+<hr>
+<p>Bye.</p>'
+
+ echo "Total: $((pass + fail + skip)), Passed: $pass, Failed: $fail, Skip: $skip"
+ return "$fail"
+}
+
+test_run() {
+ eval "test_$1=\$((test_$1 + 1)); ti=\"\$test_$1\""
+ [ "$tfilter" ] &&
+ case "$1#$ti" in
+ $tfilter) ;;
+ *) skip=$((skip + 1)); return 0 ;;
+ esac
+ "$@"
+ [ "$got" = "$want" ] && {
+ pass=$((pass + 1))
+ return 0
+ }
+ fail=$((fail + 1))
+ printf "%s FAIL\n Got: %s\n Want: %s\n" "$1#$ti" "$got" "$want" >&2
+ return 1
+}
+
+# Execute command line
+[ "$1" ] || help && "$@"