<rss version="2.0">
  <channel>
    <title>Oto Šťáva</title>
    <link>https://spiffyk.cz</link>
    <description>Oto Šťáva - Blog</description>
    <generator>Zine -- https://zine-ssg.io</generator>
    <language>en-US</language>
    <lastBuildDate>Thu, 04 Jun 2026 07:29:47 +0000</lastBuildDate>
    
      <item>
        <title>Newlines in bad places</title>
        <description>&lt;p&gt;So it turns out that if you violate standards, &lt;em&gt;bad things happen&lt;/em&gt;.  Who woulda thought?&lt;/p&gt;&lt;p&gt;For the longest time, I’ve had this little problem with my web server, in that &lt;em&gt;some&lt;/em&gt; clients would refuse to load it.  The major ones worked – Firefox, Chromium, cURL, Android apps – all of them good.  The first time I encountered this problem was when I was working on hardening the web server’s security (TLS, CSP, that kind thing).  I would test the site with &lt;a href=&quot;https://developer.mozilla.org/en-US/observatory&quot; target=&quot;_blank&quot;&gt;Mozilla Observatory&lt;/a&gt;, only for it to fail with a vague error message that the site couldn’t be loaded.&lt;/p&gt;&lt;p&gt;Since everything else worked, I didn’t put too much thought to it back then. Maybe there was some weird issue that maybe the Observatory had &lt;a href=&quot;https://www.scaleway.com/en/&quot; target=&quot;_blank&quot;&gt;Scaleway&lt;/a&gt;—my current VPS host—banned for some reason?  I left it at that for some time.&lt;/p&gt;&lt;p&gt;&lt;figure&gt;&lt;a href=&quot;https://spiffyk.cz/blog/http-newlines/observatory-error.png&quot;&gt;&lt;img src=&quot;https://spiffyk.cz/blog/http-newlines/observatory-error.png&quot; width=&quot;1453&quot; height=&quot;437&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;Observatory showing a vague error&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;&lt;p&gt;But then, the issue kept turning up in other places.  I’ve been setting up &lt;a href=&quot;https://ogp.me/&quot; target=&quot;_blank&quot;&gt;OpenGraph&lt;/a&gt; for the website, testing it with various tools. Some would work well, but others would fail.  Again, with no helpful messages, everything along the lines of &lt;em&gt;“something went wrong”&lt;/em&gt; or &lt;em&gt;“is the site down?”&lt;/em&gt;. &lt;em&gt;No, it isn’t! I’m looking at it in my browser, dammit!&lt;/em&gt; &lt;a href=&quot;https://joinmastodon.org/&quot; target=&quot;_blank&quot;&gt;Mastodon&lt;/a&gt; would seemingly ignore my OpenGraph tags, while other services happily showed pretty links. I kept debugging, to no avail. &lt;a href=&quot;https://www.ssllabs.com/ssltest/&quot; target=&quot;_blank&quot;&gt;SslLabs&lt;/a&gt; worked fine.  Nginx’s debug log turned up nothing useful – clients would do the proper TLS handshake, receive the HTTP headers, then close the connection.  I couldn’t, for the life of me, figure it out.  So I gave up for several more months. My actual use cases weren’t hindered, so I just couldn’t be bothered.&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&lt;em&gt;Fast-forward to today.&lt;/em&gt;  Out of curiosity, I tried to open my website in a nightly build of &lt;a href=&quot;https://servo.org/&quot; target=&quot;_blank&quot;&gt;Servo&lt;/a&gt;.  It, like other random clients, would refuse to load up the site:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Servo could not load the requested page: client error (SendRequest)&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;As with all the other offenders, not a very helpful message.  I tried searching for the message.  Turns out the format is common for various Rust projects using the &lt;a href=&quot;https://github.com/seanmonstar/reqwest&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;reqwest&lt;/code&gt;&lt;/a&gt; crate, among them &lt;a href=&quot;https://deno.com&quot; target=&quot;_blank&quot;&gt;Deno&lt;/a&gt;, a JavaScript runtime.  I found an issue on Deno’s GitHub about a similar, but ultimately unrelated problem – something about a proxy, not interesting to me. But I got curious.  I took the reporter’s script, removed the proxy option and swapped the URL to my website:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;constructor constant variable_builtin function_builtin variable&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;constructor constant variable_builtin function_builtin variable&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constructor constant variable_builtin function_builtin variable&quot;&gt;Deno&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;createHttpClient&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;constructor constant variable_builtin function_builtin variable function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;https://spiffyk.cz&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I ran it with Deno and…  &lt;strong&gt;bingo!&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;error: Uncaught (in promise) TypeError: error sending request from *snip* for https://spiffyk.cz/ (*snip*):
       client error (SendRequest): invalid HTTP header parsed
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I started digging through my Nginx configs, then I found it:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;add_header &amp;quot;Content-Security-Policy&amp;quot;
    &amp;quot;default-src &amp;apos;self&amp;apos;;
    object-src &amp;apos;none&amp;apos;;&amp;quot; always;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In an attempt (a &lt;em&gt;bad&lt;/em&gt; one at that, now that I’m looking at it) to make the config more readable, I’ve split the CSP directives onto multiple lines.  Since neither Nginx nor my web browsers ever complained (not even in devtools), I never gave it much more thought and assumed Nginx would replace the newline with a space.  It wouldn’t.  It just pasted that newline right into the HTTP response.  Many clients, adhering to the infamous “Postel’s law&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn-1&quot; id=&quot;fn-1-ref-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;,” just swallowed that right up.  Others—rightfully, in my opinion—refused.  Turns out violating RFCs just doesn’t pay off.&lt;/p&gt;&lt;p&gt;Well, easy fix.  I merged the directives onto a single line, and one &lt;code&gt;systemctl reload nginx&lt;/code&gt; later, everything works!  So I can finally be proud of my &lt;strong&gt;A+&lt;/strong&gt; score in Observatory, and show you our cat every time I share a link to my blog:&lt;/p&gt;&lt;p&gt;&lt;figure&gt;&lt;a href=&quot;https://spiffyk.cz/blog/http-newlines/works-on-mastodon.png&quot;&gt;&lt;img src=&quot;https://spiffyk.cz/blog/http-newlines/works-on-mastodon.png&quot; width=&quot;1027&quot; height=&quot;247&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;A rich link on Mastodon leading to my website, accompanied by a photo of our cat&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;</description>
        <link>https://spiffyk.cz/blog/http-newlines/</link>
        <pubDate>Mon, 09 Mar 2026 00:00:00 +0000</pubDate>
        <guid>https://spiffyk.cz/blog/http-newlines/</guid>
      </item>
    
      <item>
        <title>So we made a game</title>
        <description>&lt;p&gt;&lt;figure&gt;&lt;a href=&quot;https://spiffyk.cz/blog/fruits-and-tails/fruitsandtails.png&quot;&gt;&lt;img src=&quot;https://spiffyk.cz/blog/fruits-and-tails/fruitsandtails.png&quot; width=&quot;2560&quot; height=&quot;1440&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;A screenshot of Fruits &amp; Tails&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;&lt;p&gt;After a year of on-and-off work, one of my long-term dreams has come true; that is, to create—and actually finish—a project together with &lt;a href=&quot;http://zuzaslavik.com&quot; target=&quot;_blank&quot;&gt;Zuzka&lt;/a&gt;, my beloved partner in crime.  What we created is in terms of mechanics a tiny game, a sort of remix of &lt;a href=&quot;https://en.wikipedia.org/wiki/Connect_Four&quot; target=&quot;_blank&quot;&gt;four-in-a-row&lt;/a&gt;, but with &lt;em&gt;cute squirrels&lt;/em&gt;, flashy animations, a nice tutorial, and &lt;em&gt;the grid is hexagonal&lt;/em&gt; instead of square.  As expected, I was responsible for the coding, while Zuzka designed all of the UX/UI, as well as all of the &lt;em&gt;super cute&lt;/em&gt; hand-drawn art.&lt;/p&gt;&lt;p&gt;Our game is called &lt;em&gt;Fruits &amp; Tails&lt;/em&gt; and you can play it right now on your PC, phone, tablet, or whatever device with a modern-enough web browser you have on hand, at &lt;strong&gt;&lt;a href=&quot;https://fruitsandtails.fghj.cz/&quot; target=&quot;_blank&quot;&gt;FruitsAndTails.fghj.cz&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;&lt;hr&gt;&lt;p&gt;Fruits &amp; Tails is completely hand-made.  It was written in &lt;a href=&quot;https://ziglang.org/&quot; target=&quot;_blank&quot;&gt;Zig&lt;/a&gt;, with its only external dependencies being the standard library, Web APIs (mostly &lt;code&gt;CanvasRenderingContext2D&lt;/code&gt; and input events), and &lt;a href=&quot;https://lisperator.net/uglifyjs/&quot; target=&quot;_blank&quot;&gt;UglifyJS&lt;/a&gt; – the last one being optional to make release builds as small as possible.  We’re not even using any ready-made glue code of the WASI or Emscripten kind – the glue to interact with the Web APIs is just a 600-line &lt;code&gt;index.js&lt;/code&gt; file, hand-rolled on an as-needed basis.  All this makes for a neat package of &lt;strong&gt;5.1 MiB&lt;/strong&gt; (compiled in &lt;code&gt;ReleaseSmall&lt;/code&gt; mode, with JavaScript minification), of which 4.8 MiB are the art assets.&lt;/p&gt;&lt;p&gt;Currently, you can play this with a friend, offline, on a single device.  The plan, though, is to also add a way to play online, and I’ve already been cooking up an algorithmic opponent (you know, AI, but &lt;em&gt;the good kind&lt;/em&gt;) that is already quite competent at playing the game, so that’s coming in an update soon-ish.&lt;/p&gt;&lt;p&gt;If you want to know more about our little journey, stay tuned!  I’m going to touch on the brief history of the game, as well as some of the inner workings of its engine.  I’m also planning to release the source code, so if you are looking into Zig—specifically in conjunction with WebAssembly—it might just turn out to be a helpful resource.&lt;/p&gt;&lt;p&gt;You can subscribe to this blog’s &lt;a href=&quot;https://spiffyk.cz/blog/index.xml&quot;&gt;RSS feed&lt;/a&gt; or &lt;a href=&quot;https://mastodon.social/@alefunguju&quot; target=&quot;_blank&quot;&gt;follow me on Mastodon&lt;/a&gt; to stay up to date!&lt;/p&gt;</description>
        <link>https://spiffyk.cz/blog/fruits-and-tails/</link>
        <pubDate>Mon, 15 Dec 2025 00:00:00 +0000</pubDate>
        <guid>https://spiffyk.cz/blog/fruits-and-tails/</guid>
      </item>
    
      <item>
        <title>Diffing Word and Writer documents with Git</title>
        <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; &lt;a href=&quot;#configuration&quot;&gt;Skip my blabbing and go directly to the configuration&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;figure&gt;&lt;a href=&quot;https://spiffyk.cz/blog/git-pandoc/forgejo-diff.png&quot;&gt;&lt;img src=&quot;https://spiffyk.cz/blog/git-pandoc/forgejo-diff.png&quot; width=&quot;1343&quot; height=&quot;969&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;Diff of a DOCX file with a review comment in Forgejo&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;&lt;p&gt;At my day job, we have recently been evaluating &lt;a href=&quot;https://forgejo.org&quot; target=&quot;_blank&quot;&gt;Forgejo&lt;/a&gt;—obviously primarily for hosting of our software sources with Git—but we have also been pondering other possible use-cases.  Since the company is pretty small, we want to keep the number of tools we use rather low, so as to keep the system-administrative workload at a minimum.&lt;/p&gt;&lt;p&gt;One such pondered use-case for Forgejo is the review of non-technical legal and policy documents.  These are generally created with Microsoft Word (&lt;code&gt;docx&lt;/code&gt;) and/or LibreOffice Writer (&lt;code&gt;odt&lt;/code&gt;), from templates, complete with the company’s standardized visual identity.  To emphasize, the goal of this endeavour &lt;strong&gt;cannot&lt;/strong&gt; be that my non-technical colleagues will magically switch from Word to Markdown, reStructuredText, or LaTeX.  That may be my perfectionist-programmer-ass pipe dream, but we live in the real world.&lt;/p&gt;&lt;p&gt;So the question is this: can we get Git and Forgejo to show meaningful differences between two versions of a Word/Writer document?  Spoiler: the answer is of course &lt;strong&gt;yes&lt;/strong&gt;, but first, let’s look at what failed (or you can always go &lt;a href=&quot;#configuration&quot;&gt;TL;DR&lt;/a&gt;).&lt;/p&gt;&lt;h2&gt;What does &lt;em&gt;not&lt;/em&gt; work&lt;/h2&gt;&lt;p&gt;At this point I think it is pretty common knowledge amongst the tech-savvy crowd that both &lt;code&gt;docx&lt;/code&gt; and &lt;code&gt;odt&lt;/code&gt; are “just” specifically structured ZIP archives containing a bunch of XML files and assets (like images) that comprise the document.  My initial idea then was very simple – could we get Word and Writer to open and edit documents &lt;em&gt;unpacked&lt;/em&gt;?  That way, we could simply keep the whole structure in a Git repository, making diffing and even &lt;em&gt;merging&lt;/em&gt; pretty easy, since XML is a text-based format.&lt;/p&gt;&lt;p&gt;Unfortunately, Writer only supports working with properly packaged documents and a cursory internet search indicated that Word is the same in this regard. I have checked with LibreOffice both in the GUI, which offers no way of opening entire directories, as well as trying to make it run with the terminal. Simply running &lt;code&gt;libreoffice .&lt;/code&gt; in a directory containing an unpacked document results in LibreOffice not even starting – it shows the splash screen, then exits with code &lt;code&gt;0&lt;/code&gt; as if everything was cool and dandy.&lt;/p&gt;&lt;p&gt;While I was at it, I also took a look at an ODT’s XML files in a text editor.  I really should not be surprised, but apart from the nicely formatted &lt;code&gt;manifest.rdf&lt;/code&gt;, all of the other XML documents are simply dumped on a single line.  This would make diffing quite the nightmare.  Even if I did some automated reformatting, the &lt;a href=&quot;https://en.wikipedia.org/wiki/Office_Open_XML&quot; target=&quot;_blank&quot;&gt;OOXML&lt;/a&gt; format used by Office would still be &lt;a href=&quot;https://hsu.cy/2025/09/is-ooxml-artificially-complex/#ooxml-as-a-sloppy-standard&quot; target=&quot;_blank&quot;&gt;quite unreadable due to historical cruft&lt;/a&gt;.  Not to mention that I probably cannot expect non-techies to dig through XML syntax while reviewing document changes.&lt;/p&gt;&lt;p&gt;Again, none of this is particularly surprising.  The files are not really meant to be perused by humans.  But it further drives the point home that this approach is not really feasible.&lt;/p&gt;&lt;h2&gt;Pandoc to the rescue&lt;/h2&gt;&lt;p&gt;So, as a surprise to virtually no-one, Git is &lt;em&gt;really&lt;/em&gt; powerful.  One source of this power is that you can hook arbitrary programs to many parts of its mechanism, modifying the outcome.  Today, we are going to be using the &lt;a href=&quot;https://git-scm.com/docs/gitattributes#_generating_diff_text&quot; target=&quot;_blank&quot;&gt;diff drivers&lt;/a&gt;, to hook programs to the diffing mechanism in Git. Diff drivers can be declared by adding &lt;code&gt;[diff &amp;quot;driver-name&amp;quot;]&lt;/code&gt; sections in your &lt;a href=&quot;https://git-scm.com/docs/git-config#FILES&quot; target=&quot;_blank&quot;&gt;Git configuration&lt;/a&gt;, allowing us to change &lt;code&gt;git diff&lt;/code&gt;’s behaviour quite substantially – we can even completely substitute the diffing program this way. What we are currently interested in the most, though, is the &lt;code&gt;textconv&lt;/code&gt; property.&lt;/p&gt;&lt;p&gt;In simple terms, &lt;code&gt;textconv&lt;/code&gt; allows Git to call upon an arbitrary program to do a one-way conversion from an arbitrary file format to a preferably plain-text representation.  Emphasis on &lt;em&gt;one-way&lt;/em&gt;, because this is really only useful for reviewing diffs.  You &lt;em&gt;cannot&lt;/em&gt; use this to patch files.&lt;/p&gt;&lt;h2 id=&quot;configuration&quot;&gt;How to actually configure this&lt;/h2&gt;&lt;p&gt;First, make sure you have &lt;code&gt;pandoc&lt;/code&gt; installed.  It is available in most of the major Linux distributions’ repositories, so just call upon your &lt;code&gt;apt&lt;/code&gt;, &lt;code&gt;pacman&lt;/code&gt;, or whatever floats your distro’s boat.&lt;/p&gt;&lt;div class=&quot;block note&quot;&gt;&lt;p&gt; &lt;strong&gt;Update (2025-09-12):&lt;/strong&gt; Shortly after publishing the post it was brought to my attention that &lt;code&gt;pandoc&lt;/code&gt; may access external files when run on certain types of untrusted inputs.  Based on my understanding of &lt;a href=&quot;https://pandoc.org/demo/example33/21-a-note-on-security.html&quot; target=&quot;_blank&quot;&gt;Pandoc’s official note on security&lt;/a&gt; this should not be a problem for &lt;code&gt;odt&lt;/code&gt;/&lt;code&gt;docx&lt;/code&gt; inputs and Markdown outputs, but other combinations might be risky.  It is recommended—especially when dealing with untrusted files—to use the &lt;code&gt;--sandbox&lt;/code&gt; option when calling Pandoc like this.  The examples in this post were amended to include the &lt;code&gt;--sandbox&lt;/code&gt; option to be on the safe side.&lt;/p&gt;&lt;/div&gt;&lt;h3&gt;Git&lt;/h3&gt;&lt;p&gt;Once &lt;code&gt;pandoc&lt;/code&gt; is installed, define this &lt;a href=&quot;https://git-scm.com/docs/gitattributes#_generating_diff_text&quot; target=&quot;_blank&quot;&gt;diff driver&lt;/a&gt; in your &lt;a href=&quot;https://git-scm.com/docs/git-config#FILES&quot; target=&quot;_blank&quot;&gt;Git configuration&lt;/a&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;ini&quot;&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;diff&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;pandoc&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;property&quot;&gt;textconv&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;pandoc&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;--sandbox&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;--to&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;markdown&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, to actually use the driver, you also need to configure &lt;a href=&quot;https://git-scm.com/docs/gitattributes#_performing_text_diffs_of_binary_files&quot; target=&quot;_blank&quot;&gt;Git attributes&lt;/a&gt; for &lt;code&gt;odt&lt;/code&gt; and &lt;code&gt;docx&lt;/code&gt; files.  You may do that either globally in your &lt;code&gt;~/.config/git/attributes&lt;/code&gt; file, or in a &lt;code&gt;.gitattributes&lt;/code&gt; file inside of your repositories:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;conf&quot;&gt;*.odt diff=pandoc
