2024-08-16 [src]

A Blog: better late than never

I've got a blog now! One less place safe from my ramblings & infamous hot takes!

code, web, confgen, lua


Hello readers!

Yes, yes, your friendly neighborhood madman now finally did something with his website. Truth be told, I've long been looking for some place to dump my thoughts, but have always been held back by a mix of laziness, and the fact that this website used to be generated with Zola, a static generator that has generally been a pain to work with, probably because it tried to force design paradigms onto me that I didn't necessarily agree with.

After half a day of coding, this whole website is now generated by Confgen, my beloved template engine based on Lua, initially built for config files (don't ask). If you're interested in how exactly this works, the website is open source as is my moral obligation, but I'll also explain in a bit. My friend Marcius, who had this idea first also wrote a more in-depth article about this concept on his blog (currently doesn't seem to be up anywhere, I'll add a link here once someone finds it).

What you'll read here

I'm a programmer, have quite unconventional political views, and this is my anything goes-zone. I'll tell you why X sucks, why Y is great and why society should stop doing Z already. Also, expect extremely technical and perhaps lengthy articles on whatever comes to my mind and, of course, rants.

The technicalities

As I've mentioned, this is built with my custom template engine, Confgen. The core principles of Confgen are too much to go over here and are explained in their own article.

Taking that knowledge not a single person in the world besides me posesses for granted, let's get to some of the specialties I employed here:

Markdown

Confgen does not natively support Markdown. This is by design, because if we start supporting every little thing someone once came up with, we'll find ourselves with an unmaintainable dumpster fire in no time. Instead, Confgen build on a mature ecosystem, offering unparalleled flexibility (for a template engine, anyways). All Lua code runs under Confgen!

Utilizing that incredibly neat fact, I implemented Markdown rendering with the cmark-lua library, a set of Lua bindings for the CMark library. CMark not only offers the full set of Markdown features (especially including the surprisingly scarcely supported code blocks I'll get into soon), but unlike other libraries doesn't just spit out the rendered HTML, but also offers access to an Abstract Syntax Tree (AST) of the markdown source, that can be manipulated to one's will. This is what allowed me to have...

Syntax Highlighting

...which is a gigantic pain, by the way.

Your average, run-of-the-mill webdev (eww) would've probably just thrown PrismJS or insert JS framework that is holding onto survival at the time of reading here at it, but kind as I am, I decided to offer you pre-highlighted code on here, so your browser doesn't have to do it! Instead, I decided to go on a long and arduous journey for CLI tools (Lua libraries were a lost cause) that can:

Surprise, surprise, that doesn't exist, especially because Zig support was a must. My solution was to beat some tool not meant for this whatsoever into submission, as I like to do. Today's victim was Bat, which ticks the first two boxes, but disappointingly leaves the third unchecked, only outputting ANSI (=terminal)-formatted data. Luckily, there exists a tool called ANSI HTML Adapter that can convert Bat's output.

The only lacking step now was to integrate this into Confgen, which was easy enough.

-- Parse the Markdown source. UNSAFE signifies that we don't want to sanitize the input.
local doc = cmark.parse_document(src, string.len(src), cmark.OPT_UNSAFE)

-- Iterate over all nodes
for cur, entering, node_type in cmark.walk(doc) do
    if not entering then
    -- If we found a code block and are entering the node...
    if entering and node_type == cmark.NODE_CODE_BLOCK then
        -- Get its language
        local lang = cmark.node_get_fence_info(cur)

        -- If the language is not unspecified
        if #lang > 0 then
            -- Invoke Bat and AHA, writing the HTML code to a temporary file.
            local tmpfp = os.tmpname()
            local proc = io.popen(
                "bat --color always --style plain --language " .. lang .. " | aha --no-header >" .. tmpfp,
                "w"
            )
            proc:write(cmark.node_get_literal(cur))
            proc:close()

            -- Replace the code block node with the generated HTML
            local tmpf = io.open(tmpfp, "r")
            local new = cmark.node_new(cmark.NODE_HTML_BLOCK)
            cmark.node_set_literal(new, [[<pre class="codeblock"><code>]] .. tmpf:read "*a" .. [[</code></pre>]])
            cmark.node_replace(cur, new)
            tmpf:close()
            os.remove(tmpfp)
        end
    end
end

return cmark.render_html(doc, cmark.OPT_UNSAFE)

Works a charm, doesn't it?

API (or one generated JSON file to be precise)

The index of articles on mzte.de is not static gen'd, although that'd be easier, but instead produced by some Javashit JavaScript code to facilitate a future tagging and filtering system I've got planned. As a consequence of this, a JSON-based index of articles you may use at your leisure is to be found here. It looks somewhat like this, but this is subject to change without warning:

[ // Oldest first
    {
        "id": "0001-a-blog-better-late-than-never",
        "title": "A Blog: better late than never",
        "summary": "I've got a blog now! One less place safe from my ramblings & infamous hot takes!",
        "date": "2024-08-16",
        "tags": [ "code", "web", "confgen", "lua" ]
    }
]

That's pretty much all there is to it. I hope you've enjoyed this quick read and here's to many more!