about summary refs log tree commit diff stats
path: root/ht.sh
blob: 9c3302f03e5bd3c7a1cb94044fb236a6e86eb839 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/bin/sh
# HAT TRICK
# (C) 2022 C. Duckworth

[ "x$DEBUG" = "xYES" ] && set -x

: "${HTDAT:=$(date +%s)}"
: "${HTTMP:=/tmp/ht}"; mkdir -p "$HTTMP"
: "${HTENV:=$HTTMP/env-$HTDAT.sh}"
: "${HTBOD:=$HTTMP/bod-$HTDAT.txt}"
export HTDAT HTTMP HTENV HTBOD

HT_TMPL_COUNT=1
HT_TMPL_PRE=:

print() { # print STRING...
    ## A sane version of `echo`.
    printf '%s\n' "$*"
}

htt() { # htt FILES...
    # Like `cat`, but with templating.
    ht_end="ht_main_$HTDAT_$HT_TMPL_COUNT" # be extra double sure
    eval "$(print "cat <<$ht_end"; cat "$@"; print; print "$ht_end")"
    HT_TMPL_COUNT=$(expr $HT_TMPL_COUNT + 1)
}

ht_build_env() { # ht_build_env FILE...
    print "body() { cat \"$HTBOD\"; }" > "$HTENV"
    : > "$HTBOD"; # clear out body
    while read -r line; do
        case "$line" in
            *@@*:*@@*) # "simple" metadata; just a string
                print "$line" |
                    sed 's/.*@@\([^:]*\): \?\(.*\)@@.*/\1() { print "\2"; }/'
                ;;
            *@@*::*@@*) # "complex" metadata: can be anything
                print "$line" |
                    sed 's/.*@@\([^:]*\):: \?\(.*\)@@.*/\1() { \2 ; }/'
                ;;
        esac >> "$HTENV"
        # Still print the line to the body (no need to escape or w/e)
        print "$line" >> "$HTBOD"
    done
    env | grep '^HT' | sort | uniq >> "$HTENV"
}

ht_main() { # main TEMPLATE < INPUT
    ## Apply TEMPLATE to INPUT and print it.
    # TEMPLATE will be interpreted as a heredoc.
    if [ $# -eq 0 ]; then
        print "ht.sh TEMPLATE < INPUT" >&2
        exit 1
    fi

    eval "ht_build_env; . \"$HTENV\"; print \"\$(htt \"\$@\")\";";
}

# To keep this POSIX-compliant, we can't use a bashism like
# [[ "$0" == # "$BASH_SOURCE[0]" ]].  However, there are still ways to guess
# whether the user is sourcing this file as a library or executing it as a
# script.

case "$0" in
    *ht.sh) ht_main "$@" ;;
    *) print "Sourcing ht.sh" ;;
esac