<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
    <title>lozinka</title>
    <link>https://lozinka.duckdns.org</link>
    <description>latest posts</description>
    <language>en</language>
    <lastBuildDate>Fri, 11 Sep 2026 00:00:00 GMT</lastBuildDate>
    <atom:link href="https://lozinka.duckdns.org/rss.xml" rel="self" type="application/rss+xml"/>
    <item>
        <title>Writing a static site generator</title>
        <link>https://lozinka.duckdns.org/stuff/03-ssg/</link>
        <guid isPermaLink="true">https://lozinka.duckdns.org/stuff/03-ssg/</guid>
        <pubDate>Fri, 11 Sep 2026 00:00:00 GMT</pubDate>
        <description><![CDATA[<p>I wanted a blog. So now I have one. Reaching for Hugo or Jekyll seemed like the obvious move, until I noticed the sheer overhead of setting either one up. They're great tools, but neither is as simple to use as the 250-line generator I wrote myself. Here's how I built it, and how it's working out so far.</p>
<h2>Why not use an already-existing tool?</h2>
<ol>
<li>It's a personal blog for my own rants, not a sophisticated site with a mountain of content. I will never have so many posts that rendering speed becomes something to worry about. The features I actually need are headings, basic text formatting, images. Writing a generator around just those, means its configuration and behavior are made for me, not for every use case a general-purpose tool has to support.</li>
<li>Portability. My generator has no external dependencies making it run anywhere Python is installed. There's no install step, no configuration file, no lockfile to keep in sync. It will work the same way in ten years as it does today, which isn't a guarantee I can make about a Hugo or Jekyll setup, where a toolchain upgrade can quietly break a build.</li>
<li>When something fails or breaks in my generator, I have to understand the issue myself, work out a fix, and apply it without framework abstraction standing between me and the bug. Since I know exactly what my generator does and how, fixing an issue or adding a new feature is far more appealing than digging through someone else's plugin system.</li>
<li>The only job of this generator is to turn Markdown into HTML, so adopting an existing tool means adopting its entire ecosystem, including a long list of features I'll never use.</li>
</ol>
<p>None of this means Hugo is a bad tool. It just means that, for a project this size, the framework overshadows the actual purpose and ends up overwhelming the person using it.</p>
<h2>Design decisions</h2>
<p>There's exactly one template in the entire generator:</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
...
&lt;title&gt;{title}&lt;/title&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;{css_href}&quot;&gt;
&lt;/head&gt;
&lt;body&gt;
{back_link}{content}
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>I wanted to stay clear of Jinja, to avoid a &quot;language within a language&quot; situation and to avoid pulling in a dependency I don't actually need. A nice side effect of using plain <code>.format()</code> instead of a templating engine is that I never re-parse the page content; only the template string itself gets scanned for placeholders. In practice this means that if a post happens to contain a literal <code>{placeholder}</code> looking string it won't break rendering. I'm glad I didn't start out building templates with f-strings and several layers of string concatenation instead, because I suspect I'd have run into exactly that problem.</p>
<p>The build itself is a single walk over the content directory using <code>os.walk</code>. For every folder, it builds a listing of that folder's contents, any non-Markdown file is copied to the output directory unchanged and every post gets its own directory - <code>example/index.html</code> instead of <code>example.html</code>, so the url is left without a file extension. If a directory contains an <code>index.md</code> file, its contents are rendered as the intro text on that folder's listing page, shown above the generated list of posts.</p>
<p>The sitemap is built as a second pass over the output searching for every <code>index.html</code>. Of course this could be achieved in the first pass over the content directory instead of being redone afterward, but it works, and for now that's what matters.</p>
<p>One decision made purely for simplicity was to re-render every page on every run rather than build incrementally. I expected that to have a real impact on build time, but in practice a full rebuild takes less than <code>0.1s</code>, so until my site is large enough for that to matter, it's not worth the added complexity of caching or change detection.</p>
<p>The one feature I still consider genuinely important, and haven't built yet, is a live preview. Right now, checking how a post looks means switching to a terminal tab, re-running the build, starting an HTTP server, and switching to the browser every single time I make an edit. That loop is tedious enough to discourage small revisions, which is the opposite of what a writing tool should do. It's the next thing on my list.</p>
<h2>Where this leaves me</h2>
<p>The generator does exactly what I need and nothing else, which was the whole point. All the other features offered by existing tools can be easily built into my own version if I would ever have decided that they are needed for my purposes.</p>]]></description>
    </item>
    <item>
        <title>Fedora as my new main</title>
        <link>https://lozinka.duckdns.org/stuff/02-fedora/</link>
        <guid isPermaLink="true">https://lozinka.duckdns.org/stuff/02-fedora/</guid>
        <pubDate>Sun, 30 Aug 2026 00:00:00 GMT</pubDate>
        <description><![CDATA[<p>For nearly 4 years i used archlinux. I started using it when i didn't understand linux at all. But you learn the most from your own mistakes. Now i can say that i am an advanced linux user and the terminal feels like home, but constantly nursing my own OS is not my idea of fun.</p>
<p>The shift happened subtly, when over time i stumbled upon more and more random issues with the kernel, graphics drivers or the network. Not to mention mismatched software lacking any mutual coherence. When life got busy I didn't have time to debug my system and i even installed windows to get my system working (it turned out to be an immovable obstacle in my way of working, and i ended up with linux mint or ubuntu).</p>
<p>Moving on to a distro that puts my sanity first was in the top 10 best decisions i made this year. After half a year i'm still amazed how much easier life got when my system doesn't need constant attention.</p>
<p>Archlinux was the best teacher i had and i'm glad i stuck with him for so long.</p>
<p><em>all's well, that ends well</em> ~Belmondawg</p>]]></description>
    </item>
    <item>
        <title>Test file</title>
        <link>https://lozinka.duckdns.org/stuff/01-test/</link>
        <guid isPermaLink="true">https://lozinka.duckdns.org/stuff/01-test/</guid>
        <pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate>
        <description><![CDATA[<h2>Heading 2</h2>
<h3>Heading 3</h3>
<p><em>Italic</em>, <strong>Bold</strong>, <strong><em>Both</em></strong>, <del>Strikethrough</del>, <code>Inline Code</code>, and <a href="https://example.com">Link</a>.</p>
<ul>
<li>Unordered item</li>
<li>More items</li>
<li>And some more</li>
</ul>
<ol>
<li>Ordered item</li>
<li>More items</li>
<li>And some more</li>
</ol>
<pre><code># comment
def add(a, b):
    return a + b</code></pre>
<p><img src="https://lozinka.duckdns.org/stuff/markdown.webp" alt="Markdown"></p>]]></description>
    </item>
    </channel>
</rss>
