From 59e5a214a8be015b00004b1961a83f48dd6d65f4 Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Mon, 29 Jan 2024 00:02:27 -0600 Subject: Initial commit --- subtext.awk | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ test.st | 33 ++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 subtext.awk create mode 100644 test.st diff --git a/subtext.awk b/subtext.awk new file mode 100644 index 0000000..c3e135b --- /dev/null +++ b/subtext.awk @@ -0,0 +1,165 @@ +# subtext -- text substitutor -*- awk -*- +# (C) C Duckworth + +BEGIN { + ## Tuneables + postproc = get_value(postproc, "ST_POSTPROC", "shexpand") + bodyfunc = get_value(bodyfunc, "ST_BODYFUNC", "sub_text") + sopath = get_value(sopath, "ST_SOPATH", ".:"ENVIRON["HOME"]"/.subtext") + split(sopath, asopath, ":") + # postproc = postproc ? postproc : "shexpand" + # bodyfunc = bodyfunc ? bodyfunc : "sub_text" + ## Globals + # Booleans + true = 1 + false = 0 + ## Wrap the text in a function + pretext = "### begin text\n"bodyfunc"(){\n" + posttext = "}\n### end text" + ## Prelude function strings + # Ask sed to do these b/c awk has no capture groups ;_; + shellfix = "sed -E" \ + " -e 's/`/\\\\`/g'" \ + " -e 's/(^|[^\\$])\\$([^\\$]|$)/\\1\\\\$\\2/g'" \ + " -e 's/(^|[^\\$])\\$(\\$+)([^\\$]|$)/\\1\\2\\3/g'" + shxwrap = " -e 's/^/:/'" + htmlfix = "sed -E" \ + " -e 's#([^\\\\]|^)&#\\1\\&#g'" \ + " -e 's#([^\\\\]|^)<#\\1\\<#g'" \ + " -e 's#([^\\\\]|^)>#\\1\\>#g'" \ + " -e 's#\\\\([&<>])#\\1#g'"; + ## Prelude + par = "#!/bin/sh\n### kernel\n" \ + "preface()(sed \"s/^/$1/\")\n" \ + "unpreface()(sed \"s/^$1//\")\n" \ + "shexpand()(eval \"$( (echo 'cat<<.';preface +;echo .)" \ + " | unpreface + )\")\n" \ + "### library\n" \ + "shellfix()(" shellfix ")\n" \ + "htmlfix()(" htmlfix ")\n" \ + "### variables\n" \ + "ST_POSTPROC=" postproc "\n" \ + "ST_BODYFUNC=" bodyfunc "\n" \ + "ST_SOPATH=" sopath "\n" \ + "### header\n" +} + +### End a block + +end[endn] && $0 == end[endn] { + par = par "\n" end[endn--] "\n)" + printpar() + subdocp = false + next +} + +### Line continuation + +/\\$/ { + getline nl + sub(/\\$/,"") + $0 = $0 " " nl +} + +### Special commands +## These call subtext-internal functions + +/^\.so/ { # Insert $2 verbatim (if in sopath), else error + source($2) + next +} + +### Escape sequences + +/^\.\.\./ { # Delimit document (end is optional) + printpar() + docp = !docp + if (docp) print pretext "unpreface ':'<<'_'|eval \"$ST_POSTPROC\"" + else end_text() + next +} + +/^\.\./ && docp { # Begin a heredoc + # ..[] [] [< [] + ## wraps the line in $( ... ), basically (also quotes) + specialp = 2 + gsub(/"/,"\\\\&") + ln = "$$(" substr($1, 2) + for (f=2;f<=NF;f++) ln = ln " \"" $f "\"" + ln = ln ")" + $0 = ln +} + +/^\\/ && docp { # \ at the beginning of a line escapes the next character + $0 = substr($0, 2) +} + +### Book-keeping + +/^$/ { + if (!par) next + printpar() +} + +{ par = par (par?"\n":"") $0 } +{ if (--specialp < 0) specialp = 0 } + +END { + if (dead) exit dead + if (par) printpar() + while (endn > 0) + print "\n" end[endn--] "\n)" + if (docp) end_text() +} + +function end_text() { + print "_\n" posttext +} + +function printpar() { + specialp = specialp || (match(par, /^[ ]*" par "

" + shx = shellfix shxwrap + print par | shx + close(shx) + } else print par + par = "" +} + +function get_value(var, env_var, default) { + if (var) return var + else if (ENVIRON[env_var]) return ENVIRON[env_var] + else return default +} + +function source(name) { + found = false + sp = "" + for (dir in asopath) { + fn = asopath[dir] "/" name + sp = asopath[dir] "\n\t" sp + while ((getline ln < fn) > 0) { + found = true + par = par (par?"\n":"") ln + } + if (found) break + } + if (!found) + die("Couldn't source " name "; looked in:\n\t" sp, 9) +} + +function die(message, code) { + dead = code + print "!!" FILENAME ":" NR ": " message > "/dev/stderr" + exit +} diff --git a/test.st b/test.st new file mode 100644 index 0000000..b11bd87 --- /dev/null +++ b/test.st @@ -0,0 +1,33 @@ +.so etlib.sh +alias verse=cat +title="test file" +... +here's a test file +.a href="https://example.com" a link or something!! + +.h1 it has "headers" or whatever + +..blockquote title=foo +it has paragraphs of quotes +.. + +$$(echo it has shell $scripty-stuff) + +.. +escaped par! +omg wow +.. + +..p +another one :O + +holy crap +this is great +.. + +i should have more paragraphs + +they are wonderful +i love them + +very much -- cgit 1.4.1-21-gabe81