*.docx diff=pandoc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that &lt;code&gt;pandoc&lt;/code&gt; only supports the newer &lt;code&gt;docx&lt;/code&gt; format and not &lt;code&gt;doc&lt;/code&gt;. Hopefully nobody is using that old thing anymore, but just so you know.&lt;/p&gt;&lt;h3&gt;Forgejo&lt;/h3&gt;&lt;p&gt;If you want to do this same transformation in &lt;a href=&quot;https://forgejo.org&quot; target=&quot;_blank&quot;&gt;Forgejo&lt;/a&gt;’s diffs, you may put this &lt;a href=&quot;https://forgejo.org/docs/latest/admin/config-cheat-sheet/#git---config-options-gitconfig&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;[git.config]&lt;/code&gt; section in your &lt;code&gt;app.ini&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;ini&quot;&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;attributesFile&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; /&lt;span class=&quot;property&quot;&gt;path&lt;/span&gt;/&lt;span class=&quot;property&quot;&gt;to&lt;/span&gt;/&lt;span class=&quot;property&quot;&gt;git&lt;/span&gt;/&lt;span class=&quot;property&quot;&gt;attributes&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;diff&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;pandoc&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;textconv&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;pandoc&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;--sandbox&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;--to&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;markdown&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Bonus round: Document previews in Forgejo&lt;/h2&gt;&lt;p&gt;Additionally, you can use &lt;code&gt;pandoc&lt;/code&gt; to preview documents (when not diffing) in Forgejo without downloading them in a very similar fashion.  Mind you it will not be perfect – only properly semantically formatted text will work well, the document will not be split into pages, and you won’t see any images embedded in the document.  But for basic previews to make sure you are looking at the right document, or to quickly check some facts in said document, I think this is pretty neat.&lt;/p&gt;&lt;p&gt;To do this, you can use the &lt;a href=&quot;https://forgejo.org/docs/latest/admin/config-cheat-sheet/#markup-markup&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;[markup.*]&lt;/code&gt; section in the &lt;code&gt;app.ini&lt;/code&gt; file&lt;/a&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;ini&quot;&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;markup&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;docx&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;ENABLED&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant_builtin&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;NEED_POSTPROCESS&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant_builtin&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;FILE_EXTENSIONS&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;docx&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;RENDER_COMMAND&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;pandoc&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;--sandbox&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;--from&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;docx&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;--to&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;html&lt;/span&gt;

&lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;markup&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;odt&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;ENABLED&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant_builtin&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;NEED_POSTPROCESS&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant_builtin&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;FILE_EXTENSIONS&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;odt&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;RENDER_COMMAND&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;pandoc&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;--sandbox&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;--from&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;odt&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;--to&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The main difference here is that Forgejo (as opposed to Git) does not provide the file name to Pandoc.  It instead provides the file contents on the standard input, meaning that Pandoc cannot determine the file type from the name.  To remedy this, we need to specify the &lt;code&gt;--from=&lt;/code&gt; argument to let Pandoc know what the source file format is.  We are also converting directly to HTML instead of Markdown, because we don’t need the extra step – Forgejo would need to convert from Markdown to HTML to display the file to the user anyway.&lt;/p&gt;</description>
        <link>https://spiffyk.cz/blog/git-pandoc/</link>
        <pubDate>Fri, 12 Sep 2025 00:00:00 +0000</pubDate>
        <guid>https://spiffyk.cz/blog/git-pandoc/</guid>
      </item>
    
  </channel>
</rss>
