<rss version="2.0"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>JTT's Blog</title>
<description>Blog of Johannes Thyssen Tishman</description>
<dc:date>2025-12-22T00:00:00Z</dc:date>
<link>https://www.thyssentishman.com</link>
<atom:link rel="self" type="application/rss+xml" href="https://www.thyssentishman.com/rss.xml"/>
<item>
<title>Editor-agnostic plain text table formatter</title>
<link>https://www.thyssentishman.com/blog/005.html</link>
<guid>https://www.thyssentishman.com/blog/005.html</guid>
<dc:date>2025-10-14T00:00:00Z</dc:date>
<dc:creator>Johannes Thyssen Tishman</dc:creator>
<description>
<![CDATA[
<p>A while back I wrote a plugin for the <a href="https://github.com/martanne/vis">vis</a>
editor to format plain text tables interactively à la Emacs Org Mode. No
formulas or any fancy spreadsheet editing functions, just formatting. The
plugin worked well, but I have to admit, the code was terrible. Editing plain
text tables interactively is a hack in itself, but what I wrote was hacky^10.
Anyway, after a while, I stopped using vis and went back to using vim. This
left me with an unpleasant dilemma: should I maintain the spaghetti code that I
no longer used, or let it rot? Even worse, I wanted to use the plugin with vim,
but I wasn&#8217;t going to write yet another plugin<sup id="fnref1"><a href="#fn1" rel="footnote">1</a></sup> that I would eventually abandon.
This gave me the idea to rewrite the plugin as an editor-agnostic tool<sup id="fnref2"><a href="#fn2" rel="footnote">2</a></sup>: ptt.</p>
<h2>TL;DR</h2>
<p><video controls>
<source src="../media/ptt_demo.webm" type="video/webm">
<a href="../media/ptt_demo.webm">DEMO VIDEO</a>
</video></p>
<h2>Usage</h2>
<p>ptt(1) can be used from the command line to quickly format a file with
delimiter-separated values into a plain text table. However, it can also
manipulate its cells, rows and columns by using a unique character called the
<em>cursor</em> (a tilde by default) to keep track of the row and column of the table
that is currently being manipulated. This is what allows scriptable editors to
interact with ptt. Essentially, for an editor to interact with ptt, it needs to
do the following:</p>
<ol>
<li>Insert <em>cursor</em> character at current location in table.</li>
<li>Pipe table into ptt to perform an operation.</li>
<li>Read ptt&#8217;s output.</li>
<li>Search for <em>cursor</em> character, move to it, and delete it.</li>
</ol>
<br/>
<p>Depending on the operation that is performed on the table, ptt will position
the <em>cursor</em> character such that when the editor reads its output, it can know
where to move the actual editor cursor.</p>
<p>For example, assume that the following is the content of a file that is open in
vim and vim&#8217;s cursor is at the &#8216;X&#8217;:</p>
<pre><code>| Item    |XPrice [$] | Qty. |
|---------+-----------+------|
| Lemons  |      3.00 | 2.00 |
| Apples  |      2.00 | 4.00 |
| Chicken |     10.00 | 1.00 |
</code></pre>
<p>The &#8216;Price&#8217; column can be moved to the right by running the following in vim:</p>
<pre><code>:execute "normal i~\&#60;Esc&#62;vap:!ptt column right -\&#60;CR&#62;&#47;\\~\&#60;CR&#62;r "
</code></pre>
<p>This results in the following table, where the second column is now the third
and vim&#8217;s cursor followed the motion.</p>
<pre><code>| Item    | Qty. |XPrice [$] |
|---------+------+-----------|
| Lemons  | 2.00 |      3.00 |
| Apples  | 4.00 |      2.00 |
| Chicken | 1.00 |     10.00 |
</code></pre>
<p>All the macro did is to perform the four steps mentioned above. However,
instead of writing these confusing macros manually, one would ideally write
bindings for their editor of choice to interact with ptt. At the time of
writing I have implemented bindings for the vim and vis editors. These can be
used as examples by anyone wishing to write bindings for another editor.</p>
<p>I&#8217;m aware that calling an external tool for every operation performed on a
table is not very efficient. However, I believe it is a worthy trade-off to
enable different editors to benefit from ptt. Furthermore, ptt is written in
POSIX <a href="https://man.openbsd.org/awk">awk(1)</a>, which makes it very fast,
portable, and free of dependencies.</p>
<div class="footnotes">
<hr/>
<ol>

<li id="fn1">
<p>I knew of
<a href="https://github.com/dhruvasagar/vim-table-mode">vim-table-mode</a>, which is a
powerful plain text table editor plugin for vim. However, I wanted
something simpler that everyone could use, not just vim or vis users.&#160;<a href="#fnref1" rev="footnote">&#8617;</a></p>
</li>

<li id="fn2">
<p>Vis users can still use the old plugin by cloning it from the
&#8216;vis-tables&#8217; branch. However, this plugin will no longer be maintained.&#160;<a href="#fnref2" rev="footnote">&#8617;</a></p>
</li>

</ol>
</div>
]]>
</description>
</item>
<item>
<title>Quick HTTP server for local development on OpenBSD</title>
<link>https://www.thyssentishman.com/blog/004.html</link>
<guid>https://www.thyssentishman.com/blog/004.html</guid>
<dc:date>2025-09-10T00:00:00Z</dc:date>
<dc:creator>Johannes Thyssen Tishman</dc:creator>
<description>
<![CDATA[
<p>Whenever I want to preview my website before pushing it to the hosting server,
I run</p>
<pre><code>$ firefox file:&#47;&#47;&#47;path&#47;to&#47;page&#47;index.html
</code></pre>
<p>This worked fine until I decided to use absolute paths in the navigation bar
links, e.g., <code>&#47;gallery.html</code> instead of <code>..&#47;gallery.html</code>, causing firefox to
look for the file <code>&#47;gallery.html</code><sup id="fnref1"><a href="#fn1" rel="footnote">1</a></sup> instead of <code>&#47;path&#47;to&#47;page&#47;gallery.html</code>.
When looking for an alternative, I found the one-liner</p>
<pre><code>$ python3 -m http.server
</code></pre>
<p>which can be run from the root directory of the website to serve the files on
port 8000 of localhost. This is really cool&#8230;, but it requires python. I could
try with perl, which is shipped with OpenBSD, but I would probably need to
install a module such as
<a href="https://metacpan.org/pod/HTTP%3A%3AServer%3A%3ASimple">HTTP::Server::Simple</a>.
So, I turned to see if I could achieve something similar with
<a href="https://man.openbsd.org/httpd">httpd(8)</a>, OpenBSD&#8217;s HTTP daemon. It turns out,
it is quite simple. It is not a one-liner, but a configuration file like the
following is enough:</p>
<pre><code>$ cat .&#47;httpd.conf
chroot "."

server "local" {
    listen on localhost port 8000
    root "."
    no log
}
</code></pre>
<p>With this, serving a website locally is as simple as running</p>
<pre><code>$ cd &#47;path&#47;to&#47;page
# httpd -df &#47;path&#47;to&#47;httpd.conf
</code></pre>
<p>and navigating to <a href="http://localhost:8000">http:&#47;&#47;localhost:8000</a> in the
browser.</p>
<div class="footnotes">
<hr/>
<ol>

<li id="fn1">
<p>Even if this file did exist, firefox wouldn&#8217;t find it as it uses <a href="https://man.openbsd.org/unveil">unveil(2)</a> on OpenBSD.&#160;<a href="#fnref1" rev="footnote">&#8617;</a></p>
</li>

</ol>
</div>
]]>
</description>
</item>
<item>
<title>Multi-path TikZ sphere</title>
<link>https://www.thyssentishman.com/blog/003.html</link>
<guid>https://www.thyssentishman.com/blog/003.html</guid>
<dc:date>2025-09-09T00:00:00Z</dc:date>
<dc:creator>Johannes Thyssen Tishman</dc:creator>
<description>
<![CDATA[
<p>TikZ has a library called <a href="https://tikz.dev/library-shadings">shadings</a> that
allows you to fill a path with a shading that makes it look like a sphere.</p>
<pre style="display: flex; justify-content: space-between;">
<code>\usetikzlibrary{shadings}
\begin{tikzpicture}
    \shade[ball color=blue] (0,0) circle (1);
\end{tikzpicture}
</code>
<img style="padding: 0 15px;" src="../media/tikz_sphere_1.svg" alt="Circle with blue shading that makes it look like a sphere.">
</pre>
<p>For my master&#8217;s thesis, I wanted to use this to draw the symbol for the center
of gravity, conventionally a quartered black-and-white circle, but for a
three-dimensional drawing. However, I couldn&#8217;t find any examples in the
documentation of the <em>ball</em> shading applied to multiple paths. So, I just
tried.</p>
<pre style="display: flex; justify-content: space-between;">
<code>\usetikzlibrary{shadings}
\begin{tikzpicture}
    \shade[ball color=white] (0,0) -- (-1,0) arc (180:90:1)
        -- (0,-1) arc (270:360:1) --cycle;
    \shade[ball color=black] (0,0) -- (1,0) arc (0:90:1)
        -- (0,-1) arc (270:180:1) --cycle;
\end{tikzpicture}
</code>
<img style="padding: 0 15px;" src="../media/tikz_sphere_2.svg" alt="Quartered black and white circle with shading that makes it look like a sphere.">
</pre>
<p>To my surprise, it worked! But why? Well, it turns out that I just got lucky.
Apparently, the shading is applied relative to the bounding boxes of the
individual paths. Since both paths have rectangular bounding boxes with lower
left corners at <code>(-1,-1)</code> and upper right corners at <code>(1,1)</code>, their shadings
overlap. Had I drawn the same symbol with four paths such that their bounding
boxes did not coincide, this would not have worked.</p>
<pre style="display: flex; justify-content: space-between;">
<code>\usetikzlibrary{shadings}
\begin{tikzpicture}
    \shade[ball color=white] (0,0) -- (-1,0) arc (180:90:1) --cycle;
    \shade[ball color=white] (0,0) -- (1,0) arc (360:270:1) --cycle;
    \shade[ball color=black] (0,0) -- (0,1) arc (90:0:1) --cycle;
    \shade[ball color=black] (0,0) -- (0,-1) arc (270:180:1) --cycle;
\end{tikzpicture}
</code>
<img style="padding: 0 15px;" src="../media/tikz_sphere_3.svg" alt="Quartered black and white circle with different shading for each quarter.">
</pre>
]]>
</description>
</item>
<item>
<title>Integrating mutt with fzf</title>
<link>https://www.thyssentishman.com/blog/002.html</link>
<guid>https://www.thyssentishman.com/blog/002.html</guid>
<dc:date>2024-10-23T00:00:00Z</dc:date>
<dc:creator>Johannes Thyssen Tishman</dc:creator>
<description>
<![CDATA[
<p>For the past couple of days I&#8217;ve been hacking on my <code>muttrc</code> to try and find a
generic way to integrate fzf in my E-Mail workflow with mutt. The idea was to
create a shell script that would prompt the user to select an entry from a list
using fzf, to then execute a mutt function on it<sup id="fnref1"><a href="#fn1" rel="footnote">1</a></sup>.</p>
<pre class="ascii-art">
        function(entry)        
   +----------------------+    
   v                      |    
+------+  function   +--------+
| mutt | ----------> | script |
+------+             +--------+
</pre>
<p>To honor the unix philosophy, I ended up writing two short scripts instead of
one: <code>file_menu</code> for selecting files and <code>mbox_menu</code> for selecting mailboxes.
These can be used with any mutt function that requires a file or a mailbox as
an argument e.g. <code>&#60;attach-file&#62;</code> or <code>&#60;change-folder&#62;</code>.</p>
<h2>TL;DR</h2>
<p><video controls>
<source src="../media/mutt_fzf_demo.webm" type="video/webm">
<a href="../media/mutt_fzf_demo.webm">DEMO VIDEO</a>
</video></p>
<h2>Usage</h2>
<p>The scripts rely on mutt&#8217;s <a href="http://www.mutt.org/doc/manual/#source">source</a>
command, which in addition to evaluating configuration files, it can also
evaluate the output of a script when the filename is suffixed with a pipe
(&#8216;|&#8217;).</p>
<pre><code>source &#47;path&#47;to&#47;script|
</code></pre>
<p>The <code>file_menu</code> script is meant for selecting multiple files<sup id="fnref2"><a href="#fn2" rel="footnote">2</a></sup>. For example,
it can be used with mutt&#8217;s <code>&#60;attach-file&#62;</code> function, to attach files in bulk:</p>
<pre><code>$ file_menu attach-file
push &#60;attach-file&#62;&#47;path&#47;to&#47;file_1.txt&#60;Return&#62;\
    &#60;attach-file&#62;&#47;path&#47;to&#47;file_2.txt&#60;Return&#62;\
    &#60;attach-file&#62;&#47;path&#47;to&#47;file_3.txt&#60;Return&#62;
</code></pre>
<p>The following macro maps the &#8216;a&#8217; key<sup id="fnref3"><a href="#fn3" rel="footnote">3</a></sup> to attach files from mutt&#8217;s compose
screen using the <code>file_menu</code> script.</p>
<pre><code>macro compose a \
&#39;&#60;enter-command&#62;source "&#47;path&#47;to&#47;file_menu attach-file"|&#60;Return&#62;&#39; \
&#39;attach files with fzf&#39;
</code></pre>
<p>The <code>mbox_menu</code> script is meant for selecting a mailbox. For example, it can be
used with mutt&#8217;s <code>&#60;change-folder&#62;</code> function to switch between mailboxes:</p>
<pre><code>$ mbox_menu change-folder
push &#60;change-folder&#62;+INBOX&#60;Return&#62;
</code></pre>
<p>The following macro maps the space bar to switch between mailboxes from mutt&#8217;s
index and pager screens using the <code>mbox_menu</code> script.</p>
<pre><code>macro index,pager &#60;Space&#62; \
&#39;&#60;enter-command&#62;source "&#47;path&#47;to&#47;mbox_menu change-folder"|&#60;Return&#62;&#39; \
&#39;open a mailbox with fzf&#39;
</code></pre>
<h2>Source</h2>
<pre><code>$ cat file_menu
#!&#47;bin&#47;sh

FILES=$(fzf --height=100% --multi)

printf &#39;push &#39;
for i in $FILES
do
    [ -f "$i" ] &#38;&#38; printf &#39;&#60;%s&#62;%s&#60;Return&#62;&#39; "$1" "$i"
    [ -d "$i" ] &#38;&#38; find "$i"&#47;* -type f -maxdepth 0 \
        -exec printf &#39;&#60;%s&#62;%s&#60;Return&#62;&#39; "$1" {} \;
done
</code></pre>
<pre><code>$ cat mbox_menu
#!&#47;bin&#47;sh

list()
{
    # your command to list mailboxes
}

MAILBOX=$(list | fzf --height=100% | sed &#39;s&#47; &#47;%20&#47;g&#39;)

if [ -n "$MAILBOX" ]
then
    printf &#39;push &#60;%s&#62;+%s&#60;Return&#62;&#39; "$1" "$MAILBOX"
fi
</code></pre>
<h2>Ideas</h2>
<p>These scripts are not limited to the examples shown here. After all, the idea
was to make them as generic as possible for them to be flexible and reusable.
Below are some other ideas on how these scripts can be used:</p>
<p><code>mbox_menu</code>:</p>
<ul>
<li>Move&#47;Copy tagged messages to another mailbox</li>
<li>Switch between accounts with folder hooks by listing mailboxes of multiple accounts</li>
</ul>
<br>
<p><code>file_menu</code>:</p>
<ul>
<li>Save an attachment to a specific folder</li>
<li>Change the current working directory</li>
</ul>
<div class="footnotes">
<hr/>
<ol>

<li id="fn1">
<p>This was inspired by a <a href="https://gist.github.com/tscherf/d46b822c60c60c40a2544233802dcac5">gist on GitHub</a>&#160;<a href="#fnref1" rev="footnote">&#8617;</a></p>
</li>

<li id="fn2">
<p>Using fzf&#8217;s &#8211;multi flag&#160;<a href="#fnref2" rev="footnote">&#8617;</a></p>
</li>

<li id="fn3">
<p>Mutt&#8217;s default key to attach a file&#160;<a href="#fnref3" rev="footnote">&#8617;</a></p>
</li>

</ol>
</div>
]]>
</description>
</item>
<item>
<title>Dependency-less notifications in dwm</title>
<link>https://www.thyssentishman.com/blog/001.html</link>
<guid>https://www.thyssentishman.com/blog/001.html</guid>
<dc:date>2024-05-28T00:00:00Z</dc:date>
<dc:creator>Johannes Thyssen Tishman</dc:creator>
<description>
<![CDATA[
<p>For some time now, I&#8217;ve been trying to reduce the number of dotfiles I keep
track of, mainly to make them easier to maintain and deploy. This usually means
having to learn program defaults or just installing less crap.</p>
<p>One of the programs that felt a little extra in my setup was
<a href="https://dunst-project.org/">dunst</a>, which in the words of it&#8217;s author is <em>a
lightweight and customizable notification daemon</em>. I rarely need or get
notifications, yet I kept a full blown configuration to make them pretty. So,
to get rid of dunst without losing notifications completely, I came up with a
setup that makes use of the status bar of suckless&#8217; dynamic window manager
(<a href="https://dwm.suckless.org/">dwm</a>), my window manager of choice, to display
notifications.</p>
<h2>TL;DR</h2>
<p><video controls>
<source src="../media/dwm_notifications_demo.webm" type="video/webm">
<a href="../media/dwm_notifications_demo.webm">DEMO VIDEO</a>
</video></p>
<h2>Configuring the status bar</h2>
<p>For context, the dwm&#8217;s status bar uses the name of the X11 <em>root window</em><sup id="fnref1"><a href="#fn1" rel="footnote">1</a></sup> as
it&#8217;s source of text to display in the status bar. This property can be set to
anything (usually the output of a command e.g.
<a href="https://man.openbsd.org/date">date(1)</a>) and updated indefinite times. For
example, the following shell script displays the date and time in the status
bar and updates it every second:</p>
<pre><code>$ cat statusbar
#!&#47;bin&#47;sh

while true; do
    xsetroot -name "$(date)"
    sleep 1
done
</code></pre>
<p>This script can now be run in the background before starting dwm from an X11
startup script to have it continuously display the date in the status bar for
the entire session.</p>
<h2>Displaying notifications</h2>
<p>To display notifications in the status bar (if any), the above example can be
updated as follows:</p>
<pre><code>$ cat statusbar
#!&#47;bin&#47;sh

while true; do
    if [ -s "&#47;tmp&#47;nqueue" ]; then
        printf "1p\n1d\nw\n" | ed -s &#47;tmp&#47;nqueue
        touch &#47;tmp&#47;nlock
    else
        date
    fi | xargs -I{} xsetroot -name &#39;{}&#39;

    if [ -f "&#47;tmp&#47;nlock" ]; then
        sleep 10
        rm -f &#47;tmp&#47;nlock
    else
        sleep 1
    fi
done
</code></pre>
<p>The script monitors the file <code>&#47;tmp&#47;nqueue</code>, which acts as a queue of
notifications (one message per line). The queue follows the <em>First in, First
out</em> (FIFO) principle. That is, the oldest message (first line) is displayed in
the status bar and removed from the queue, after which the second message
becomes the first and the cycle is repeated until there are no more messages.
When the queue is empty, the status bar reverts to displaying the output of the
date command.</p>
<p>In addition, when a notification is displayed in the status bar, a lock file
(<code>&#47;tmp&#47;nlock</code>) is created to prevent new notifications from overwriting the
current one (see the <code>notify</code> script below). However, the frequency at which
the status bar is updated to show the next available notification or to update
the output of the date command is also regulated by the presence or absence of
this file.</p>
<p>Finally, to add a notification to the queue, a script like the following can be
used:</p>
<pre><code>$ cat notify
#!&#47;bin&#47;sh

echo "$1" &#62;&#62; "&#47;tmp&#47;nqueue"
[ ! -e "&#47;tmp&#47;nlock" ] &#38;&#38; sbreset
</code></pre>
<p>This will append the first argument passed to the script (the notification
message) to the queue, and force the status bar to be updated with the
following <code>sbreset</code> script if a lock file doesn&#8217;t exist:</p>
<pre><code>$ cat sbreset
#!&#47;bin&#47;sh

PID=$(pgrep -f statusbar)
[ -n "$PID" ] &#38;&#38; pkill -P "$PID"
</code></pre>
<p>The script simply finds the PID of the <code>statusbar</code> script and kills its child
processes, causing a new loop iteration to begin. That&#8217;s it! Once dwm has been
restarted with the updated <code>statusbar</code> script, notifications can be queued as
follows:</p>
<pre><code>$ notify "Example notification"
</code></pre>
<h2>Bonus</h2>
<p>The right mouse button can be mapped to execute the <code>sbreset</code> script to force a
status bar update in dwm&#8217;s <code>config.h</code> file:</p>
<pre><code>static const char *sbreset[] = {"sbreset", NULL};
static Button buttons[] = {
    ...
    {ClkStatusText, 0, Button3,  spawn, {.v = sbreset}},
    ...
};
</code></pre>
<p>The update causes any notifications that are being displayed to be cleared
before their time expires, mimicking the behaviour of dunst.</p>
<div class="footnotes">
<hr/>
<ol>

<li id="fn1">
<p>The WM_NAME X11 property of the root window.&#160;<a href="#fnref1" rev="footnote">&#8617;</a></p>
</li>

</ol>
</div>
]]>
</description>
</item>
</channel>
</rss>
