Blame


1 d7de9ba6 2020-12-29 op I like text/gemini. I like writing in this format. At first, it was a bit limitating, like, I want *bold*, /italic/, _underline_, ~striked~, [inline links](…), ![inline images](…), !![inline videos](…) (?) etc. But I as started writing (by the way, every post in the last 3 months was written in text/gemini) I found myself pretty accustomed to it. I really like the idea of one link-per-line.
2 d7de9ba6 2020-12-29 op
3 d7de9ba6 2020-12-29 op I also started writing text/gemini outside this blog. The INSTALL file for gmid is written in text/gemini. The README for tango (a new hack, will write about that later) is also written in text/gemini.
4 d7de9ba6 2020-12-29 op
5 d7de9ba6 2020-12-29 op => https://git.omarpolo.com/gmid/about/ gmid repository
6 d7de9ba6 2020-12-29 op => https://git.omarpolo.com/tango/about/ tango repository
7 d7de9ba6 2020-12-29 op
8 d7de9ba6 2020-12-29 op (they’re only gemini-related things, so using text/gemini for documentational/presentational purpose seems appropriate.)
9 d7de9ba6 2020-12-29 op
10 d7de9ba6 2020-12-29 op I also have a public (HTTP-only for the time being) git repository, powered by cgit.
11 d7de9ba6 2020-12-29 op
12 d7de9ba6 2020-12-29 op If you sum this two things, you’ll reach the logical conclusion that I need a filter for cgit to display text/gemini over HTTP.
13 d7de9ba6 2020-12-29 op
14 d7de9ba6 2020-12-29 op Cgit has this cool things called filters: you can write script (or any executable really) that accept input in a particular format and output HTML and cgit will use it to render pages.
15 d7de9ba6 2020-12-29 op
16 d7de9ba6 2020-12-29 op There are a few text/gemini to HTML converters, but I rolled my own. NIH. Well, not really. I currently run cgit on a FreeBSD jail, and I don’t like the idea of installing too much things inside it. I could have built a (say) go executable linked statically and copied into the jail, but I don’t really like the idea.
17 d7de9ba6 2020-12-29 op
18 d7de9ba6 2020-12-29 op Instead, I wrote an AWK script to convert text/gemini files to HTML. I was kinda surprised that nobody had already written one in AWK (or Perl). It isn’t too ugly, and was an occasion to review the language.
19 d7de9ba6 2020-12-29 op
20 d7de9ba6 2020-12-29 op AWK is, in my opinion, an almost perfect scripting language. It is quick, easy to learn and to use (both as a filter in pipe and as a standalone script) and packed with nice and essential features. But it lacks something. I don’t know exactly what, but every time I use it (for more than a one-liner) I get the impression that something is missing.
21 d7de9ba6 2020-12-29 op
22 d7de9ba6 2020-12-29 op Anyway, here’s the script in all its glory. This time I discovered the “next” statement, that unfortunately cannot be used inside a function (probably for a good reason).
23 d7de9ba6 2020-12-29 op
24 d7de9ba6 2020-12-29 op (it’s open to improvements, but at the moment I’m happy with it)
25 d7de9ba6 2020-12-29 op
26 d7de9ba6 2020-12-29 op ```awk
27 d7de9ba6 2020-12-29 op #!/usr/bin/awk -f
28 d7de9ba6 2020-12-29 op
29 d7de9ba6 2020-12-29 op BEGIN {
30 d7de9ba6 2020-12-29 op in_pre = 0;
31 d7de9ba6 2020-12-29 op in_list = 0;
32 d7de9ba6 2020-12-29 op }
33 d7de9ba6 2020-12-29 op
34 d7de9ba6 2020-12-29 op !in_pre && /^###/ { output("<h3>", substr($0, 4), "</h3>"); next }
35 d7de9ba6 2020-12-29 op !in_pre && /^##/ { output("<h2>", substr($0, 3), "</h2>"); next }
36 d7de9ba6 2020-12-29 op !in_pre && /^#/ { output("<h1>", substr($0, 2), "</h1>"); next }
37 d7de9ba6 2020-12-29 op !in_pre && /^>/ { output("<blockquote>", substr($0, 2), "</blockquote>"); next }
38 d7de9ba6 2020-12-29 op !in_pre && /^\*/ { output("<li>", substr($0, 2), "</li>"); next }
39 d7de9ba6 2020-12-29 op
40 d7de9ba6 2020-12-29 op !in_pre && /^=>/ {
41 d7de9ba6 2020-12-29 op $0 = substr($0, 3);
42 d7de9ba6 2020-12-29 op link = $1;
43 d7de9ba6 2020-12-29 op $1 = "";
44 d7de9ba6 2020-12-29 op output_link(link, $0);
45 d7de9ba6 2020-12-29 op next;
46 d7de9ba6 2020-12-29 op }
47 d7de9ba6 2020-12-29 op
48 d7de9ba6 2020-12-29 op !in_pre && /^```/ {
49 d7de9ba6 2020-12-29 op in_pre = 1;
50 d7de9ba6 2020-12-29 op if (in_list) {
51 d7de9ba6 2020-12-29 op in_list = 0;
52 d7de9ba6 2020-12-29 op print("</ul>");
53 d7de9ba6 2020-12-29 op }
54 d7de9ba6 2020-12-29 op print "<pre>";
55 d7de9ba6 2020-12-29 op next
56 d7de9ba6 2020-12-29 op }
57 d7de9ba6 2020-12-29 op
58 d7de9ba6 2020-12-29 op in_pre && /^```/ { in_pre = 0; print "</pre>"; next }
59 d7de9ba6 2020-12-29 op !in_pre { output("<p>", $0, "</p>"); next }
60 d7de9ba6 2020-12-29 op in_pre { print san($0); next }
61 d7de9ba6 2020-12-29 op
62 d7de9ba6 2020-12-29 op END {
63 d7de9ba6 2020-12-29 op if (in_list)
64 d7de9ba6 2020-12-29 op print "</ul>"
65 d7de9ba6 2020-12-29 op if (in_pre)
66 d7de9ba6 2020-12-29 op print "</pre>"
67 d7de9ba6 2020-12-29 op }
68 d7de9ba6 2020-12-29 op
69 d7de9ba6 2020-12-29 op function trim(s) {
70 d7de9ba6 2020-12-29 op sub("^[ \t]*", "", s);
71 d7de9ba6 2020-12-29 op return s;
72 d7de9ba6 2020-12-29 op }
73 d7de9ba6 2020-12-29 op
74 d7de9ba6 2020-12-29 op function san(s) {
75 d7de9ba6 2020-12-29 op gsub("&", "\\&amp;", s)
76 d7de9ba6 2020-12-29 op gsub("<", "\\&lt;", s)
77 d7de9ba6 2020-12-29 op gsub(">", "\\&gt;", s)
78 d7de9ba6 2020-12-29 op return s;
79 d7de9ba6 2020-12-29 op }
80 d7de9ba6 2020-12-29 op
81 d7de9ba6 2020-12-29 op function output(ot, content, et) {
82 d7de9ba6 2020-12-29 op content = trim(content);
83 d7de9ba6 2020-12-29 op
84 d7de9ba6 2020-12-29 op if (!in_list && ot == "<li>") {
85 d7de9ba6 2020-12-29 op in_list = 1;
86 d7de9ba6 2020-12-29 op print "<ul>";
87 d7de9ba6 2020-12-29 op }
88 d7de9ba6 2020-12-29 op
89 d7de9ba6 2020-12-29 op if (in_list && ot != "<li>") {
90 d7de9ba6 2020-12-29 op in_list = 0;
91 d7de9ba6 2020-12-29 op print "</ul>";
92 d7de9ba6 2020-12-29 op }
93 d7de9ba6 2020-12-29 op
94 d7de9ba6 2020-12-29 op if (ot == "<p>" && content == "")
95 d7de9ba6 2020-12-29 op return;
96 d7de9ba6 2020-12-29 op
97 d7de9ba6 2020-12-29 op printf("%s%s%s\n", ot, san(content), et);
98 d7de9ba6 2020-12-29 op }
99 d7de9ba6 2020-12-29 op
100 d7de9ba6 2020-12-29 op function output_link(link, content) {
101 d7de9ba6 2020-12-29 op if (in_list) {
102 d7de9ba6 2020-12-29 op in_list = 0;
103 d7de9ba6 2020-12-29 op print "</ul>";
104 d7de9ba6 2020-12-29 op }
105 d7de9ba6 2020-12-29 op
106 d7de9ba6 2020-12-29 op if (content == "")
107 d7de9ba6 2020-12-29 op content = link;
108 d7de9ba6 2020-12-29 op
109 d7de9ba6 2020-12-29 op printf("<p><a href=\"%s\">%s</a></p>\n", link, trim(san(content)));
110 d7de9ba6 2020-12-29 op }
111 d7de9ba6 2020-12-29 op ```
112 d7de9ba6 2020-12-29 op
113 d7de9ba6 2020-12-29 op Cheers!