about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorCase Duckworth2024-01-30 23:42:09 -0600
committerCase Duckworth2024-01-30 23:42:09 -0600
commita7a348461b24b8ffe969a48cd804ab5b8a3d7469 (patch)
tree3b5e83f1dd7180d983425b0a3d9635e3e81ccde8
parentInitial commit (diff)
downloadsubtext-a7a348461b24b8ffe969a48cd804ab5b8a3d7469.tar.gz
subtext-a7a348461b24b8ffe969a48cd804ab5b8a3d7469.zip
Begin subtext.sh
-rw-r--r--subtext.awk95
-rwxr-xr-xsubtext.sh57
-rw-r--r--test.st4
3 files changed, 121 insertions, 35 deletions
diff --git a/subtext.awk b/subtext.awk index c3e135b..ee04238 100644 --- a/subtext.awk +++ b/subtext.awk
@@ -2,17 +2,13 @@
2# (C) C Duckworth <acdw@acdw.net> 2# (C) C Duckworth <acdw@acdw.net>
3 3
4BEGIN { 4BEGIN {
5 true = 1; false = 0
5 ## Tuneables 6 ## Tuneables
6 postproc = get_value(postproc, "ST_POSTPROC", "shexpand") 7 runbody = bool(runbody ? runbody : true)
7 bodyfunc = get_value(bodyfunc, "ST_BODYFUNC", "sub_text") 8 postproc = postproc ? postproc : "shexpand"
8 sopath = get_value(sopath, "ST_SOPATH", ".:"ENVIRON["HOME"]"/.subtext") 9 bodyfunc = bodyfunc ? bodyfunc : "body"
9 split(sopath, asopath, ":") 10 sopath = get_value(sopath, ".:"ENVIRON["HOME"]"/.subtext")
10 # postproc = postproc ? postproc : "shexpand"
11 # bodyfunc = bodyfunc ? bodyfunc : "sub_text"
12 ## Globals 11 ## Globals
13 # Booleans
14 true = 1
15 false = 0
16 ## Wrap the text in a function 12 ## Wrap the text in a function
17 pretext = "### begin text\n"bodyfunc"(){\n" 13 pretext = "### begin text\n"bodyfunc"(){\n"
18 posttext = "}\n### end text" 14 posttext = "}\n### end text"
@@ -47,7 +43,7 @@ BEGIN {
47### End a block 43### End a block
48 44
49end[endn] && $0 == end[endn] { 45end[endn] && $0 == end[endn] {
50 par = par "\n" end[endn--] "\n)" 46 pushpar(end[endn--] "\n)", true)
51 printpar() 47 printpar()
52 subdocp = false 48 subdocp = false
53 next 49 next
@@ -64,27 +60,31 @@ end[endn] && $0 == end[endn] {
64### Special commands 60### Special commands
65## These call subtext-internal functions 61## These call subtext-internal functions
66 62
67/^\.so/ { # Insert $2 verbatim (if in sopath), else error 63/^#so/ { # Insert $2 verbatim (if in sopath), else error
64 pushpar($0)
68 source($2) 65 source($2)
69 next 66 next
70} 67}
71 68
72### Escape sequences 69/^###$/ { # Delimit document
73
74/^\.\.\./ { # Delimit document (end is optional)
75 printpar() 70 printpar()
76 docp = !docp 71 docp = !docp
77 if (docp) print pretext "unpreface ':'<<'_'|eval \"$ST_POSTPROC\"" 72 if (docp) {
78 else end_text() 73 print pretext "unpreface ':'<<'_'|eval \"$ST_POSTPROC\""
74 } else {
75 end_text()
76 }
79 next 77 next
80} 78}
81 79
80### Escape sequences
81
82/^\.\./ && docp { # Begin a heredoc 82/^\.\./ && docp { # Begin a heredoc
83 # ..[<command>] [<options>] [<<delim] 83 # ..[<command>] [<options>] [<<delim]
84 ## ends with DELIM or '..' 84 ## ends with DELIM or '..'
85 subdocp = true 85 subdocp = true
86 end[++endn] = (match($0,"<<") ? substr($0,RSTART+RLENGTH) : "..") 86 end[++endn] = (match($0, "<<") ? substr($0, RSTART + RLENGTH) : "..")
87 command = substr($0, 3, RSTART ? RSTART - 2 : length) 87 command = substr($0, 3, RSTART ? RSTART - 2 : length($0))
88 $0 = "$$(" (command ? command : "cat") "<<" end[endn] 88 $0 = "$$(" (command ? command : "cat") "<<" end[endn]
89} 89}
90 90
@@ -92,9 +92,11 @@ end[endn] && $0 == end[endn] {
92 # .<command> [<parameters>] 92 # .<command> [<parameters>]
93 ## wraps the line in $( ... ), basically (also quotes) 93 ## wraps the line in $( ... ), basically (also quotes)
94 specialp = 2 94 specialp = 2
95 gsub(/"/,"\\\\&") 95 gsub(/"/, "\\\\&", $0)
96 ln = "$$(" substr($1, 2) 96 ln = "$$(" substr($1, 2)
97 for (f=2;f<=NF;f++) ln = ln " \"" $f "\"" 97 for (f=2; f<=NF; f++) {
98 ln = ln " \"" $f "\""
99 }
98 ln = ln ")" 100 ln = ln ")"
99 $0 = ln 101 $0 = ln
100} 102}
@@ -106,53 +108,80 @@ end[endn] && $0 == end[endn] {
106### Book-keeping 108### Book-keeping
107 109
108/^$/ { 110/^$/ {
109 if (!par) next 111 if (!par)
112 next
110 printpar() 113 printpar()
111} 114}
112 115
113{ par = par (par?"\n":"") $0 } 116{
114{ if (--specialp < 0) specialp = 0 } 117 pushpar($0)
118 if (--specialp < 0)
119 specialp = 0
120}
115 121
116END { 122END {
117 if (dead) exit dead 123 if (dead)
118 if (par) printpar() 124 exit dead
125 if (par)
126 printpar()
119 while (endn > 0) 127 while (endn > 0)
120 print "\n" end[endn--] "\n)" 128 print "\n" end[endn--] "\n)"
121 if (docp) end_text() 129 if (docp)
130 end_text()
131 if (runbody)
132 print bodyfunc
122} 133}
123 134
124function end_text() { 135function end_text() {
125 print "_\n" posttext 136 print "_\n" posttext
126} 137}
127 138
139function pushpar(text, force_newline) {
140 par = par ((par || force_newline) ? "\n" : "") text
141}
142
128function printpar() { 143function printpar() {
129 specialp = specialp || (match(par, /^[ ]*</)) 144 specialp = specialp || (match(par, /^[ ]*</))
130 if (docp) { 145 if (docp) {
131 if (!subdocp && !specialp) par = "<p>" par "</p>" 146 if (!subdocp && !specialp)
147 par = "<p>" par "</p>"
132 shx = shellfix shxwrap 148 shx = shellfix shxwrap
133 print par | shx 149 print par | shx
134 close(shx) 150 close(shx)
135 } else print par 151 } else
152 print par
136 par = "" 153 par = ""
137} 154}
138 155
139function get_value(var, env_var, default) { 156function get_value(var, env_var, default) {
140 if (var) return var 157 if (var)
141 else if (ENVIRON[env_var]) return ENVIRON[env_var] 158 return var
142 else return default 159 else
160 return default
161}
162
163function bool(var, default) {
164 if (var=="false" || var=="no" || var=="0")
165 return false
166 else if (var=="true" || var=="yes" || var=="1")
167 return true
168 else
169 return var || default
143} 170}
144 171
145function source(name) { 172function source(name) {
146 found = false 173 found = false
147 sp = "" 174 sp = ""
175 split(sopath, asopath, ":")
148 for (dir in asopath) { 176 for (dir in asopath) {
149 fn = asopath[dir] "/" name 177 fn = asopath[dir] "/" name
150 sp = asopath[dir] "\n\t" sp 178 sp = asopath[dir] "\n\t" sp
151 while ((getline ln < fn) > 0) { 179 while ((getline ln < fn) > 0) {
152 found = true 180 found = true
153 par = par (par?"\n":"") ln 181 pushpar(ln)
154 } 182 }
155 if (found) break 183 if (found)
184 break
156 } 185 }
157 if (!found) 186 if (!found)
158 die("Couldn't source " name "; looked in:\n\t" sp, 9) 187 die("Couldn't source " name "; looked in:\n\t" sp, 9)
diff --git a/subtext.sh b/subtext.sh new file mode 100755 index 0000000..d845955 --- /dev/null +++ b/subtext.sh
@@ -0,0 +1,57 @@
1#!/bin/sh
2
3stawk() {
4 awk -f subtext.awk "$@" # SUBTEXT AWK SCRIPT HERE
5}
6
7usage() {
8 cat>&2 <<EOF
9SUBTEXT v.meowmers (C) Case Duckworth
10Usage: subtext [OPTIONS] FILE...
11 subtext < FILE
12Options:
13 -h Show this help and exit.
14 -n Don't run the resulting script; just print it.
15 -m FILE Use macrofile FILE.
16 -I DIRECTORY Add DIRECTORY to the search path.
17EOF
18 exit $1
19}
20
21configure() {
22 ## Initialize state variables
23 : "${ST_MACROFILE:=}"
24 : "${ST_SOPATH:=.:$HOME/.subtext}"
25 : "${ST_PIPE_SH:=true}"
26 ## Process options
27 while getopts :hm:I:n OPT
28 do
29 case "$OPT" in
30 (h) usage ;;
31 (m) ST_MACROFILE="$OPTARG" ;;
32 (I) ST_SOPATH="$ST_SOPATH:$OPTARG" ;;
33 (n) ST_PIPE_SH=false ;;
34 (:) printf >&2 'Unknown option -%s\n' "$OPTARG";
35 usage 1 ;;
36 (*) usage 1 ;;
37 esac
38 done
39}
40
41main() {
42 configure "$@"
43 shift $((OPTIND-1))
44 stawk -vsopath="$ST_SOPATH" "$@" |
45 if "$ST_PIPE_SH"
46 then sh
47 else cat
48 fi
49}
50
51die() {
52 ec="$1"; shift
53 printf >&2 '!! %s\n' "$*"
54 exit "$ec"
55}
56
57main "$@"
diff --git a/test.st b/test.st index b11bd87..18319fe 100644 --- a/test.st +++ b/test.st
@@ -1,7 +1,7 @@
1.so etlib.sh 1#so etlib.sh
2alias verse=cat 2alias verse=cat
3title="test file" 3title="test file"
4... 4###
5here's a test file 5here's a test file
6.a href="https://example.com" a link or something!! 6.a href="https://example.com" a link or something!!
7 7