Libraryize
This commit is contained in:
parent
1e7913665b
commit
ce40a9da27
|
@ -0,0 +1,80 @@
|
|||
#!/bin/sh
|
||||
# hell - HTML in shell
|
||||
|
||||
tx()
|
||||
{
|
||||
: "${RAW:=false}"
|
||||
|
||||
if "$RAW"; then
|
||||
printf '%b\n' "$*"
|
||||
return
|
||||
fi
|
||||
|
||||
while
|
||||
[ "$#" -gt 0 ] && printf %s "$1"
|
||||
do
|
||||
[ "$#" -gt 1 ] && printf ' '
|
||||
shift
|
||||
done
|
||||
printf '\n'
|
||||
}
|
||||
|
||||
el()
|
||||
{ # el NAME [ATTR=VALUE...] [-] [TEXT...]
|
||||
el="$1"; shift
|
||||
READ_IN=true
|
||||
text=
|
||||
attr=
|
||||
class=
|
||||
|
||||
for word; do
|
||||
case "$word" in
|
||||
\\*) # words starting with backslashes are text
|
||||
text="$text${text:+ }${word#\\}"
|
||||
;;
|
||||
class=*) # otherwise, 'class=' is a special case
|
||||
class="${class:-class=\"}${class:+ }${word#class=}"
|
||||
;;
|
||||
*=*) # otherwise, words containing an equals are attr=value pairs
|
||||
anam="${word%=*}"
|
||||
aval="${word#*=}"
|
||||
aval="${aval%\"}"
|
||||
aval="${aval#\"}"
|
||||
attr="$attr${attr:+ }${anam}=\"${aval}\""
|
||||
;;
|
||||
-) # otherwise, '-' denotes stdin
|
||||
"$READ_IN" &&
|
||||
while IFS= read -r line; do
|
||||
text="$text${text:+
|
||||
}$line" # this is very ugly but it works
|
||||
done
|
||||
;;
|
||||
/) # close-tag flag: don't look for text from stdin
|
||||
READ_IN=false
|
||||
;;
|
||||
*) # otherwise, it's text
|
||||
text="$text${text:+ }$word"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# close out the class string
|
||||
if [ -n "$class" ]; then
|
||||
class="$class\""
|
||||
attr="$attr${attr:+ }$class"
|
||||
fi
|
||||
|
||||
# if there's no text, try reading from stdin
|
||||
if [ -z "$text" ] && "$READ_IN"; then
|
||||
while IFS= read -r line; do
|
||||
text="$text${text:+
|
||||
}$line" # this is very ugly but it works
|
||||
done
|
||||
fi
|
||||
|
||||
# print the thing
|
||||
printf '<%s%s>%s' "$el" "${attr:+ }$attr" "$text"
|
||||
# if there's text, close the tag
|
||||
[ -n "$text" ] && printf '</%s>' "$el"
|
||||
printf '\n'
|
||||
}
|
244
hell.sh
244
hell.sh
|
@ -1,244 +0,0 @@
|
|||
#!/bin/sh
|
||||
# hell - HTML in shell
|
||||
# (c) 2020 Case Duckworth <acdw at acdw dot net>
|
||||
# License: MIT
|
||||
# v.0.0.2 (codename WHY AM I DOING THIS?)
|
||||
#
|
||||
# This file is part of _hawkish_, an ssg made of shell, awk, and Makefiles
|
||||
# (maybe). As POSIX as possible. For fun and non-profit.
|
||||
# Maybe I could rename this Saitama: I'm a build system for fun!
|
||||
# ANYWAY:
|
||||
# This file is meant to be sourced by the eventual generated sh script.
|
||||
# It will define functions that the generated script will use to generate
|
||||
# HTML.
|
||||
# The generated sh script will be generated by an intermediary awk script that
|
||||
# transforms input text files into a shab(github.com/zimbatm/shab)-like file,
|
||||
# which will be run to output the HTML.
|
||||
|
||||
[ -n "$DEBUG" ] && set -x
|
||||
|
||||
# implement die (TODO: put this in a util file?)
|
||||
die()
|
||||
{
|
||||
case "$#" in
|
||||
1) echo "$1"; exit 1 ;;
|
||||
*) ec="$1"; shift; echo "$@"; exit "$ec" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
||||
# First things first - define how to cleanly exit.
|
||||
cleanup()
|
||||
{
|
||||
rm "$BLOCKS" "$INLINES"
|
||||
}
|
||||
trap cleanup INT QUIT TERM EXIT
|
||||
|
||||
|
||||
# BLOCKS holds all open block-level elements so that we can close them like good
|
||||
# little children.
|
||||
BLOCKS="$(mktemp hell-blocks.XXXXXX)"
|
||||
# INLINES is the same, but for inlines.
|
||||
INLINES="$(mktemp hell-inlines.XXXXXX)"
|
||||
|
||||
# You can push tags to the stack or pop them.
|
||||
# Note: these only deal with tag NAMEs (e.g. 'p', 'h1', etc.). The actual TAGs
|
||||
# ('<h1 class=whatever>', etc.) are left up to the caller.
|
||||
# These only deal with one line at a time right now. I think that's best.
|
||||
push()
|
||||
{ # push FILE VALUE
|
||||
# returns: VALUE
|
||||
stack="$1"
|
||||
#shift
|
||||
|
||||
printf '%s\n' "$2" >> "$stack"
|
||||
}
|
||||
|
||||
# see unix.stackexchange.com/questions/474838
|
||||
pop()
|
||||
{ # pop FILE
|
||||
# returns: popped VALUE
|
||||
# shellcheck disable=2034
|
||||
LC_TYPE=C
|
||||
stack="$1"
|
||||
#shift
|
||||
|
||||
l="$(tail -n1 "$stack"; echo t)"
|
||||
[ "$l" = t ] && return 1
|
||||
l="${l%t}"
|
||||
# TODO: make sure truncate(1) is available most places
|
||||
truncate -s "-${#l}" "$stack"
|
||||
printf '%s' "$l"
|
||||
}
|
||||
|
||||
# common function for block() and inline().
|
||||
# consider: parsing 'tag.class#id.class[attr=attr]' type lines
|
||||
# or just what it is now, i.e. 'attr=value attr=value text text'
|
||||
parseterms()
|
||||
{ # parseterms [attr=VALUE] [TEXT]
|
||||
: "${attr:=}"
|
||||
: "${text:=}"
|
||||
class=""
|
||||
for term; do
|
||||
case "$term" in
|
||||
\\*) # if it starts with a backslash, include it in text
|
||||
text="$text ${term#\\}"
|
||||
;;
|
||||
class=*) # if it's a class, add it to the class string
|
||||
# TODO: any other attrs to do this with?
|
||||
if [ -z "$class" ]; then
|
||||
class="class=\"${term#\class=}"
|
||||
else
|
||||
class="$class ${term#\class=}"
|
||||
fi
|
||||
;;
|
||||
*=*) # if it has an equal, it's an attribute
|
||||
name="${term%=*}"
|
||||
value="${term#*=}"
|
||||
attr="$attr $name=\"$value\""
|
||||
;;
|
||||
*) # otherwise, it's text
|
||||
if [ -z "$text" ]; then
|
||||
text="$term"
|
||||
else
|
||||
text="$text $term"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [ -n "$class" ]; then
|
||||
class="$class\""
|
||||
attr="$attr $class"
|
||||
fi
|
||||
}
|
||||
|
||||
# create a new tag.
|
||||
# it won't auto-close unless the name ends with '/'.
|
||||
tag()
|
||||
{ # tag <-i|-b> TAG[/] [ATTR=VALUE...] [TEXT...]
|
||||
autoclose=false
|
||||
attr=""
|
||||
text=""
|
||||
|
||||
case "$1" in
|
||||
-i) # inline
|
||||
tagstack="$INLINES"
|
||||
shift
|
||||
;;
|
||||
-b) # block
|
||||
tagstack="$BLOCKS"
|
||||
shift
|
||||
;;
|
||||
*) # other -- default to block
|
||||
tagstack="$BLOCKS"
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$1" in
|
||||
*/) # set this tag to auto-close. don't push it onto the stack.
|
||||
autoclose=true
|
||||
tag="${1%/}"
|
||||
;;
|
||||
*) # begin a tag and push it onto the stack.
|
||||
tag="$1"
|
||||
push "$tagstack" "$tag"
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
parseterms "$@" # parse the rest of the arguments
|
||||
|
||||
if "$autoclose" && [ -z "$text" ]; then
|
||||
# Okay, here's an ugly bit of HTML.
|
||||
# APPARENTLY, with "void elements" or "foreign elements" we *can* use a slash to end an
|
||||
# empty tag, but only with those. Otherwise, it's an error (apparently
|
||||
# in HTML4 it's ALL an error, but W3C validates it fine. ufgghh...
|
||||
case "$tag" in
|
||||
area|base|br|col|embed|hr|img|input|link|meta|\
|
||||
param|source|track|wbr|command|keygen|menuitem)
|
||||
# void elements
|
||||
printf '<%s%s />' "$tag" "$attr"
|
||||
return
|
||||
;;
|
||||
# TODO: add mathml & svg ... maybe.
|
||||
*) : ;; # do nothing - I'll open and close the tag below.
|
||||
esac
|
||||
fi
|
||||
|
||||
# open the tag and add whatever text we've provided
|
||||
printf '<%s%s>%s' "$tag" "$attr" "${text:- }"
|
||||
|
||||
# close the tag if asked
|
||||
if "$autoclose"; then
|
||||
printf '</%s>' "$tag"
|
||||
fi
|
||||
printf '\n'
|
||||
}
|
||||
|
||||
|
||||
# end something
|
||||
end()
|
||||
{ # end [-b] [-t TAG] [-n NUMBER]
|
||||
while getopts t:n:ba OPT; do
|
||||
case "$OPT" in
|
||||
t) # end upto tag -- close tags up to and including TAG
|
||||
target="$OPTARG"
|
||||
while : ; do
|
||||
tag="$(pop "$INLINES")" || break # fall through to BLOCKS
|
||||
printf '</%s>' "$tag"
|
||||
[ "$tag" = "$target" ] && return 0 # found the thing!
|
||||
done
|
||||
while : ; do
|
||||
tag="$(pop "$BLOCKS")" || return 1 # didn't find target
|
||||
printf '</%s>\n' "$tag"
|
||||
[ "$tag" = "$target" ] && return 0 # found the thing!
|
||||
done
|
||||
;;
|
||||
n) # end NUMBER of tags
|
||||
n="$OPTARG"
|
||||
;;
|
||||
b) # end up to the nearest block -- a special case of -n
|
||||
i="$(wc -l < "$INLINES")"
|
||||
n=$((i+1))
|
||||
;;
|
||||
a) # end all tags -- another special case of -n
|
||||
i="$(wc -l < "$INLINES")"
|
||||
b="$(wc -l < "$BLOCKS")"
|
||||
n=$((i+b+1))
|
||||
;;
|
||||
\?) # bad OPTARG
|
||||
return 2
|
||||
;;
|
||||
*) # bad OPT
|
||||
return 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# -n case
|
||||
while [ "$n" -gt 0 ]; do
|
||||
tag="$(pop "$INLINES")" || break # fall through to BLOCKS
|
||||
printf '</%s>' "$tag"
|
||||
n=$((n-1))
|
||||
done
|
||||
while [ "$n" -gt 0 ]; do
|
||||
tag="$(pop "$BLOCKS")" || return 1 # exhausted tags before NUMBER
|
||||
printf '</%s>\n' "$tag"
|
||||
n=$((n-1))
|
||||
done
|
||||
}
|
||||
|
||||
# text is just a regular line of text.
|
||||
# no error checking is done on where the text is going to be --
|
||||
# it just prints it. (this is a less-error-prone `echo`.)
|
||||
text()
|
||||
{ # text [TEXT...]
|
||||
if [ "$#" -gt 0 ]; then
|
||||
printf '%s' "$1"
|
||||
shift
|
||||
if [ "$#" -gt 0 ]; then
|
||||
printf ' %s' "$@"
|
||||
fi
|
||||
fi
|
||||
printf '\n'
|
||||
}
|
13
test.hell
13
test.hell
|
@ -1,13 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
. ./hell.sh
|
||||
|
||||
tag -b article
|
||||
tag -b header
|
||||
tag -b h1/ class=title "Here is a sample title"
|
||||
|
||||
tag -b p "Here's a paragraph. It's going to be pretty basic"
|
||||
text "but hopefully it'll work out well. I need to quote"
|
||||
text "the arguments so that quotes and shit don't have problems."
|
||||
text "I wonder if exclamation points (!) will cause any issues."
|
||||
end -a
|
Loading…
Reference in New Issue