~sircmpwn/wersh

c016095548ff57f287489072aeff3b764d6b3233 — Drew DeVault 3 years ago bcc3fba
Add syntax for improved wersh scripts
M README => README +42 -11
@@ 1,23 1,56 @@
wersh

Static site generation with POSIX shell scripts, loosely inspired by werc[1].
Static site generation with POSIX shell scripts, loosely inspired by werc.

USAGE

wersh [-w] [input] [output]

Sources [input]/**.sh and writes the output to [output]/**. Input defaults to ./
and output defaults to _site/.
wersh takes files from input/**.sh, converts them into scripts with wersh.awk,
then sources these scripts to produce output files as output/**. Files that
don't match *.sh are copied directly to the output. Any files or directories
that begin with _ are ignored.

Files that don't match *.sh are copied directly. Files and directories that
match _* are not used.
Files parsed with wersh.awk produce scripts. Any line prefixed with % will be
added to the script, and any line without will be automatically output by the
target script. Run wersh.awk < input > output to get an idea of how it works.

When your script executes, the working directory is set to input.
PREPROCESSING

The special file _config.sh will be sourced for all scripts if present.
You can use a preprocessor to convert script output into some other format. For
example, to convert script output to markdown:

-w will use inotifywait to watch for changes, then automatically recompile your
site. This is only supported on Linux.
% preprocessor="hoedown"

Your script output will be piped into the preprocessor, and its output used as
your script output.

ENVIRONMENT

When your script executes, the working directory is set to the input directory
and the following variables are available:

- root: top level input directory
- input: path to the input file being processed
- output: path to the output file
- outputdir: top level output directory

The wsource function is also available, which behaves like the source builtin,
but it will run the file through wersh.awk first. This is useful for making
templates or including files.

TEMPLATES

The recommended method for making templates is to overwrite the render()
function in the template script and source the template script from any files
that will use it. The render() function is piped the preprocessed script output
and is expected to print the final output. You may use wersh.awk for your
template - any output lines are printed directly during the render() function.

SITE-WIDE CONFIGURATION

If present, the special file _config.sh will be sourced. Note that it will not
be preprocessed by wersh.awk.

EXAMPLES



@@ 27,5 60,3 @@ See example/ for an example wersh site. Run the following:
    lighttpd -Df lighttpd.conf

Then browse to http://localhost:8080 to check out the example site.

[1] http://werc.cat-v.org/

M example/_config.sh => example/_config.sh +10 -4
@@ 1,7 1,3 @@
function hoedown() {
    /usr/bin/hoedown --tables --fenced-code
}

pages="page-one.html.sh page-two.html.sh"

function page_title() {


@@ 14,3 10,13 @@ function page_title() {
            ;;
    esac
}

case $input in
    *.html.sh)
        preprocessor="hoedown --tables --fenced-code"
        wsource _templates/layout.html.sh
        ;;
    *.scss.sh)
        preprocessor="sassc -s -t compressed"
        ;;
esac

M example/_templates/layout.html.sh => example/_templates/layout.html.sh +5 -6
@@ 1,14 1,13 @@
cat <<EOF
% function render() {
<!doctype html>
<html>
  <head>
    <title>${title:-Test site}</title>
% echo "<title>${title:-Test site}</title>"
    <link rel="stylesheet" type="text/css" href="/css/main.css" />
  </head>
  <body>
EOF
content
cat <<EOF
% cat
  </body>
</html>
EOF
% }


M example/css/main.css.sh => example/css/main.css.sh +2 -2
@@ 1,4 1,5 @@
cat <<EOF | sassc -s -t compressed
% # vim: set ft=sass :

html
body {
  max-width: 500px;


@@ 16,4 17,3 @@ img {
    margin: 0 auto;
    max-height: 300px;
}
EOF

M example/index.html.sh => example/index.html.sh +8 -14
@@ 1,24 1,22 @@
function content() {
    cat <<EOF | hoedown
% # vim: set ft=markdown :
# wersh

Static site generation with POSIX shell scripts, loosely inspired by
[werc](http://werc.cat-v.org).

This page is a shell script: [example/index.html.sh](/index.html.sh). Files
ending with *.sh are sourced and their stdout is written to the corresponding output file.
ending with \*.sh are sourced and their stdout is written to the corresponding
output 'file'.

## Pages

Since it's a shell script, you can do pretty much anything you want. This list
of pages is dynamically generated:

EOF
    for page in $pages
    do
        echo "* [$(page_title "$page")](${page%%.sh})" | hoedown
    done
    cat <<EOF | hoedown
% for page in $pages
% do
%   emit "* [$(page_title "$page")](${page%%.sh})"
% done

## Static content



@@ 26,8 24,4 @@ Files that don't end in *.sh are automatically copied into the output
directory, like this one:

![](/images/mio.png)
EOF
}

. _templates/layout.html.sh
cp index.html.sh "$outputdir"/index.html.sh
% cp index.html.sh "$outputdir"/index.html.sh

M example/page-one.html.sh => example/page-one.html.sh +1 -5
@@ 1,10 1,6 @@
function content() {
  cat <<EOF | hoedown
% # vim: set ft=markdown :
# Page one

This is a test page.

[back](/)
EOF
}
. _templates/layout.html.sh

M example/page-two.html.sh => example/page-two.html.sh +1 -5
@@ 1,10 1,6 @@
function content() {
  cat <<EOF | hoedown
% # vim: set ft=markdown :
# Page two

This is a test page.

[back](/)
EOF
}
. _templates/layout.html.sh

M wersh => wersh +29 -3
@@ 6,6 6,7 @@ function usage() {
    exit 1
}

_bin=$(readlink -f $0)
_single=
_watch=
_n=0


@@ 27,20 28,45 @@ do
done
[ $_n -ne 0 ] && shift $_n

function render() {
    cat -
}

function emit() {
    if [ "$_rendering" == "t" ]
    then
        printf "%s\n" "$@"
    else
        content="$content
$@"
    fi
}

function escape() {
    sed -e 's/</\&lt;/g' -e 's/>/\&gt;/g'
}

function wsource() {
    local _file=$(mktemp)
    $(dirname $_bin)/wersh.awk < "$1" > "$_file"
    source "$_file"
    rm "$_file"
}

preprocessor="cat"

if [ -n "$_single" ]
then
    [ $# -ne 4 ] && usage
    root=$(readlink -f $1)
    outputdir=$(readlink -f $2)
    output=$3
    _input=$(readlink -f "$4")
    input=$4
    cd $root
    [ -e "$root"/_config.sh ] && . "$root"/_config.sh
    . "$_input"
    wsource $input
    _rendering=t
    printf "%s" "$content" | $preprocessor | render
elif [ -n "$_watch" ]
then
    [ $# -gt 2 ] && usage


@@ 67,7 93,7 @@ else
        _output=${_output%.sh}
        echo "Generating $_output from $_input"
        mkdir -p $(dirname "$_output")
        $0 -s "$root" "$_outputdir" "$_output" "$_input" > "$_output"
        $0 -s "$root" "$_outputdir" "$_output" "${_input#$root/}" > "$_output"
    done
    find "$root" -type f -not -name "*.sh" -not -path "*/_*/*" -not -name "_*" | \
    while IFS= read -r _input

A wersh.awk => wersh.awk +20 -0
@@ 0,0 1,20 @@
#!/usr/bin/awk -f
BEGIN { mode="line" }
{
    if (mode == "line") {
        if ($0 ~ /^%%%$/) {
            mode="block";
        } else if ($0 ~ /^%.*$/) {
            print substr($0, 3);
        } else {
            gsub(/'/, "'\"'\"'", $0);
            print "emit '" $emit "'";
        }
    } else if (mode == "block") {
        if ($0 ~ /^%%%$/) {
            mode="line";
        } else {
            print $0;
        }
    }
}