commit d7de9ba65a1fdd87735e4358a090dc7285db40f7 from: Omar Polo date: Tue Dec 29 20:54:44 2020 UTC new post commit - 008fd57cb78444d1a54008b0b5fedd65be24248e commit + d7de9ba65a1fdd87735e4358a090dc7285db40f7 blob - /dev/null blob + c84b032e7255a77bf2eb63e0c84e393fe138b1e4 (mode 644) --- /dev/null +++ resources/posts/text-gemini-to-html-with-awk.gmi @@ -0,0 +1,113 @@ +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. + +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. + +=> https://git.omarpolo.com/gmid/about/ gmid repository +=> https://git.omarpolo.com/tango/about/ tango repository + +(they’re only gemini-related things, so using text/gemini for documentational/presentational purpose seems appropriate.) + +I also have a public (HTTP-only for the time being) git repository, powered by cgit. + +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. + +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. + +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. + +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. + +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. + +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). + +(it’s open to improvements, but at the moment I’m happy with it) + +```awk +#!/usr/bin/awk -f + +BEGIN { + in_pre = 0; + in_list = 0; +} + +!in_pre && /^###/ { output("

", substr($0, 4), "

"); next } +!in_pre && /^##/ { output("

", substr($0, 3), "

"); next } +!in_pre && /^#/ { output("

", substr($0, 2), "

"); next } +!in_pre && /^>/ { output("
", substr($0, 2), "
"); next } +!in_pre && /^\*/ { output("
  • ", substr($0, 2), "
  • "); next } + +!in_pre && /^=>/ { + $0 = substr($0, 3); + link = $1; + $1 = ""; + output_link(link, $0); + next; +} + +!in_pre && /^```/ { + in_pre = 1; + if (in_list) { + in_list = 0; + print(""); + } + print "
    ";
    +	next
    +}
    +
    +in_pre && /^```/	{ in_pre = 0; print "
    "; next } +!in_pre { output("

    ", $0, "

    "); next } +in_pre { print san($0); next } + +END { + if (in_list) + print "" + if (in_pre) + print "" +} + +function trim(s) { + sub("^[ \t]*", "", s); + return s; +} + +function san(s) { + gsub("&", "\\&", s) + gsub("<", "\\<", s) + gsub(">", "\\>", s) + return s; +} + +function output(ot, content, et) { + content = trim(content); + + if (!in_list && ot == "
  • ") { + in_list = 1; + print ""; + } + + if (ot == "

    " && content == "") + return; + + printf("%s%s%s\n", ot, san(content), et); +} + +function output_link(link, content) { + if (in_list) { + in_list = 0; + print ""; + } + + if (content == "") + content = link; + + printf("

    %s

    \n", link, trim(san(content))); +} +``` + +Cheers! blob - 76aec8e5fef73ce12b0852abac46805588fdb5df blob + 148eddbb4406787e96f2297ab780c8b790ab15af --- resources/posts.edn +++ resources/posts.edn @@ -1,4 +1,12 @@ -[{:title "The joy of elisp: an example" +[{:title "text/gemini to HTML with AWK" + :slug "text-gemini-to-html-with-awk" + :date "2020/12/29" + :tags #{:awk :gemini :git} + :short "Fun with AWK and text/gemini" + :gemtext? true + :music {:title "Venice Queen" + :by "Red Hot Chili Peppers"}} + {:title "The joy of elisp: an example" :slug "joy-of-elisp-sndio" :date "2020/12/28" :tags #{:literate-programming :lisp :emacs :OpenBSD}