commit f5f491059254241520cf4cfd52b7f9b74ebf1ebd Author: Roi Martin (@nibble_ds) Date: Thu Feb 6 10:54:27 2014 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1377554 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3f241a5 --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +# sw - suckless webframework - 2012 - MIT License - nibble + +DESTDIR?= +PREFIX?=/usr/local +P=${DESTDIR}/${PREFIX} + +all: sw.conf + +sw.conf: + cp sw.conf.def sw.conf + +install: + mkdir -p ${P}/bin + sed -e "s,/usr/bin/awk,`./whereis awk`,g" md2html.awk > ${P}/bin/md2html.awk + chmod +x ${P}/bin/md2html.awk + cp -f sw ${P}/bin/sw + chmod +x ${P}/bin/sw diff --git a/README b/README new file mode 100644 index 0000000..11c3db7 --- /dev/null +++ b/README @@ -0,0 +1,40 @@ +sw - suckless webframework +========================== +sw is a minimal and sane web framework. + +Installation +------------ +Run: + make && make install PREFIX=/usr/local + +Configuration +------------- +Copy sw.conf and style.css to your working directory, and edit them to fit your needs. + +Static web generation +--------------------- +Run from your working directory: + sw /path/to/site + +Where 'site' is the folder where your website is located. +The static version of the website is created under 'site.static'. + +Automatic generation+upload +--------------------------- +The whole process can be automatized if you create a Makefile like this in your working directory: + +$ cat Makefile +all: + sw /path/to/site + rsync -avz site.static/ foo.org:/path/to/wwwroot/ +clean: + rm -rf site.static + +Author +------ +Nibble + +Contributors +------------ +pancake +Andrew Antle diff --git a/md2html.awk b/md2html.awk new file mode 100755 index 0000000..6ab84bf --- /dev/null +++ b/md2html.awk @@ -0,0 +1,427 @@ +#!/usr/bin/awk -f +# +# by: Jesus Galan (yiyus) 2009 +# +# Usage: md2html.awk file.md > file.html +# See: http://4l77.com/src/md2html.awk + +function eschtml(t) { + gsub("&", "\\&", t); + gsub("<", "\\<", t); + return t; +} + +function oprint(t){ + if(nr == 0) + print t; + else + otext = otext "\n" t; +} + +function subref(id){ + for(; nr > 0 && sub("<<" id, ref[id], otext); nr--); + if(nr == 0 && otext) { + print otext; + otext = ""; + } +} + +function nextil(t) { + if(!match(t, /[`<&\[*_\\-]|(\!\[)/)) + return t; + t1 = substr(t, 1, RSTART - 1); + tag = substr(t, RSTART, RLENGTH); + t2 = substr(t, RSTART + RLENGTH); + if(ilcode && tag != "`") + return eschtml(t1 tag) nextil(t2); + # Backslash escaping + if(tag == "\\"){ + if(match(t2, /^[\\`*_{}\[\]()#+\-\.!]/)){ + tag = substr(t2, 1, 1); + t2 = substr(t2, 2); + } + return t1 tag nextil(t2); + } + # Dashes + if(tag == "-"){ + if(sub(/^-/, "", t2)) + tag = "—"; + return t1 tag nextil(t2); + } + # Inline Code + if(tag == "`"){ + if(sub(/^`/, "", t2)){ + if(!match(t2, /``/)) + return t1 "”" nextil(t2); + ilcode2 = !ilcode2; + } + else if(ilcode2) + return t1 tag nextil(t2); + tag = ""; + if(ilcode){ + t1 = eschtml(t1); + tag = ""; + } + ilcode = !ilcode; + return t1 tag nextil(t2); + } + if(tag == "<"){ + # Autolinks + if(match(t2, /^[^ ]+[\.@][^ ]+>/)){ + url = eschtml(substr(t2, 1, RLENGTH - 1)); + t2 = substr(t2, RLENGTH + 1); + linktext = url; + if(match(url, /@/) && !match(url, /^mailto:/)) + url = "mailto:" url; + return t1 "" linktext "" nextil(t2); + } + # Html tags + if(match(t2, /^[A-Za-z\/!][^>]*>/)){ + tag = tag substr(t2, RSTART, RLENGTH); + t2 = substr(t2, RLENGTH + 1); + return t1 tag nextil(t2); + } + return t1 "<" nextil(t2); + } + # Html special entities + if(tag == "&"){ + if(match(t2, /^#?[A-Za-z0-9]+;/)){ + tag = tag substr(t2, RSTART, RLENGTH); + t2 = substr(t2, RLENGTH + 1); + return t1 tag nextil(t2); + } + return t1 "&" nextil(t2); + } + # Images + if(tag == "!["){ + if(!match(t2, /(\[.*\])|(\(.*\))/)) + return t1 tag nextil(t2); + match(t2, /^[^\]]*/); + alt = substr(t2, 1, RLENGTH); + t2 = substr(t2, RLENGTH + 2); + if(match(t2, /^\(/)){ + # Inline + sub(/^\(/, "", t2); + match(t2, /^[^\)]+/); + url = eschtml(substr(t2, 1, RLENGTH)); + t2 = substr(t2, RLENGTH + 2); + title = ""; + if(match(url, /[ ]+\".*\"[ ]*$/)) { + title = substr(url, RSTART, RLENGTH); + url = substr(url, 1, RSTART - 1); + match(title, /\".*\"/); + title = " title=\"" substr(title, RSTART + 1, RLENGTH - 2) "\""; + } + if(match(url, /^<.*>$/)) + url = substr(url, 2, RLENGTH - 2); + return t1 "\""" nextil(t2); + } + else{ + # Referenced + sub(/^ ?\[/, "", t2); + id = alt; + if(match(t2, /^[^\]]+/)) + id = substr(t2, 1, RLENGTH); + t2 = substr(t2, RLENGTH + 2); + if(ref[id]) + r = ref[id]; + else{ + r = "<<" id; + nr++; + } + return t1 "\""" nextil(t2); + } + } + # Links + if(tag == "["){ + if(!match(t2, /(\[.*\])|(\(.*\))/)) + return t1 tag nextil(t2); + match(t2, /^[^\]]*(\[[^\]]*\][^\]]*)*/); + linktext = substr(t2, 1, RLENGTH); + t2 = substr(t2, RLENGTH + 2); + if(match(t2, /^\(/)){ + # Inline + match(t2, /^[^\)]+(\([^\)]+\)[^\)]*)*/); + url = substr(t2, 2, RLENGTH - 1); + pt2 = substr(t2, RLENGTH + 2); + title = ""; + if(match(url, /[ ]+\".*\"[ ]*$/)) { + title = substr(url, RSTART, RLENGTH); + url = substr(url, 1, RSTART - 1); + match(title, /\".*\"/); + title = " title=\"" substr(title, RSTART + 1, RLENGTH - 2) "\""; + } + if(match(url, /^<.*>$/)) + url = substr(url, 2, RLENGTH - 2); + url = eschtml(url); + return t1 "" nextil(linktext) "" nextil(pt2); + } + else{ + # Referenced + sub(/^ ?\[/, "", t2); + id = linktext; + if(match(t2, /^[^\]]+/)) + id = substr(t2, 1, RLENGTH); + t2 = substr(t2, RLENGTH + 2); + if(ref[id]) + r = ref[id]; + else{ + r = "<<" id; + nr++; + } + pt2 = t2; + return t1 "" nextil(linktext) "" nextil(pt2); + } + } + # Emphasis + if(match(tag, /[*_]/)){ + ntag = tag; + if(sub("^" tag, "", t2)){ + if(stag[ns] == tag && match(t2, "^" tag)) + t2 = tag t2; + else + ntag = tag tag + } + n = length(ntag); + tag = (n == 2) ? "strong" : "em"; + if(match(t1, / $/) && match(t2, /^ /)) + return t1 tag nextil(t2); + if(stag[ns] == ntag){ + tag = "/" tag; + ns--; + } + else + stag[++ns] = ntag; + tag = "<" tag ">"; + return t1 tag nextil(t2); + } +} + +function inline(t) { + ilcode = 0; + ilcode2 = 0; + ns = 0; + + return nextil(t); +} + +function printp(tag) { + if(!match(text, /^[ ]*$/)){ + text = inline(text); + if(tag != "") + oprint("<" tag ">" text ""); + else + oprint(text); + } + text = ""; +} + +BEGIN { + blank = 0; + code = 0; + hr = 0; + html = 0; + nl = 0; + nr = 0; + otext = ""; + text = ""; + par = "p"; +} + +# References +!code && /^ *\[[^\]]*\]:[ ]+/ { + sub(/^ *\[/, ""); + match($0, /\]/); + id = substr($0, 1, RSTART - 1); + sub(id "\\]:[ ]+", ""); + title = ""; + if(match($0, /\".*\"$/)) + title = "\" title=\"" substr($0, RSTART + 1, RLENGTH - 2); + sub(/[ ]+\".*\"$/, ""); + url = eschtml($0); + ref[id] = url title; + + subref(id); + next; +} + +# html +!html && /^<(address|blockquote|center|dir|div|dl|fieldset|form|h[1-6r]|\ +isindex|menu|noframes|noscript|ol|p|pre|table|ul|!--)/ { + if(code) + oprint(""); + for(; !text && block[nl] == "blockquote"; nl--) + oprint(""); + match($0, /^<(address|blockquote|center|dir|div|dl|fieldset|form|h[1-6r]|\ + isindex|menu|noframes|noscript|ol|p|pre|table|ul|!--)/); + htag = substr($0, 2, RLENGTH - 1); + if(!match($0, "(<\\/" htag ">)|((^
$)")) + html = 1; + if(html && match($0, /^
$/ || +(hr && />$/)) { + html = 0; + hr = 0; + oprint($0); + next; +} + +html { + oprint($0); + next; +} + +# List and quote blocks + +# Remove indentation +{ + for(nnl = 0; nnl < nl; nnl++) + if((match(block[nnl + 1], /[ou]l/) && !sub(/^( | )/, "")) || \ + (block[nnl + 1] == "blockquote" && !sub(/^> ?/, ""))) + break; +} +nnl < nl && !blank && text && ! /^ ? ? ?([*+-]|([0-9]+\.)+)( +| )/ { nnl = nl; } +# Quote blocks +{ + while(sub(/^> /, "")) + nblock[++nnl] = "blockquote"; +} +# Horizontal rules +{ hr = 0; } +(blank || (!text && !code)) && /^ ? ? ?([-*_][ ]*)([-*_][ ]*)([-*_][ ]*)+$/ { + if(code){ + oprint(""); + code = 0; + } + blank = 0; + nnl = 0; + hr = 1; +} +# List items +block[nl] ~ /[ou]l/ && /^$/ { + blank = 1; + next; +} +{ newli = 0; } +!hr && (nnl != nl || !text || block[nl] ~ /[ou]l/) && /^ ? ? ?[*+-]( +| )/ { + sub(/^ ? ? ?[*+-]( +| )/, ""); + nnl++; + nblock[nnl] = "ul"; + newli = 1; +} +(nnl != nl || !text || block[nl] ~ /[ou]l/) && /^ ? ? ?([0-9]+\.)+( +| )/ { + sub(/^ ? ? ?([0-9]+\.)+( +| )/, ""); + nnl++; + nblock[nnl] = "ol"; + newli = 1; +} +newli { + if(blank && nnl == nl && !par) + par = "p"; + blank = 0; + printp(par); + if(nnl == nl && block[nl] == nblock[nl]) + oprint("
  • "); +} +blank && ! /^$/ { + if(match(block[nnl], /[ou]l/) && !par) + par = "p"; + printp(par); + par = "p"; + blank = 0; +} + +# Close old blocks and open new ones +nnl != nl || nblock[nl] != block[nl] { + if(code){ + oprint(""); + code = 0; + } + printp(par); + b = (nnl > nl) ? nblock[nnl] : block[nnl]; + par = (match(b, /[ou]l/)) ? "" : "p"; +} +nnl < nl || (nnl == nl && nblock[nl] != block[nl]) { + for(; nl > nnl || (nnl == nl && pblock[nl] != block[nl]); nl--){ + if(match(block[nl], /[ou]l/)) + oprint("
  • "); + oprint(""); + } +} +nnl > nl { + for(; nl < nnl; nl++){ + block[nl + 1] = nblock[nl + 1]; + oprint("<" block[nl + 1] ">"); + if(match(block[nl + 1], /[ou]l/)) + oprint("
  • "); + } +} +hr { + oprint("
    "); + next; +} + +# Code blocks +code && /^$/ { + if(blanK) + oprint(""); + blank = 1; + next; +} +!text && sub(/^( | )/, "") { + if(blanK) + oprint(""); + blank = 0; + if(!code) + oprint("
    ");
    +	code = 1;
    +	$0 = eschtml($0);
    +	oprint($0);
    +	next;
    +}
    +code {
    +	oprint("
    "); + code = 0; +} + +# Setex-style Headers +text && /^=+$/ {printp("h1"); next;} +text && /^-+$/ {printp("h2"); next;} + +# Atx-Style headers +/^#+/ && (!newli || par=="p" || /^##/) { + for(n = 0; n < 6 && sub(/^# */, ""); n++) + sub(/#$/, ""); + par = "h" n; +} + +# Paragraph +/^$/ { + printp(par); + par = "p"; + next; +} + +# Add text +{ text = (text ? text " " : "") $0; } + +END { + if(code){ + oprint(""); + code = 0; + } + printp(par); + for(; nl > 0; nl--){ + if(match(block[nl], /[ou]l/)) + oprint("
  • "); + oprint(""); + } + gsub(/<<[^\"]*/, "", otext); + print(otext); +} diff --git a/style.css b/style.css new file mode 100644 index 0000000..03eb739 --- /dev/null +++ b/style.css @@ -0,0 +1,87 @@ +/* Based on werc.cat-v.org, suckless.org and garbe.us */ + +/* General */ +body { + color: #aaa; + font-family: sans-serif; + font-size: 80%; + margin: 0; + padding: 0 +} + +/* Header */ +.header { background-color: #ccc; border: 0; } +.header a { border: 0; color: #111; text-decoration: none; } +.midHeader img { border: 0; } + +.headerTitle { font-size: 1.6em; font-weight: bold; margin: 0 0 0 0.5em; padding: 0.5em; } +.headerTitle a { border: 0; text-decoration: none; } + +.headerSubTitle { font-size: 0.6em; font-weight: normal; margin-left: 1em; } + +/* Side */ +#side-bar { + width: 100%; + clear: both; + border: 0; + margin: 0; + padding: 0; + background-color: #ddd; +} + +#side-bar ul { + margin: 0; + padding: 0.3em; + list-style-type: none; + list-style-image: none; + border: 0; +} + +#side-bar li { display: inline; line-height: 1.6em; white-space: nowrap; } + +#side-bar ul li a { + margin: 0; + padding: 0.1em 1ex 0.1em 1ex; + color: #336699; + background-color: transparent; + text-decoration: none; + font-size: 1em; + border: 0; +} + +#side-bar ul li a:hover { color: #111; text-decoration: none; } + +/* Main Copy */ +#main { + max-width: 70em; + color: #111; + margin: 0 auto 0 2em; + padding: 1em 3em 2em 1em; + border: 0; +} + +#main a { color: #336699; text-decoration: none; } +#main a:hover { text-decoration: underline; } +#main h1, #main-copy h2 { color: #666; } +#main ul { list-style-type: square; } + +/* Footer */ +#footer { + background-color: #ddd; + color: #111; + font-size: 91%; + padding: 2em; + clear: both; +} + +#footer .left { text-align: left; float: left; clear: left; } +#footer .right { text-align: right; } +#footer a { color: #111; text-decoration: none; } +#footer a:hover { text-decoration: underline; } + +abbr, acronym { border-bottom: 1px dotted #333; cursor: help; } +blockquote { border-left: 1px solid #333; font-style: italic; padding: 1em; } +hr { border-width: 0 0 0.1em 0; border-color: #666; } + +code, pre { font-size: 1.1em } +pre { margin-left: 2em; } diff --git a/style.old.css b/style.old.css new file mode 100644 index 0000000..a049b4c --- /dev/null +++ b/style.old.css @@ -0,0 +1,209 @@ +/* Based on werc stylesheet (werc.cat-v.org) */ + +/* Header */ +.header { + color: rgb(39,78,144); + background-color: rgb(140,170,230); + background-color: #ff6d06; + border: solid 0 black; + border-width: 2px 0; +} + +.headerTitle { + color: black; + font-size: 233%; + font-weight: normal; + margin: 0 0 0 4mm; + padding: 0.25ex 0; +} + +.headerSubTitle { + font-size: 50%; + font-style: italic; + margin-left: 1em; +} + +.headerTitle a { color: black; } +.headerTitle a:hover { text-decoration: none; } + +/* Side */ +#side-bar { + width: 16em; + float: left; + clear: left; + border-right: 1px solid #ddd; +} + +#side-bar ul { + list-style-type: none; + list-style-position: outside; + margin: 0; + padding: 0 0 0.3em 0; +} + +#side-bar li { + margin: 0; + padding: 0.1ex 0; /* Circumvents a rendering bug (?) in MSIE 6.0 XXX should move to iehacks.css, this causes an ugly gap */ +} + +#side-bar a { + color: rgb(0,102,204); + background-color: transparent; + margin: 0; + padding: 0.25em 1ex 0.25em 2mm; + display: block; + text-transform: capitalize; + font-weight: bold!important; + font-size: 102%; + border-left: white solid 0.2em; +} + +#side-bar a:hover { + color: white; + background-color: rgb(100,135,220); + border-left: black solid 0.2em; + text-decoration: none; +} + +/* Main Copy */ +#main { + max-width: 70em; + color: black; + background-color: transparent; + text-align: justify; + line-height: 1.5em; + margin: 0em 0 0 16em; + padding: 0.5mm 5mm 5mm 5mm; + border-left: 1px solid #ddd; +} + +#bodyText { + margin: 0 0 0 15.5em; + padding: 2mm 5mm 2mm 5mm; +} + +#main p { + margin: 1em 1ex 1em 1ex !important; /* Need !important so troff-generated pages don't look totally squezed */ + padding: 0; +} + +#main a { + color: rgb(0,102,204); + background-color: transparent; +} + +#main a:hover { + color: rgb(100,135,220); +} + +#main h1, #main h2 { + color: rgb(0,102,204); + background-color: transparent; + font-size: 145.5%; + font-weight: bold; + margin: 2em 0 0 0; + padding: 0.5ex 0 0.5ex 0.6ex; + border-bottom: 2px solid rgb(0,102,204); +} + +#main h2 { + font-size: 115.5%; + border-bottom: 1px solid rgb(0,102,204); +} + +#main .topOfPage { + color: rgb(0,102,204); + background-color: transparent; + font-size: 91%; + font-weight: bold; + text-decoration: none; + margin: 3ex 1ex 0 0; + padding: 0; + float: right; +} + +dl { + margin: 1em 1ex 2em 1ex; + padding: 0; +} + +dt { + font-weight: bold; + margin: 0 0 0 0; + padding: 0; +} + +dd { + margin: 0 0 2em 2em; + padding: 0; +} + +/* Footer */ +#footer { + color: white; + background-color: rgb(100,135,220); + padding: 0.4em; + clear: both; +} + +#footer .right { + text-align: right; + line-height: 1.45em; +} + +#footer a { + color: white; + background-color: transparent; +} + +/* General */ +body { + color: black; + background-color: white; + font-family: Helvetica, Arial, 'Liberation Sans', FreeSans, sans-serif; + font-size: 84%; /* Enables font size scaling in MSIE */ + margin: 0; + padding: 0; +} + +a { text-decoration: none; } +a:hover { text-decoration: underline; } + +li ul { + padding-left: 0.6em !important; +} + +table { + border: solid 1px black; +} +th { + background-color: #abc; + border: solid 1px black; + text-align: center; +} +td { + background-color: #def; + border: solid 1px black; +} + +hr { + border-width: 0px 0px 0.1em 0px; + border-color: black; +} + +acronym, .titleTip { + border-bottom: 1px solid #ddd; + cursor: help; + margin: 0; + padding: 0 0 0.4px 0; +} + +pre { + margin-left: 2em; + font-size: 1.2em; +} + +blockquote { + border-left: 1px solid blue; + font-style: italic; +} diff --git a/sw b/sw new file mode 100755 index 0000000..4f57bff --- /dev/null +++ b/sw @@ -0,0 +1,106 @@ +#!/bin/sh +# sw - suckless webframework - 2012 - MIT License - nibble + +sw_filter() { + for b in $BL; do + [ "$b" = "$1" ] && return 0 + done +} + +sw_main() { + $MDHANDLER $1 +} + +sw_menu() { + echo "
      " + [ -z "`echo $1 | grep index.md`" ] && echo "
    • .
    • " + [ "`dirname $1`" != "." ] && echo "
    • ..
    • " + FILES=`ls \`dirname $1\` | sed -e 's,.md$,.html,g'` + for i in $FILES ; do + sw_filter $i && continue + NAME=`echo $i | sed -e 's/\..*$//' -e 's/_/ /g'` + [ -z "`echo $i | grep '\..*$'`" ] && i="$i/index.html" + echo "
    • $NAME
    • " + done + echo "
    " +} + +sw_page() { + # Header + cat << _header_ + + + +${TITLE} + + +_header_ + # Stylesheet + sw_style + cat << _header_ + + +
    +

    +${TITLE} ${SUBTITLE} +

    +
    +_header_ + # Menu + echo "
    " + sw_menu $1 + echo "
    " + # Body + echo "
    " + sw_main $1 + echo "
    " + # Footer + cat << _footer_ + + + +_footer_ +} + +sw_style() { + if [ -f $CDIR/$STYLE ]; then + echo '' + fi +} + +# Set input dir +IDIR="`echo $1 | sed -e 's,/*$,,'`" +if [ -z "$IDIR" ] || [ ! -d $IDIR ]; then + echo "Usage: sw [dir]" + exit 1 +fi + +# Load config file +if [ ! -f $PWD/sw.conf ]; then + echo "Cannot find sw.conf in current directory" + exit 1 +fi +. $PWD/sw.conf + +# Setup output dir structure +CDIR=$PWD +ODIR="$CDIR/`basename $IDIR`.static" +rm -rf $ODIR +mkdir -p $ODIR +cp -rf $IDIR/* $ODIR +rm -f `find $ODIR -type f -iname '*.md'` + +# Parse files +cd $IDIR +FILES=`find . -iname '*.md' | sed -e 's,^\./,,'` +for a in $FILES; do + b="$ODIR/`echo $a | sed -e 's,.md$,.html,g'`" + echo "* $a" + sw_page $a > $b; +done + +exit 0 diff --git a/sw.conf.def b/sw.conf.def new file mode 100644 index 0000000..385c2c9 --- /dev/null +++ b/sw.conf.def @@ -0,0 +1,9 @@ +# sw - suckless webframework - 2012 - nibble + +# Configuration +TITLE="foo.org" # Site title +SUBTITLE="" # Site subtitle +BL="index.html images" # Black list +STYLE="style.css" # Stylesheet name +# External apps +MDHANDLER="/usr/local/bin/md2html.awk" # md handler diff --git a/whereis b/whereis new file mode 100755 index 0000000..9cf5412 --- /dev/null +++ b/whereis @@ -0,0 +1,9 @@ +#!/bin/sh +[ -z "$1" ] && exit 1 +IFS=: +for a in $PATH ; do + if [ -e "$a/$1" ]; then + echo "$a/$1" + break + fi +done