diff options
-rwxr-xr-x | jimmy | 290 | ||||
-rw-r--r-- | test.gmi | 37 |
2 files changed, 0 insertions, 327 deletions
diff --git a/jimmy b/jimmy deleted file mode 100755 index 3e4485e..0000000 --- a/jimmy +++ /dev/null | |||
@@ -1,290 +0,0 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | ### Initialize | ||
4 | # init buffers | ||
5 | buff="$(mktemp)" | ||
6 | lbuf="$(mktemp)" | ||
7 | meta="$(mktemp)" | ||
8 | cleanup() { rm "$buff" "$lbuff" "$meta" 2>/dev/null; } | ||
9 | trap cleanup EXIT INT KILL | ||
10 | |||
11 | # init state | ||
12 | prev= # previous linetype | ||
13 | curr= # current linetype | ||
14 | tmpl= # template (optional) | ||
15 | verbatimp=false # in verbatim block? | ||
16 | metap=true # in metadata block? | ||
17 | IPATH="$PWD" # inclusion path | ||
18 | # (tuneables) | ||
19 | : "${nl:=::NL::}" # newline | ||
20 | : "${sp:=::SP::}" # space | ||
21 | : "${te:=::END::}" # template end | ||
22 | : "${to:=html}" # output format | ||
23 | |||
24 | ### Formats | ||
25 | ## HTML and GMI are given here. Other formats can be defined in their | ||
26 | ## own files and they'll be sourced. | ||
27 | |||
28 | ## NOTES | ||
29 | # should we allow modifying variables from the environment ? | ||
30 | |||
31 | html() { | ||
32 | : "${fmtbuff_hd_1:=<h1>%s</h1>$nl}" | ||
33 | : "${fmtline_hd_1:=%s}" | ||
34 | : "${fmtbuff_hd_2:=<h2>%s</h2>$nl}" | ||
35 | : "${fmtline_hd_2:=%s}" | ||
36 | : "${fmtbuff_hd_3:=<h3>%s</h3>$nl}" | ||
37 | : "${fmtline_hd_3:=%s}" | ||
38 | : "${fmtbuff_quot:=<blockquote>$nl%s</blockquote>$nl}" | ||
39 | : "${fmtline_quot:=%s$nl}" | ||
40 | : "${fmtbuff_list:=<ul>$nl%s</ul>$nl}" | ||
41 | : "${fmtline_list:=<li>%s</li>$nl}" | ||
42 | : "${fmtbuff_para:=<p>%s</p>$nl}" | ||
43 | : "${fmtline_para:=%s$nl}" | ||
44 | : "${fmtline_plnk:=<a href=\"%s\">%s</a>$nl}" | ||
45 | : "${fmtbuff_link:=<ul class=\"links\">$nl%s</ul>$nl}" | ||
46 | : "${fmtline_link:=<li><a href=\"%s\">%s</li>$nl}" | ||
47 | : "${fmtbuff_verb:=<pre><code>%s</code></pre>$nl}" | ||
48 | : "${fmtline_verb:=%s$nl}" | ||
49 | : "${fmtbuff_blank:=$nl}" | ||
50 | : "${fmtline_blank:=$nl}" | ||
51 | } | ||
52 | |||
53 | gmi() { | ||
54 | : "${fmtbuff_hd_1:=# %s$nl}" | ||
55 | : "${fmtline_hd_1:=%s}" | ||
56 | : "${fmtbuff_hd_2:=## %s$nl}" | ||
57 | : "${fmtline_hd_2:=%s}" | ||
58 | : "${fmtbuff_hd_3:=### %s$nl}" | ||
59 | : "${fmtline_hd_3:=%s}" | ||
60 | : "${fmtbuff_quot:=> %s$nl}" | ||
61 | : "${fmtline_quot:=%s$sp}" | ||
62 | : "${fmtbuff_list:=%s$nl}" | ||
63 | : "${fmtline_list:=* %s$nl}" | ||
64 | : "${fmtbuff_para:=%s$nl}" | ||
65 | : "${fmtline_para:=%s$sp}" | ||
66 | : "${fmtline_plnk:=$nl=> %s %s$nl}" | ||
67 | : "${fmtbuff_link:=%s}" | ||
68 | : "${fmtline_link:==> %s %s$nl}" | ||
69 | : "${fmtbuff_verb:=\`\`\`$nl%s\`\`\`$nl}" | ||
70 | : "${fmtline_verb:=%s$nl}" | ||
71 | : "${fmtbuff_blank:=$nl}" | ||
72 | : "${fmtline_blank:=$nl}" | ||
73 | } | ||
74 | |||
75 | ### Filters | ||
76 | |||
77 | filter_buff() { | ||
78 | f="filter_buff_$to" | ||
79 | if type "$f" 2>/dev/null | grep -q function | ||
80 | then "$f" | ||
81 | else cat | ||
82 | fi | ||
83 | } | ||
84 | |||
85 | filter_line() { | ||
86 | f="filter_line_$to" | ||
87 | if type "$f" 2>/dev/null | grep -q function | ||
88 | then printf '%s\n' "$*" | "$f" | ||
89 | else printf '%s\n' "$*" | ||
90 | fi | ||
91 | } | ||
92 | |||
93 | filter_line_html() { | ||
94 | # s/// : escape <, >, & from html | ||
95 | # s### : *bold*, _italic_, `code` | ||
96 | # s@@@ : smart versions of things | ||
97 | sed \ | ||
98 | -e 's/&/\&/g' \ | ||
99 | -e 's/</\</g' \ | ||
100 | -e 's/>/\>/g' \ | ||
101 | -e 's#\*\([^*]*\)\*#<b>\1</b>#g' \ | ||
102 | -e 's#_\([^_]*\)_#<i>\1</i>#g' \ | ||
103 | -e 's#`\([^`]*\)`#<code>\1</code>#' \ | ||
104 | -e 's@---@\—@g' \ | ||
105 | -e 's@--@\–@g' | ||
106 | |||
107 | } | ||
108 | |||
109 | ### Processing | ||
110 | |||
111 | ## Utility functions | ||
112 | |||
113 | pushline() { | ||
114 | tag="$1"; shift | ||
115 | printf "$(eval echo "\$fmtline_$tag")" "$@" >> "$buff" | ||
116 | } | ||
117 | |||
118 | bufprint() { | ||
119 | b="$(filter_buff<"$buff")" | ||
120 | printf "$(eval echo "\$fmtbuff_$1")" "$b" | | ||
121 | sed -e "s/$nl/\n/g" -e "s/$sp/ /g" # fix whitespace | ||
122 | : > "$buff" | ||
123 | } | ||
124 | |||
125 | ### Where the magic happens | ||
126 | process() { | ||
127 | set -f | ||
128 | while read -r sigil line | ||
129 | do | ||
130 | if $verbatimp && test "$sigil" != '```' | ||
131 | then | ||
132 | pushline verb "$(filter_line "$sigil $line")" | ||
133 | continue | ||
134 | fi | ||
135 | |||
136 | case "$sigil" in | ||
137 | (*':') # metadata | ||
138 | if $metap | ||
139 | then printf 'export %s="%s"\n' \ | ||
140 | "${sigil%:}" "$line" >>"$meta" | ||
141 | fi | ||
142 | ;; | ||
143 | ('```') # verbatim | ||
144 | # CONSIDER: "types" of verbatim | ||
145 | # designated by extra fields after the | ||
146 | # sigil | ||
147 | ## ``` class_of_content | ||
148 | # ^--- change the class of the content, | ||
149 | # eg. in html do <pre class="type"> | ||
150 | # other formats might do other things | ||
151 | ## ``` | some_program | ||
152 | # ^--- pipe the buffer to some_program | ||
153 | metap=false | ||
154 | if $verbatimp | ||
155 | then | ||
156 | bufprint verb | ||
157 | verbatimp=false | ||
158 | prev= | ||
159 | else | ||
160 | bufprint "$prev" | ||
161 | verbatimp=true | ||
162 | fi | ||
163 | continue | ||
164 | ;; | ||
165 | ('=>') # link | ||
166 | metap=false | ||
167 | |||
168 | printf '%s\n' "$line" > "$lbuf" | ||
169 | read -r url title < "$lbuf" | ||
170 | if test "$curr" = para | ||
171 | then | ||
172 | pushline plnk "$url" "$title" | ||
173 | continue | ||
174 | else curr=link | ||
175 | fi | ||
176 | ;; | ||
177 | ('#'*) # header | ||
178 | metap=false | ||
179 | curr=hd_${#sigil} ;; | ||
180 | ('>') # quote | ||
181 | metap=false | ||
182 | curr=quot ;; | ||
183 | ('*') # list | ||
184 | metap=false | ||
185 | curr=list ;; | ||
186 | ('') # blank line | ||
187 | metap=false | ||
188 | curr=blank ;; | ||
189 | (*) # paragraph | ||
190 | metap=false | ||
191 | curr=para | ||
192 | line="$sigil $line" | ||
193 | ;; | ||
194 | esac | ||
195 | |||
196 | test "$curr" = "$prev" || bufprint "$prev" | ||
197 | prev="$curr" | ||
198 | |||
199 | if test "$curr" = verb | ||
200 | then | ||
201 | pushline "$curr" "$line" | ||
202 | continue | ||
203 | fi | ||
204 | |||
205 | if test "$curr" = link | ||
206 | then pushline "$curr" "$url" "$(filter_line "$title")" | ||
207 | else pushline "$curr" "$(filter_line "$line")" | ||
208 | fi | ||
209 | done | ||
210 | |||
211 | bufprint "$curr" | ||
212 | } | ||
213 | |||
214 | templatize() { | ||
215 | eval "cat<<$te | ||
216 | $(cat $@) | ||
217 | $te" | ||
218 | } | ||
219 | |||
220 | ### Entry point | ||
221 | |||
222 | usage() { | ||
223 | cat <<EOF >&2 | ||
224 | jimmy: convert gmi to other formats | ||
225 | usage: jimmy [-h] [-t FORMAT] [-I DIRECTORY] [-T FILE] [FILE...] | ||
226 | If no FILE is given on the command line, jimmy reads standard input. | ||
227 | options: | ||
228 | -h show this help and exit | ||
229 | -x enable xtrace (set -x) | ||
230 | -t FORMAT | ||
231 | convert gmi to FORMAT. html is default, gmi is built-in. | ||
232 | you can also pass the name of a file that will be sourced. | ||
233 | -I DIRECTORY | ||
234 | add DIRECTORY to the include path for -t. the current | ||
235 | directory is always in the include path. | ||
236 | -T FILE | ||
237 | use FILE as a template for the output text. | ||
238 | EOF | ||
239 | exit $1 | ||
240 | } | ||
241 | |||
242 | main() { | ||
243 | while getopts hxI:t:T: OPT | ||
244 | do | ||
245 | case "$OPT" in | ||
246 | (h) usage 0 ;; | ||
247 | (x) set -x ;; | ||
248 | (I) IPATH="$OPTARG:$IPATH" ;; | ||
249 | (t) to="$OPTARG" ;; | ||
250 | (T) tmpl="$OPTARG" ;; | ||
251 | (*) usage 1 ;; | ||
252 | esac | ||
253 | done | ||
254 | shift $((OPTIND - 1)) | ||
255 | |||
256 | case "$to" in | ||
257 | (html|gmi) "$to" ;; | ||
258 | (*) | ||
259 | found=false | ||
260 | for p in $(echo "$IPATH"|tr : ' ') | ||
261 | do | ||
262 | if test -f "$p/$to" | ||
263 | then . "$p/$to"; found=true | ||
264 | elif test -f "$p/$to.sh" | ||
265 | then . "$p/$to.sh"; found=true | ||
266 | fi | ||
267 | done | ||
268 | if ! $found | ||
269 | then | ||
270 | echo >&2 "Can't find file: '$to'" | ||
271 | echo >&2 "Looked in $IPATH" | ||
272 | exit 2 | ||
273 | fi | ||
274 | ;; | ||
275 | esac | ||
276 | |||
277 | # while read requires a final newline | ||
278 | (cat "${@:--}"; echo) | | ||
279 | process | | ||
280 | if test -n "$tmpl" | ||
281 | then | ||
282 | # use eval cat instead of source for pipe sequencing | ||
283 | # reasons | ||
284 | eval "$(cat "$meta")" | ||
285 | templatize "$tmpl" | ||
286 | else cat | ||
287 | fi | ||
288 | } | ||
289 | |||
290 | main "$@" | ||
diff --git a/test.gmi b/test.gmi deleted file mode 100644 index 62bed2e..0000000 --- a/test.gmi +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | title: a test document | ||
2 | date: 2024-05-13T03:02:45Z | ||
3 | uuid: b3daebf1-440b-4828-a4d9-9089c7bd7c61 | ||
4 | |||
5 | # a test document of some kind | ||
6 | |||
7 | here is a test document. | ||
8 | it has paragraphs | ||
9 | => example.com with links! | ||
10 | and other things. | ||
11 | |||
12 | ## a code example | ||
13 | ``` | ||
14 | for (a=1;a<=4;a++) { | ||
15 | printf("%d\n", a); | ||
16 | } | ||
17 | ``` | ||
18 | |||
19 | ### other examples | ||
20 | |||
21 | > a blockquote is a quote | ||
22 | > that is blocky. | ||
23 | |||
24 | * list 1 | ||
25 | * list 2 | ||
26 | * list 3 | ||
27 | => example.com link list 1 | ||
28 | => example.com link list 2 | ||
29 | => example.com link list 3 | ||
30 | |||
31 | ok, now for another test: | ||
32 | will *strong* in-line text be converted? | ||
33 | as well as `code`, _emph_ and such? | ||
34 | what if *i _nest_ them* | ||
35 | what if *i _nest them* wrong_ ? | ||
36 | what about *breaking them | ||
37 | over two lines?* | ||