summary refs log tree commit diff stats
path: root/ht.awk
diff options
context:
space:
mode:
Diffstat (limited to 'ht.awk')
-rwxr-xr-xht.awk385
1 files changed, 187 insertions, 198 deletions
diff --git a/ht.awk b/ht.awk index 60e042b..b9ae377 100755 --- a/ht.awk +++ b/ht.awk
@@ -1,246 +1,235 @@
1#!/usr/bin/awk -f 1#!/bin/awk -f
2# -*- indent-tabs-mode: t; -*-
3# HAT TRICK 2# HAT TRICK
4# (C) 2022 C. Duckworth 3# Copyright (C) 2022 Case Duckworth <acdw@acdw.net>
5 4#
6### Commentary:
7
8# OLDIFS=$IFS; IFS=$'\n';
9# for line in `cat testfile`; do
10# test=`echo "$line" | grep -E '[\]$'`;
11# if [ $test ]; then
12# newline=`echo $line | rev | cut -c 2- | rev`;
13# echo -n "$newline"; else echo "$line";
14# fi; done;
15# IFS=$OLDIFS
16
17### Code:
18BEGIN { 5BEGIN {
19 width = 72 6 # Configuration
20 default_htag = "p" 7 DEFAULT_CONFIG_MODE = "config"
21 default_gtag = "" 8 config_initialize()
22 default_ftag = "" 9 config_parse(ENVIRON["HT_CONFIG"] ? ENVIRON["HT_CONFIG"] : "ht.conf")
23} 10 # State
24 11 DEFTAG = CONFIG["default_tag"]
25### Raw formatting 12 DEFATTR = CONFIG["default_attr"]
26/^>>>/ { 13 TAG = DEFTAG
27 getline first_raw 14 ATTR = DEFATTR
28 if (raw_fmt_p("html")) { 15}
29 raw_html = 1 16
30 html[++hpar] = "<pre><code>" html_escape(first_raw) 17# Mutliple-file awareness
31 } 18FNR == 1 {
32 if (raw_fmt_p("gemini")) { 19 fileflush()
33 raw_gemini = 1 20}
34 gemini[++gpar] = "```" 21
35 gemini[++gpar] = first_raw 22# Handle raw sections
36 } 23$0 ~ CONFIG["raw_delim"] {
37 if (raw_fmt_p("gopher")) { 24 RAW = ! RAW
38 raw_gopher = 1 25 if (RAW) {
39 gopher[++fpar] = first_raw 26 buflush()
27 bufpush(CONFIG["raw_beg"], -1)
28 } else {
29 bufpush(CONFIG["raw_end"], -1)
30 print BUFFER
31 BUFFER = ""
40 } 32 }
41 raw = 1
42 next 33 next
43} 34}
44 35
45/^<<</ { 36RAW {
46 if (raw_html) { 37 bufpush($0)
47 html[hpar] = html[hpar] "</code></pre>"
48 }
49 if (raw_gemini) {
50 gemini[++gpar] = "```"
51 gemini[++gpar] = ""
52 }
53 if (raw_gopher) {
54 gopher[++fpar] = ""
55 }
56 raw_html = 0
57 raw_gemini = 0
58 raw_gopher = 0
59 raw = 0
60 next 38 next
61} 39}
62 40
63raw { 41# Comments
64 if (raw_html) { 42$0 ~ ("^" COMMENT_DELIM) {
65 html_empty = 0
66 html[++hpar] = html_escape($0)
67 }
68 if (raw_gemini) {
69 gemini_empty = 0
70 gemini[++gpar] = $0
71 }
72 if (raw_gopher) {
73 gopher_empty = 0
74 gopher[++fpar] = $0
75 }
76 next 43 next
77} 44}
78 45
79# Block types 46# HTML escape hatch
80/^#/ { 47/^</ {
81 match($0, /#+/) 48 HTML = 1
82 htag = "h" (RLENGTH > 6 ? 6 : RLENGTH) 49 bufpush($0)
83 gtag = substr($0, RSTART, (RLENGTH > 3 ? 3 : RLENGTH)) " " 50 next
84 ftag = substr($0, RSTART, RLENGTH) " "
85 sub(/^#+[ \t]*/, "", $0)
86} 51}
87 52
88# Line types 53# Sure, let's do templating! This makes it less... weird.
89/^=>/ { 54/\$/ {
90 title = "" 55 # XXX: This is probably the dumbest way to do it.
91 for (i = 3; i <= NF; i++) { 56 gsub(/\$\$/, "$\a", $0)
92 title = title (title ? " " : "") $i 57 gsub(/\$[^\a]/, "\\\\&", $0)
93 } 58 gsub(/\$\a/, "$", $0)
94 hbuf[++hline] = "<a href=\"" $2 "\">" title "</a>"
95 gbuf[++gline] = "\ngemini\t" $0
96 # TODO: gopher
97 next
98} 59}
99 60
100### Everything else 61# Blocks of text
101/./ { 62/./ {
102 html_empty = 0 63 # EOL escape
103 gemini_empty = 0 64 if (match($0, /\\$/)) {
104 gopher_empty = 0 65 sep = -1
105 hbuf[++hline] = $0 66 $0 = substr($0, 1, RSTART - 1)
106 gbuf[++gline] = $0 67 } else {
107 fbuf[++fline] = $0 68 sep = "\n"
69 }
70 # Loop through BLOCK_TYPES
71 for (bt in BLOCK_TYPES) {
72 if (match($0, "^" bt "[ \t]*")) {
73 $0 = substr($0, RSTART + RLENGTH)
74 if (match(BLOCK_TYPES[bt], "[ \t]*>[ \t]*")) {
75 parent = substr(BLOCK_TYPES[bt], 1, RSTART - 1)
76 child = substr(BLOCK_TYPES[bt], RSTART + RLENGTH)
77 }
78 if (parent) {
79 split(parent, pa, FS)
80 split(child, bl, FS)
81 if (! IN_PARENT) {
82 IN_PARENT = pa[1]
83 }
84 TAG = IN_PARENT
85 ATTR = ""
86 for (i = 2; i <= length(pa); i++) {
87 ATTR = ATTR (ATTR ? " " : "") pa[i]
88 }
89 bufpush("<" child ">" $0 "</" bl[1] ">")
90 next # XXX: This is messy.
91 } else {
92 split(BLOCK_TYPES[bt], bl, FS)
93 if (IN_PARENT) {
94 bufpush("</" IN_PARENT ">")
95 IN_PARENT = ""
96 }
97 if (! BUFFER) {
98 TAG = bl[1]
99 for (b = 2; b <= length(bl); b++) {
100 ATTR = ATTR (ATTR ? " " : "") bl[b]
101 }
102 } else {
103 $0 = "<" BLOCK_TYPES[bt] ">" $0 "</" bl[1] ">"
104 }
105 }
106 }
107 }
108 # Loop through LINE_TYPES
109 for (lt in LINE_TYPES) {
110 if (match($0, "^" lt "[ \t]*")) {
111 $0 = substr($0, RSTART + RLENGTH)
112 templ = LINE_TYPES[lt]
113 while (match(templ, /\$[0-9]+/)) {
114 sub(/\$[0-9]+/, $(substr(templ, RSTART + 1, RLENGTH - 1)), templ)
115 }
116 $0 = templ
117 }
118 }
119 # Push to buffer
120 bufpush($0, sep)
108} 121}
109 122
123# Blank lines end blocks
110/^$/ { 124/^$/ {
111 bufput() 125 if (HTML) {
126 html_end()
127 }
128 if (! RAW) {
129 buflush()
130 }
112} 131}
113 132
133# Clean up
114END { 134END {
115 bufput() 135 if (HTML) {
116 printarr(html, "html") 136 html_end()
117 printarr(gemini, "gemini") 137 } else if (RAW) {
118 printarr(gopher, "gopher") 138 bufpush(CONFIG["raw_end"], -1)
119} 139 print BUFFER
120 140 } else {
121 141 buflush()
122function bufput()
123{
124 hbufput()
125 gbufput()
126 fbufput()
127}
128
129function clear(arr)
130{
131 for (x in arr) {
132 delete arr[x]
133 } 142 }
134} 143}
135 144
136function fbufput()
137{
138 if (! length(fbuf)) {
139 next
140 }
141 for (ln in fbuf) { # XXX: gopher line types
142 paragraph = paragraph (paragraph ? " " : "") fbuf[ln]
143 }
144 fill(paragraph)
145 for (ln in fp) {
146 gopher[++fpar] = ((ln == 1) ? ftag : "") fp[ln]
147 }
148 gopher[++fpar] = ""
149 paragraph = ""
150 ftag = default_ftag
151 clear(fp)
152 clear(fbuf)
153}
154 145
155function fill(paragraph) 146### Buffer-y functions
147function buflush()
156{ 148{
157 char = 0 149 buftrim()
158 ln = 1 150 if (BUFFER) {
159 split(paragraph, words, FS) 151 if (TAG) {
160 for (word in words) { 152 TAG_BEG = "<" TAG (ATTR ? " " ATTR : "") ">"
161 char += length(words[word]) 153 TAG_END = "</" TAG ">"
162 if (char <= width) {
163 fp[ln] = fp[ln] (fp[ln] ? " " : "") words[word]
164 } else {
165 fp[++ln] = words[word]
166 char = length(words[word])
167 } 154 }
155 print TAG_BEG BUFFER TAG_END
156 BUFFER = ""
157 TAG = DEFTAG
158 ATTR = DEFATTR
159 IN_PARENT = ""
168 } 160 }
169} 161}
170 162
171function gbufput() 163function bufpush(text, separator)
172{ 164{
173 if (! length(gbuf)) { 165 if (! separator) {
174 next 166 separator = "\n"
175 } 167 }
176 for (ln in gbuf) { 168 if (separator == -1) {
177 paragraph = paragraph (paragraph ? " " : "") gbuf[ln] 169 separator = ""
178 } 170 }
179 gemini[++gpar] = gtag paragraph 171 BUFFER = BUFFER text (separator ? separator : "")
180 gemini[++gpar] = ""
181 gtag = default_gtag
182 paragraph = ""
183 clear(gbuf)
184} 172}
185 173
186function gopher_line(type, display, selector, hostname, port) 174function buftrim()
187{ 175{
188 return (type display "\t" selector "\t" hostname "\t" port) 176 if (match(BUFFER, "\n+$")) {
189} 177 BUFFER = substr(BUFFER, 1, RSTART - 1)
190
191function hbufput()
192{
193 if (! length(hbuf)) {
194 next
195 }
196 for (ln in hbuf) {
197 paragraph = paragraph (paragraph ? " " : "") hbuf[ln]
198 }
199 fill(paragraph)
200 for (ln in fp) {
201 html[++hpar] = ((ln == 1) ? "<" (htag ? htag : default_htag) ">" : "") fp[ln]
202 } 178 }
203 html[hpar] = html[hpar] (htag_end ? htag_end : "</" (htag ? htag : default_htag) ">")
204 paragraph = ""
205 htag = default_htag
206 clear(fp)
207 clear(hbuf)
208} 179}
209 180
210function html_escape(text) 181### Config functions
182function config_initialize()
211{ 183{
212 gsub(/&/, "\\&amp;", text) 184 COMMENT_DELIM = ";"
213 gsub(/</, "\\&lt;", text) 185 CONFIG["raw_delim"] = "```"
214 gsub(/>/, "\\&gt;", text) 186 CONFIG["raw_beg"] = "<pre><code>"
215 return text 187 CONFIG["raw_end"] = "</code></pre>"
216} 188 CONFIG["default_tag"] = "p"
217 189 CONFIG["default_attr"] = ""
218function printarr(arr, prefix) 190 LINE_TYPES["@"] = "<a href=\"$1\">$2</a>"
191 LINE_TYPES["`"] = "<code>$0</code>"
192 BLOCK_TYPES["#"] = "h1"
193 BLOCK_TYPES["##"] = "h2"
194 BLOCK_TYPES["###"] = "h3"
195 BLOCK_TYPES["-"] = "ul>li"
196}
197
198function config_parse(file)
219{ 199{
220 if (prefix) { 200 mode = DEFAULT_CONFIG_MODE
221 fmt = "%s\t%s\n" 201 while ((getline < file) > 0) {
222 } else { 202 if (match($0, /^#/) || ! $0) {
223 fmt = "%s%s\n" 203 continue
224 } 204 }
225 for (x in arr) { 205 if (match($0, /^\\/)) {
226 printf fmt, prefix, arr[x] 206 $0 = substr($0, 2)
207 }
208 if (match($0, /\[[^\]]+\]/)) {
209 mode = substr($0, RSTART + 1, RLENGTH - 2)
210 continue
211 } else {
212 var = $1
213 val = ""
214 for (i = 2; i <= NF; i++) {
215 val = val (val ? " " : "") $i
216 }
217 if (mode == "config") {
218 CONFIG[var] = val
219 } else if (mode == "block") {
220 BLOCK_TYPES[var] = val
221 } else if (mode == "line") {
222 LINE_TYPES[var] = val
223 }
224 }
227 } 225 }
228} 226}
229 227
230function raw_fmt_p(format) 228### Other functions
229function html_end()
231{ 230{
232 if (NF < 2) { 231 buftrim()
233 return 1 232 print BUFFER
234 } 233 BUFFER = ""
235 if ($2 ~ /-/) { 234 HTML = 0
236 if ($2 ~ ("-" format)) {
237 return 0
238 } else {
239 return 1
240 }
241 }
242 if ($2 ~ format) {
243 return 1
244 }
245 return 0
246} 235}