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 fec02a6b 2021-02-13 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 chance 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 bb54dbe9 2021-08-03 op EDIT 2021/02/03: after seeing another decoder, I took some time to refactor the original converter. I reordered the matches so the pre handling is before everything else.
27 fec02a6b 2021-02-13 op
28 fec02a6b 2021-02-13 op => https://gist.github.com/dracometallium/bf70ae09b4dd9a857d33e93daa2810c4 dracometallium’ gmi2html.awk
29 fec02a6b 2021-02-13 op
30 d7de9ba6 2020-12-29 op ```awk
31 d7de9ba6 2020-12-29 op #!/usr/bin/awk -f
32 d7de9ba6 2020-12-29 op
33 d7de9ba6 2020-12-29 op BEGIN {
34 d7de9ba6 2020-12-29 op in_pre = 0;
35 d7de9ba6 2020-12-29 op in_list = 0;
36 d7de9ba6 2020-12-29 op }
37 d7de9ba6 2020-12-29 op
38 d7de9ba6 2020-12-29 op !in_pre && /^```/ {
39 d7de9ba6 2020-12-29 op in_pre = 1;
40 d7de9ba6 2020-12-29 op if (in_list) {
41 d7de9ba6 2020-12-29 op in_list = 0;
42 d7de9ba6 2020-12-29 op print("</ul>");
43 d7de9ba6 2020-12-29 op }
44 d7de9ba6 2020-12-29 op print "<pre>";
45 d7de9ba6 2020-12-29 op next
46 d7de9ba6 2020-12-29 op }
47 d7de9ba6 2020-12-29 op in_pre && /^```/ { in_pre = 0; print "</pre>"; next }
48 d7de9ba6 2020-12-29 op in_pre { print san($0); next }
49 d7de9ba6 2020-12-29 op
50 fec02a6b 2021-02-13 op /^###/ { output("<h3>", substr($0, 4), "</h3>"); next }
51 fec02a6b 2021-02-13 op /^##/ { output("<h2>", substr($0, 3), "</h2>"); next }
52 fec02a6b 2021-02-13 op /^#/ { output("<h1>", substr($0, 2), "</h1>"); next }
53 fec02a6b 2021-02-13 op /^>/ { output("<blockquote>", substr($0, 2), "</blockquote>"); next }
54 fec02a6b 2021-02-13 op /^\*/ { output("<li>", substr($0, 2), "</li>"); next }
55 fec02a6b 2021-02-13 op
56 fec02a6b 2021-02-13 op /^=>/ {
57 fec02a6b 2021-02-13 op $0 = substr($0, 3);
58 fec02a6b 2021-02-13 op link = $1;
59 fec02a6b 2021-02-13 op $1 = "";
60 fec02a6b 2021-02-13 op output_link(link, $0);
61 fec02a6b 2021-02-13 op next;
62 fec02a6b 2021-02-13 op }
63 fec02a6b 2021-02-13 op
64 fec02a6b 2021-02-13 op // { output("<p>", $0, "</p>"); next }
65 fec02a6b 2021-02-13 op
66 d7de9ba6 2020-12-29 op END {
67 d7de9ba6 2020-12-29 op if (in_list)
68 d7de9ba6 2020-12-29 op print "</ul>"
69 d7de9ba6 2020-12-29 op if (in_pre)
70 d7de9ba6 2020-12-29 op print "</pre>"
71 d7de9ba6 2020-12-29 op }
72 d7de9ba6 2020-12-29 op
73 d7de9ba6 2020-12-29 op function trim(s) {
74 d7de9ba6 2020-12-29 op sub("^[ \t]*", "", s);
75 d7de9ba6 2020-12-29 op return s;
76 d7de9ba6 2020-12-29 op }
77 d7de9ba6 2020-12-29 op
78 d7de9ba6 2020-12-29 op function san(s) {
79 d7de9ba6 2020-12-29 op gsub("&", "\\&amp;", s)
80 d7de9ba6 2020-12-29 op gsub("<", "\\&lt;", s)
81 d7de9ba6 2020-12-29 op gsub(">", "\\&gt;", s)
82 d7de9ba6 2020-12-29 op return s;
83 d7de9ba6 2020-12-29 op }
84 d7de9ba6 2020-12-29 op
85 fec02a6b 2021-02-13 op function output(ot, content, ct) {
86 d7de9ba6 2020-12-29 op content = trim(content);
87 d7de9ba6 2020-12-29 op
88 d7de9ba6 2020-12-29 op if (!in_list && ot == "<li>") {
89 d7de9ba6 2020-12-29 op in_list = 1;
90 d7de9ba6 2020-12-29 op print "<ul>";
91 d7de9ba6 2020-12-29 op }
92 d7de9ba6 2020-12-29 op
93 d7de9ba6 2020-12-29 op if (in_list && ot != "<li>") {
94 d7de9ba6 2020-12-29 op in_list = 0;
95 d7de9ba6 2020-12-29 op print "</ul>";
96 d7de9ba6 2020-12-29 op }
97 d7de9ba6 2020-12-29 op
98 d7de9ba6 2020-12-29 op if (ot == "<p>" && content == "")
99 d7de9ba6 2020-12-29 op return;
100 d7de9ba6 2020-12-29 op
101 fec02a6b 2021-02-13 op printf("%s%s%s\n", ot, san(content), ct);
102 d7de9ba6 2020-12-29 op }
103 d7de9ba6 2020-12-29 op
104 d7de9ba6 2020-12-29 op function output_link(link, content) {
105 d7de9ba6 2020-12-29 op if (in_list) {
106 d7de9ba6 2020-12-29 op in_list = 0;
107 d7de9ba6 2020-12-29 op print "</ul>";
108 d7de9ba6 2020-12-29 op }
109 d7de9ba6 2020-12-29 op
110 d7de9ba6 2020-12-29 op if (content == "")
111 d7de9ba6 2020-12-29 op content = link;
112 d7de9ba6 2020-12-29 op
113 d7de9ba6 2020-12-29 op printf("<p><a href=\"%s\">%s</a></p>\n", link, trim(san(content)));
114 d7de9ba6 2020-12-29 op }
115 d7de9ba6 2020-12-29 op ```
116 d7de9ba6 2020-12-29 op
117 d7de9ba6 2020-12-29 op Cheers!