<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:source="https://source.scripting.com/" xml:lang="en">
  <title>Stefan VanBuren · TILs</title>
  <link href="https://stefan.vanburen.xyz/til/" rel="alternate" type="text/html"/>
  <link href="https://stefan.vanburen.xyz/til/index.xml" rel="self" type="application/atom+xml" />
  <id>https://stefan.vanburen.xyz/til/</id>
  
  <updated>2026-06-02T09:11:22-04:00</updated>
  <rights>©️ 2026 Stefan VanBuren</rights>
  <icon>https://stefan.vanburen.xyz/favicon.svg</icon>
  <generator uri="https://gohugo.io/">Hugo</generator>
  <author>
    <name>Stefan VanBuren</name>
    <email>stefan@vanburen.xyz</email>
  </author>
  
  <entry>
    <title type="html"><![CDATA[Sargable]]></title>
    <link href="https://stefan.vanburen.xyz/til/sargable/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/sargable/</id>
    <published>2026-06-02T08:32:10-04:00</published>
    <updated>2026-06-02T09:11:22-04:00</updated>
    <content type="html"><![CDATA[<p>TIL of <a href="https://en.wikipedia.org/wiki/Sargable">&ldquo;sargable&rdquo;</a> conditions in SQL queries,
which just means that an index can be used to speed up the query.
One of those &ldquo;you already know the concept, but the <em>handle</em> is useful&rdquo; sort of things.</p>
]]></content>
    <source:markdown><![CDATA[
TIL of ["sargable"][1] conditions in SQL queries,
which just means that an index can be used to speed up the query.
One of those "you already know the concept, but the _handle_ is useful" sort of things.

[1]: https://en.wikipedia.org/wiki/Sargable
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Tangenting]]></title>
    <link href="https://stefan.vanburen.xyz/til/tangenting/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/tangenting/</id>
    <published>2026-04-26T20:03:30-04:00</published>
    <updated>2026-04-26T20:59:05-04:00</updated>
    <content type="html"><![CDATA[<p><a href="/til/tk">Again</a>,
not something I learned <em>today</em>,
but within the last few weeks:
&ldquo;tangenting&rdquo;.
I read about this in the wonderful Looking At Picture Books Substack,
<a href="https://lookingatpicturebooks.com/p/goodnight-moon">discussing</a> one of my (and Wilhelmina&rsquo;s) favorites, <cite><a href="https://en.wikipedia.org/wiki/Goodnight_Moon">Goodnight Moon</a></cite>:</p>
<blockquote>
<p>Tangenting is something you get yelled at for when you’re in art/design school. The theory is that the edges of things shouldn’t touch closely. You should instead look for large overlaps, so the different objects or elements are clearly divided — if they’re too close it feels badly planned, and harder to tell where one thing ends and the other begins, so they say.
Clement Hurd&hellip; was SUPER into tangenting.</p>
</blockquote>
<p>The whole thing is worth a read, if only for the tangenting discussion.</p>
]]></content>
    <source:markdown><![CDATA[
[Again](/til/tk),
not something I learned _today_,
but within the last few weeks:
"tangenting".
I read about this in the wonderful Looking At Picture Books Substack,
[discussing][1] one of my (and Wilhelmina's) favorites, <cite><a href="https://en.wikipedia.org/wiki/Goodnight_Moon">Goodnight Moon</a></cite>:

> Tangenting is something you get yelled at for when you’re in art/design school. The theory is that the edges of things shouldn’t touch closely. You should instead look for large overlaps, so the different objects or elements are clearly divided — if they’re too close it feels badly planned, and harder to tell where one thing ends and the other begins, so they say.
> Clement Hurd... was SUPER into tangenting.

The whole thing is worth a read, if only for the tangenting discussion.

[1]: https://lookingatpicturebooks.com/p/goodnight-moon
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[TK]]></title>
    <link href="https://stefan.vanburen.xyz/til/tk/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/tk/</id>
    <published>2026-04-25T19:43:17-04:00</published>
    <updated>2026-04-26T21:04:08-04:00</updated>
    <content type="html"><![CDATA[<p>TK means <a href="https://en.wikipedia.org/wiki/To_come_(publishing)">&ldquo;to come&rdquo;</a>.
You&rsquo;ll typically see it as &ldquo;TKTK&rdquo; or &ldquo;TKTKTK&rdquo;,
as a simple way to search (i.e., <kbd><a href="https://en.wikipedia.org/wiki/Command_key">⌘</a></kbd>+<kbd>f</kbd>) for details that haven&rsquo;t been written yet.
I use it when drafting blog posts to skip over a sentence or section I want to come back to write later,
to avoid losing momentum.</p>
<p>I didn&rsquo;t learn this today,
but within the last year or two (not too sure where!);
I was just reminded by seeing it in print<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup><sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> in <a href="https://en.wikipedia.org/wiki/Merrimack_Valley_Library_Consortium">my library</a>&rsquo;s edition of <a href="https://www.jezburrows.com/">Jez Burrow&rsquo;s</a> <a href="http://www.dictionarystories.com">Dictionary Stories</a>,
which is otherwise lovely so far.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>To be fair, I get it:
it&rsquo;s in a footnote where the &ldquo;TK&rdquo; is taking the place of a page number,
which I imagine is one of the last things to be solidified in a print book after all of the typesetting has taken place.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Funny timing, but a post on Daring Fireball the day after this one <a href="https://daringfireball.net/2026/04/nyt_wrong_crossword_grid">mentioned a similar snafu of printing &ldquo;Headline Goes Here&rdquo;</a> &ndash; &ldquo;TK&rdquo; may have been useful there!&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content>
    <source:markdown><![CDATA[
TK means ["to come"](https://en.wikipedia.org/wiki/To_come_(publishing)).
You'll typically see it as "TKTK" or "TKTKTK",
as a simple way to search (i.e., <kbd><a href="https://en.wikipedia.org/wiki/Command_key">⌘</a></kbd>+<kbd>f</kbd>) for details that haven't been written yet.
I use it when drafting blog posts to skip over a sentence or section I want to come back to write later,
to avoid losing momentum.

I didn't learn this today,
but within the last year or two (not too sure where!);
I was just reminded by seeing it in print[^1][^2] in [my library][3]'s edition of [Jez Burrow's][1] [Dictionary Stories][2],
which is otherwise lovely so far.

[^1]: To be fair, I get it:
it's in a footnote where the "TK" is taking the place of a page number,
which I imagine is one of the last things to be solidified in a print book after all of the typesetting has taken place.

[^2]: Funny timing, but a post on Daring Fireball the day after this one [mentioned a similar snafu of printing "Headline Goes Here"][4] -- "TK" may have been useful there!

[1]: https://www.jezburrows.com/
[2]: http://www.dictionarystories.com
[3]: https://en.wikipedia.org/wiki/Merrimack_Valley_Library_Consortium
[4]: https://daringfireball.net/2026/04/nyt_wrong_crossword_grid
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Neovim <code>:Inspect</code>]]></title>
    <link href="https://stefan.vanburen.xyz/til/neovim-inspect/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/neovim-inspect/</id>
    <published>2026-01-10T16:26:47-05:00</published>
    <updated>2026-05-11T20:01:13-04:00</updated>
    <content type="html"><![CDATA[<p>Yesterday, I was working on <a href="https://github.com/bufbuild/buf/pull/4270">improving <code>buf</code>&rsquo;s lsp protobuf semantic tokens</a>,
and needed to test out how my changes were working in a real <abbr title="Language Server Protocol">LSP</abbr> client.</p>
<p>I knew neovim had a couple of helper functions for inspecting the current position;
first I tried:</p>
<pre><code class="language-vim">:lua vim.print(vim.inspect_pos())
</code></pre>
<p>I figured there must be a function more specifically for semantic tokens:</p>
<pre><code class="language-vim">:lua vim.print(vim.lsp.semantic_tokens.get_at_pos())
</code></pre>
<p>But finally I landed on:</p>
<pre><code class="language-vim">:Inspect
</code></pre>
<p>(<a href="https://neovim.io/doc/user/lua.html#%3AInspect%21">neovim docs</a>)</p>
<p>which prints both treesitter and semantic tokens,
but in a much cleaner way than the two lua functions.</p>
<p>I&rsquo;ve <a href="https://github.com/stefanvanburen/dotfiles/commit/7dadb128015d37030f7b3b55b1e849b2873e499b">keymapped the underlying <code>vim.show_pos()</code> function to <code>&lt;leader&gt;i</code> in neovim</a> for easier access.</p>
]]></content>
    <source:markdown><![CDATA[
Yesterday, I was working on [improving `buf`'s lsp protobuf semantic tokens][1],
and needed to test out how my changes were working in a real <abbr title="Language Server Protocol">LSP</abbr> client.

I knew neovim had a couple of helper functions for inspecting the current position;
first I tried:

```vim
:lua vim.print(vim.inspect_pos())
```

I figured there must be a function more specifically for semantic tokens:

```vim
:lua vim.print(vim.lsp.semantic_tokens.get_at_pos())
```

But finally I landed on:

```vim
:Inspect
```

([neovim docs](https://neovim.io/doc/user/lua.html#%3AInspect%21))

which prints both treesitter and semantic tokens,
but in a much cleaner way than the two lua functions.

I've [keymapped the underlying `vim.show_pos()` function to `<leader>i` in neovim][2] for easier access.

[1]: https://github.com/bufbuild/buf/pull/4270
[2]: https://github.com/stefanvanburen/dotfiles/commit/7dadb128015d37030f7b3b55b1e849b2873e499b
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Neovim <code>:InspectTree</code> Tree-sitter]]></title>
    <link href="https://stefan.vanburen.xyz/til/nvim-inspect-tree-sitter/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/nvim-inspect-tree-sitter/</id>
    <published>2025-09-10T19:50:36-04:00</published>
    <updated>2026-05-11T20:01:13-04:00</updated>
    <content type="html"><![CDATA[<p>I had assumed that to interact with Tree-sitter in Neovim,
you still needed to use the utilities from <a href="https://github.com/nvim-treesitter/nvim-treesitter">nvim-treesitter</a>.
Apparently that&rsquo;s not the case &mdash;
Neovim has had a builtin <a href="https://neovim.io/doc/user/treesitter.html#%3AInspectTree"><code>:InspectTree</code></a> command that brings up the <abbr title="Abstract Syntax Tree">AST</abbr> from Tree-sitter in a split window,
which is <a href="https://neovim.io/doc/user/options.html#'scrollbind'"><code>scrollbound</code></a> to the original window and highlights the selected node in both windows.</p>
<p>It also has a <a href="https://gpanders.com/blog/whats-new-in-neovim-0.10/#tree-sitter-query-editor">query editor</a>,
which I haven&rsquo;t yet had the need for,
but it&rsquo;s good to know it exists.</p>
]]></content>
    <source:markdown><![CDATA[
I had assumed that to interact with Tree-sitter in Neovim,
you still needed to use the utilities from [nvim-treesitter][1].
Apparently that's not the case ---
Neovim has had a builtin [`:InspectTree`][2] command that brings up the <abbr title="Abstract Syntax Tree">AST</abbr> from Tree-sitter in a split window,
which is [`scrollbound`][3] to the original window and highlights the selected node in both windows.

It also has a [query editor][4],
which I haven't yet had the need for,
but it's good to know it exists.

[1]: https://github.com/nvim-treesitter/nvim-treesitter
[2]: https://neovim.io/doc/user/treesitter.html#%3AInspectTree
[3]: https://neovim.io/doc/user/options.html#'scrollbind'
[4]: https://gpanders.com/blog/whats-new-in-neovim-0.10/#tree-sitter-query-editor
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[WikiGnome]]></title>
    <link href="https://stefan.vanburen.xyz/til/wiki-gnome/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/wiki-gnome/</id>
    <published>2025-09-02T09:10:30-04:00</published>
    <updated>2026-04-16T19:45:21-04:00</updated>
    <content type="html"><![CDATA[<p>TIL about <a href="https://en.m.wikipedia.org/wiki/Wikipedia:WikiGnome">WikiGnomes</a>:</p>
<blockquote>
<p>A WikiGnome is a wiki user who makes useful incremental edits without clamoring for attention.
WikiGnomes work behind the scenes of a wiki, tying up little loose ends and making things run more smoothly.</p>
</blockquote>
<p>Some of the most valuable work can be the tiny changes that leave things in a better place than they were found.</p>
<p>Also, sounds a little like <a href="/blog/prutsen">prutsen</a>.</p>
]]></content>
    <source:markdown><![CDATA[
TIL about [WikiGnomes][1]:

> A WikiGnome is a wiki user who makes useful incremental edits without clamoring for attention.
> WikiGnomes work behind the scenes of a wiki, tying up little loose ends and making things run more smoothly.

Some of the most valuable work can be the tiny changes that leave things in a better place than they were found.

Also, sounds a little like [prutsen](/blog/prutsen).

[1]: https://en.m.wikipedia.org/wiki/Wikipedia:WikiGnome
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Wrapping arrays in <code>jq</code>]]></title>
    <link href="https://stefan.vanburen.xyz/til/jq-wrap-array/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/jq-wrap-array/</id>
    <published>2025-08-20T08:55:08-04:00</published>
    <updated>2026-05-11T20:01:13-04:00</updated>
    <content type="html"><![CDATA[<p>Riffing on <a href="https://macwright.com/2025/08/19/using-super">Tom MacWright&rsquo;s &ldquo;Using super&rdquo; post</a> from yesterday,
I saw the post and immediately thought of using <a href="https://jqlang.org"><code>jq</code></a>.</p>
<p>I thought I might get what he was looking for with my initial attempt, something like:</p>
<pre><code class="language-console">$ pbpaste | jq '.[].name'
&quot;ALGOLIA_API_KEY&quot;
&quot;AMAZON_AWS_ACCESS_KEY_ID&quot;
</code></pre>
<p>&hellip; but that left out the wrapper array.
I figured I might need some other <code>jq</code> function or pipe,
but instead I found that you can just wrap the entire expression in square brackets to wrap the result:</p>
<pre><code class="language-console">$ pbpaste | jq '[.[].name]'
&quot;ALGOLIA_API_KEY&quot;
&quot;AMAZON_AWS_ACCESS_KEY_ID&quot;
</code></pre>
<p>Regardless, <code>jq</code> feels worth the investment,
especially given <a href="https://github.com/fiatjaf/awesome-jq">the community (and alternative implementations)</a> built up around it.</p>
]]></content>
    <source:markdown><![CDATA[
Riffing on [Tom MacWright's "Using super" post][1] from yesterday,
I saw the post and immediately thought of using [`jq`][2].

I thought I might get what he was looking for with my initial attempt, something like:

```console
$ pbpaste | jq '.[].name'
"ALGOLIA_API_KEY"
"AMAZON_AWS_ACCESS_KEY_ID"
```

... but that left out the wrapper array.
I figured I might need some other `jq` function or pipe,
but instead I found that you can just wrap the entire expression in square brackets to wrap the result:

```console
$ pbpaste | jq '[.[].name]'
"ALGOLIA_API_KEY"
"AMAZON_AWS_ACCESS_KEY_ID"
```

Regardless, `jq` feels worth the investment,
especially given [the community (and alternative implementations)][3] built up around it.

[1]: https://macwright.com/2025/08/19/using-super
[2]: https://jqlang.org
[3]: https://github.com/fiatjaf/awesome-jq
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Neovim LSP Defaults]]></title>
    <link href="https://stefan.vanburen.xyz/til/neovim-lsp-defaults/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/neovim-lsp-defaults/</id>
    <published>2025-07-01T16:33:55-04:00</published>
    <updated>2026-04-23T06:44:40-04:00</updated>
    <content type="html"><![CDATA[<p>neovim released v0.11.0 a little while back,
and in the interest of using the defaults,
I <a href="https://github.com/stefanvanburen/dotfiles/commit/8f8ad882a1092c8c032b13e118efc960317759f4#diff-568ff9545a264b9c3d0daec0395b05bf4217c6448328e6f2e70b1ad55adcbd4eL533-R534">removed some of my <abbr title="Language Server Protocol">LSP</abbr>-related keymaps</a> that are now <a href="https://gpanders.com/blog/whats-new-in-neovim-0-11/#defaults">automatically mapped</a>.
These are listed at <a href="https://neovim.io/doc/user/lsp.html#_defaults"><code>:help lsp-defaults</code></a>.</p>
]]></content>
    <source:markdown><![CDATA[
neovim released v0.11.0 a little while back,
and in the interest of using the defaults,
I [removed some of my <abbr title="Language Server Protocol">LSP</abbr>-related keymaps][1] that are now [automatically mapped][2].
These are listed at [`:help lsp-defaults`][3].

[1]: https://github.com/stefanvanburen/dotfiles/commit/8f8ad882a1092c8c032b13e118efc960317759f4#diff-568ff9545a264b9c3d0daec0395b05bf4217c6448328e6f2e70b1ad55adcbd4eL533-R534
[2]: https://gpanders.com/blog/whats-new-in-neovim-0-11/#defaults
[3]: https://neovim.io/doc/user/lsp.html#_defaults
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Postgres <code>citext</code> type]]></title>
    <link href="https://stefan.vanburen.xyz/til/postgres-citext/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/postgres-citext/</id>
    <published>2024-08-21T07:49:04-04:00</published>
    <updated>2026-05-11T20:01:13-04:00</updated>
    <content type="html"><![CDATA[<p>TIL about the Postgres <code>citext</code> type (that is, <a href="https://www.postgresql.org/docs/current/citext.html">case-insensitive text type</a>),
from reading <a href="https://github.com/surprisetalk/ding/blob/main/db.sql#L18-L19">this schema</a>.</p>
<p>Based on this tip from the Postgres docs,
this might not be the right type for general text:</p>
<blockquote>
<p>Consider using nondeterministic collations (see <a href="https://www.postgresql.org/docs/current/collation.html#COLLATION-NONDETERMINISTIC">Section 24.2.2.4</a>) instead of this module.
They can be used for case-insensitive comparisons,
accent-insensitive comparisons,
and other combinations,
and they handle more Unicode special cases correctly.</p>
</blockquote>
<p>&hellip; but if you&rsquo;re storing something like a username or email address that&rsquo;s already limited to an ascii-ish character set,
and want to keep things unique on a case-insensitive basis,
it might be what you&rsquo;re looking for.</p>
]]></content>
    <source:markdown><![CDATA[
TIL about the Postgres `citext` type (that is, [case-insensitive text type][1]),
from reading [this schema][2].

Based on this tip from the Postgres docs,
this might not be the right type for general text:

> Consider using nondeterministic collations (see [Section 24.2.2.4][3]) instead of this module.
> They can be used for case-insensitive comparisons,
> accent-insensitive comparisons,
> and other combinations,
> and they handle more Unicode special cases correctly.

... but if you're storing something like a username or email address that's already limited to an ascii-ish character set,
and want to keep things unique on a case-insensitive basis,
it might be what you're looking for.

[1]: https://www.postgresql.org/docs/current/citext.html
[2]: https://github.com/surprisetalk/ding/blob/main/db.sql#L18-L19
[3]: https://www.postgresql.org/docs/current/collation.html#COLLATION-NONDETERMINISTIC
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Go Pass by Value or Pointer]]></title>
    <link href="https://stefan.vanburen.xyz/til/go-passing/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/go-passing/</id>
    <published>2024-08-18T19:09:03-04:00</published>
    <updated>2024-08-18T19:14:46-04:00</updated>
    <content type="html"><![CDATA[<p>I&rsquo;ve long struggled with the choice of how to pass around Go values,
specifically structs.
I was happy to find <a href="https://blog.percywegmann.com/2023/09/20/go-pass-by-value-or-pointer.html">this article</a> on the topic,
specifically the conclusion,
reproduced here:</p>
<blockquote>
<ol>
<li>Types that are not structs or arrays should be passed by value.</li>
<li>Struct types that don’t export their members and are clearly built as immutable value types, like time.Time, should be passed by value. Note that these types are relatively rare, and are even rarer to be defined by you.</li>
<li>Arrays and all other struct types should be passed by pointer, whether small, large, stateful, or whatever.</li>
<li>If you’re passing data that could be mutated by a concurrent process and its important to you for that data not to be mutated, explicitly make a copy of it before passing it along. Be aware that you can’t just rely on passing the data by value since that does not create a deep copy.</li>
</ol>
</blockquote>
<p>I&rsquo;ll be referencing this moving forward,
and taking the guesswork out of my passing conventions.</p>
]]></content>
    <source:markdown><![CDATA[
I've long struggled with the choice of how to pass around Go values,
specifically structs.
I was happy to find [this article][1] on the topic,
specifically the conclusion,
reproduced here:

> 1. Types that are not structs or arrays should be passed by value.
> 1. Struct types that don’t export their members and are clearly built as immutable value types, like time.Time, should be passed by value. Note that these types are relatively rare, and are even rarer to be defined by you.
> 1. Arrays and all other struct types should be passed by pointer, whether small, large, stateful, or whatever.
> 1. If you’re passing data that could be mutated by a concurrent process and its important to you for that data not to be mutated, explicitly make a copy of it before passing it along. Be aware that you can’t just rely on passing the data by value since that does not create a deep copy.

I'll be referencing this moving forward,
and taking the guesswork out of my passing conventions.

[1]: https://blog.percywegmann.com/2023/09/20/go-pass-by-value-or-pointer.html
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[HTML datetime duration]]></title>
    <link href="https://stefan.vanburen.xyz/til/html-date-duration/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/html-date-duration/</id>
    <published>2024-07-13T10:18:24-04:00</published>
    <updated>2026-04-23T06:44:40-04:00</updated>
    <content type="html"><![CDATA[<p>Last week I learned that an <abbr title="HyperText Markup Language">HTML</abbr> <code>datetime</code> attribute can <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time#valid_datetime_values">represent a duration</a>.</p>
<p>For example:</p>
<pre><code class="language-html">&lt;time datetime=&quot;PT4H18M3S&quot;&gt;
  4 hours, 18 minutes and 3 seconds
&lt;/time&gt;
</code></pre>
<p>The syntax is an <a href="https://en.wikipedia.org/wiki/ISO_8601#Durations"><abbr title="International Organization for Standardization">ISO</abbr> 8601 Duration</a>.</p>
]]></content>
    <source:markdown><![CDATA[
Last week I learned that an <abbr title="HyperText Markup Language">HTML</abbr> `datetime` attribute can [represent a duration][valid-datetime-values].

For example:

```html
<time datetime="PT4H18M3S">
  4 hours, 18 minutes and 3 seconds
</time>
```

The syntax is an <a href="https://en.wikipedia.org/wiki/ISO_8601#Durations"><abbr title="International Organization for Standardization">ISO</abbr> 8601 Duration</a>.

[valid-datetime-values]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time#valid_datetime_values
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GBrowse to another branch with Fugitive.vim]]></title>
    <link href="https://stefan.vanburen.xyz/til/fugitive-objects/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/fugitive-objects/</id>
    <published>2024-07-11T08:28:24-04:00</published>
    <updated>2026-04-23T06:44:40-04:00</updated>
    <content type="html"><![CDATA[<p>Last week, I watched a coworker bring up a file on a different branch using fugitive.vim&rsquo;s <a href="https://github.com/tpope/vim-fugitive/blob/8c8cdf4405cb8bdb70dd9812a33bb52363a87dbc/doc/fugitive.txt#L254">:GBrowse</a> and I was floored:
almost daily I find myself using it to open the <abbr title="Uniform Resource Locator">URL</abbr> to a file to share (or a few lines).</p>
<p>However, much of the time I&rsquo;m working on a different branch than the one I want to share,
and navigating to the same file on a different branch in the GitHub <abbr title="User Interface">UI</abbr> takes too many steps.
First, you realize you&rsquo;re on the wrong branch,
then you change branches,
then you have to navigate back to the file again.</p>
<p>I had always been vaguely aware of <a href="https://github.com/tpope/vim-fugitive/blob/8c8cdf4405cb8bdb70dd9812a33bb52363a87dbc/doc/fugitive.txt#L611"><code>:h fugitive-object</code></a>,
but had never put them to use.</p>
<p>The object you&rsquo;re looking for is <code>&lt;branch&gt;:%</code>, meaning:
bring up this file (<code>%</code>) on branch <code>&lt;branch&gt;</code>.</p>
<p>For example:</p>
<pre><code class="language-vim">:GBrowse main:%
</code></pre>
<p>And of course, this just works with all of the <a href="https://github.com/tpope/vim-fugitive/blob/8c8cdf4405cb8bdb70dd9812a33bb52363a87dbc/doc/fugitive.txt#L264-L277"><code>:GBrowse</code> variants</a>.</p>
]]></content>
    <source:markdown><![CDATA[
Last week, I watched a coworker bring up a file on a different branch using fugitive.vim's [:GBrowse][GBrowse] and I was floored:
almost daily I find myself using it to open the <abbr title="Uniform Resource Locator">URL</abbr> to a file to share (or a few lines).

However, much of the time I'm working on a different branch than the one I want to share,
and navigating to the same file on a different branch in the GitHub <abbr title="User Interface">UI</abbr> takes too many steps.
First, you realize you're on the wrong branch,
then you change branches,
then you have to navigate back to the file again.

I had always been vaguely aware of [`:h fugitive-object`][fugitive-object],
but had never put them to use.

The object you're looking for is `<branch>:%`, meaning:
bring up this file (`%`) on branch `<branch>`.

For example:

```vim
:GBrowse main:%
```

And of course, this just works with all of the [`:GBrowse` variants][GBrowse-variants].

[GBrowse]: https://github.com/tpope/vim-fugitive/blob/8c8cdf4405cb8bdb70dd9812a33bb52363a87dbc/doc/fugitive.txt#L254
[fugitive-object]: https://github.com/tpope/vim-fugitive/blob/8c8cdf4405cb8bdb70dd9812a33bb52363a87dbc/doc/fugitive.txt#L611
[GBrowse-variants]: https://github.com/tpope/vim-fugitive/blob/8c8cdf4405cb8bdb70dd9812a33bb52363a87dbc/doc/fugitive.txt#L264-L277
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Neovim nfnl Directory Configuration]]></title>
    <link href="https://stefan.vanburen.xyz/til/nvim-nfnl-directory-configuration/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/nvim-nfnl-directory-configuration/</id>
    <published>2024-05-31T08:16:19-04:00</published>
    <updated>2024-06-06T13:49:42-04:00</updated>
    <content type="html"><![CDATA[<p>I&rsquo;ve long wanted to figure out how to get <a href="https://github.com/olical/nfnl?tab=readme-ov-file#directory-local-neovim-configuration-in-fennel"><code>nfnl's</code> directory-local configuration</a> working,
but it took me until yesterday to figure it out &mdash;
mostly by <a href="https://github.com/Olical/nfnl/discussions/41">opening a discussion</a> and then realizing my mistakes. 🤡</p>
<p>First, <code>exrc</code> needs to be <a href="https://github.com/stefanvanburen/dotfiles/commit/beed66f9a0a872f2a0db07b0e2de36ad262e4649">enabled</a>.
This will ultimately load the contents of the generated <code>.nvim.lua</code> file,
as described in <a href="https://neovim.io/doc/user/options.html#'exrc'"><code>:help 'exrc'</code></a></p>
<p>Next, create an <code>.nfnl.fnl</code> file in the directory.
I&rsquo;ve been creating mine as:</p>
<pre><code class="language-fennel">;; .nfnl.fnl
{:source-file-patterns [:.nvim.fnl]}
</code></pre>
<p>&hellip; which means that <code>nfnl</code> only needs to compile the <code>.nvim.fnl</code> file into <code>.nvim.lua</code>.</p>
<p>From there, I create a <code>.nvim.fnl</code> file with my configuration.
Often this is to set up a particular project-local formatter or linter with conform or nvim-lint,
so it may look something like:</p>
<pre><code class="language-fennel">;; .nvim.fnl
(let [conform (require :conform)]
  (set conform.formatters_by_ft.json [:prettier]))
</code></pre>
<p>With this I&rsquo;ve been able to <a href="https://github.com/stefanvanburen/dotfiles/commit/b7ab7019510c4554e5eb432996bb8378d9e9bd44">remove a few $WORK specific formatters</a>.</p>
<p>Lastly, I&rsquo;ve <a href="https://github.com/stefanvanburen/dotfiles/commit/1d740e2a0337678eb6084e4c97cd0a096ea46a71">globally gitignored</a> these files so they aren&rsquo;t accidentally committed.
It&rsquo;s possible to commit the <code>.nvim.lua</code> files to share with other neovim users that have <code>exrc</code> enabled,
but I doubt I&rsquo;ll use that very often &mdash;
I&rsquo;m still undecided on if I&rsquo;ll commit these for my personal projects.</p>
<p>📁</p>
]]></content>
    <source:markdown><![CDATA[
I've long wanted to figure out how to get [`nfnl's` directory-local configuration][1] working,
but it took me until yesterday to figure it out ---
mostly by [opening a discussion][2] and then realizing my mistakes. 🤡

First, `exrc` needs to be [enabled][3].
This will ultimately load the contents of the generated `.nvim.lua` file,
as described in [`:help 'exrc'`][4]

Next, create an `.nfnl.fnl` file in the directory.
I've been creating mine as:

```fennel
;; .nfnl.fnl
{:source-file-patterns [:.nvim.fnl]}
```

... which means that `nfnl` only needs to compile the `.nvim.fnl` file into `.nvim.lua`.

From there, I create a `.nvim.fnl` file with my configuration.
Often this is to set up a particular project-local formatter or linter with conform or nvim-lint,
so it may look something like:

```fennel
;; .nvim.fnl
(let [conform (require :conform)]
  (set conform.formatters_by_ft.json [:prettier]))
```

With this I've been able to [remove a few $WORK specific formatters][6].

Lastly, I've [globally gitignored][5] these files so they aren't accidentally committed.
It's possible to commit the `.nvim.lua` files to share with other neovim users that have `exrc` enabled,
but I doubt I'll use that very often ---
I'm still undecided on if I'll commit these for my personal projects.

📁

[1]: https://github.com/olical/nfnl?tab=readme-ov-file#directory-local-neovim-configuration-in-fennel
[2]: https://github.com/Olical/nfnl/discussions/41
[3]: https://github.com/stefanvanburen/dotfiles/commit/beed66f9a0a872f2a0db07b0e2de36ad262e4649
[4]: https://neovim.io/doc/user/options.html#'exrc'
[5]: https://github.com/stefanvanburen/dotfiles/commit/1d740e2a0337678eb6084e4c97cd0a096ea46a71
[6]: https://github.com/stefanvanburen/dotfiles/commit/b7ab7019510c4554e5eb432996bb8378d9e9bd44
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Git Stash File(s)]]></title>
    <link href="https://stefan.vanburen.xyz/til/git-stash-file/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/git-stash-file/</id>
    <published>2024-05-24T07:39:46-04:00</published>
    <updated>2026-04-23T06:44:40-04:00</updated>
    <content type="html"><![CDATA[<p>This isn&rsquo;t something I&rsquo;m just learning today,
but I&rsquo;ve looked this up enough to warrant writing it down.</p>
<p>I&rsquo;m often working on some code,
and come across something unrelated that I want to change.
So I do &mdash; but it really doesn&rsquo;t belong in this commit or <abbr title="Pull Request">PR</abbr>/patch/etc.!</p>
<p>(I&rsquo;ve yet to put in the reps to understand <a href="https://git-scm.com/docs/git-worktree">worktrees</a> or <a href="https://martinvonz.github.io/jj">jujutsu</a>,
which I&rsquo;m assuming are the &ldquo;real&rdquo; answers here.)</p>
<p>For now, you can provide <code>git stash push</code> a filename (or multiple!) to come back to those changes later:</p>
<pre><code class="language-console">$ git stash push &lt;filename(s)&gt;
</code></pre>
<p>I&rsquo;m sure there&rsquo;s also a way to do this incrementally with <code>-p</code> or <a href="https://github.com/tpope/vim-fugitive">Fugitive&rsquo;s</a> interface.</p>
<p>📦</p>
]]></content>
    <source:markdown><![CDATA[
This isn't something I'm just learning today,
but I've looked this up enough to warrant writing it down.

I'm often working on some code,
and come across something unrelated that I want to change.
So I do --- but it really doesn't belong in this commit or <abbr title="Pull Request">PR</abbr>/patch/etc.!

(I've yet to put in the reps to understand [worktrees][] or [jujutsu][],
which I'm assuming are the "real" answers here.)

For now, you can provide `git stash push` a filename (or multiple!) to come back to those changes later:

```console
$ git stash push <filename(s)>
```

I'm sure there's also a way to do this incrementally with `-p` or [Fugitive's][fugitive] interface.

📦

[worktrees]: https://git-scm.com/docs/git-worktree
[jujutsu]: https://martinvonz.github.io/jj
[fugitive]: https://github.com/tpope/vim-fugitive
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Service Wrappers]]></title>
    <link href="https://stefan.vanburen.xyz/til/service-wrappers/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/service-wrappers/</id>
    <published>2022-11-01T18:54:05-04:00</published>
    <updated>2024-08-16T08:46:52-04:00</updated>
    <content type="html"><![CDATA[<p>TIL of <a href="https://naildrivin5.com/blog/2022/10/31/wrap-third-party-apis-in-service-wrappers-to-simplify-your-code.html">Service Wrappers</a>
a technique I&rsquo;ve used in the past but have never had a name for.
It&rsquo;s essentially an approach to wrapping external APIs.
From the article:</p>
<blockquote>
<ul>
<li>Methods should be named in the language of the service, not the language of the app.</li>
<li>Arguments should use the domain of the service, not the domain of the app.</li>
<li>Arguments should be whatever type is directly needed by the service, so passing in complex stuff like Active Record should be avoided.</li>
<li>The return value should not be a complex object from the third party, but ideally only what data a caller will need (often nothing at all). If it must be a complex object, its name or properties should be in the domain of the service.</li>
</ul>
</blockquote>
<p>The article is written from a Rails perspective,
but is broadly useful &mdash;
always nice to have a name for something useful!</p>
]]></content>
    <source:markdown><![CDATA[
TIL of [Service Wrappers][]
a technique I've used in the past but have never had a name for.
It's essentially an approach to wrapping external APIs.
From the article:

> * Methods should be named in the language of the service, not the language of the app.
> * Arguments should use the domain of the service, not the domain of the app.
> * Arguments should be whatever type is directly needed by the service, so passing in complex stuff like Active Record should be avoided.
> * The return value should not be a complex object from the third party, but ideally only what data a caller will need (often nothing at all). If it must be a complex object, its name or properties should be in the domain of the service.

The article is written from a Rails perspective,
but is broadly useful ---
always nice to have a name for something useful!

[Service Wrappers]: https://naildrivin5.com/blog/2022/10/31/wrap-third-party-apis-in-service-wrappers-to-simplify-your-code.html
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Go&rsquo;s fmt package Explicit Argument Indexes]]></title>
    <link href="https://stefan.vanburen.xyz/til/fmt-explicit-argument-indexes/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/fmt-explicit-argument-indexes/</id>
    <published>2022-06-24T15:59:17-04:00</published>
    <updated>2026-04-23T06:44:40-04:00</updated>
    <content type="html"><![CDATA[<p>Not sure how I hadn&rsquo;t seen this before:
in Go, you can specify the index of the format argument you want to use for each formatting verb.</p>
<p>Simply enough, from the <a href="https://pkg.go.dev/fmt#hdr-Explicit_argument_indexes">package docs</a>:</p>
<pre><code class="language-go">fmt.Sprintf(&quot;%[2]d %[1]d\n&quot;, 11, 22) // =&gt; &quot;22 11&quot;
</code></pre>
<p>In the past, I&rsquo;ve actually done something along the lines of:</p>
<pre><code class="language-go">s := &quot;test&quot;
fmt.Sprintf(&quot;%s %s&quot;, s, s) // =&gt; &quot;test test&quot;
</code></pre>
<p>Instead, you can do:</p>
<pre><code class="language-go">s := &quot;test&quot;
fmt.Sprintf(&quot;%[1]s %[1]s&quot;, s) // =&gt; &quot;test test&quot;
</code></pre>
<p>This came up today at $WORK while providing a table name to a constructed <abbr title="Structured Query Language">SQL</abbr> query -
the table name needed to be supplied multiple times in an upsert, so we could simply do:</p>
<pre><code class="language-go">query := fmt.Sprintf(`
INSERT INTO %[1]s (...) VALUES ($1, $2)
ON CONFLICT (...) DO UPDATE SET ... = %[1]s.(...) WHERE %[1]s.(...) = $2;
`, tableName)
</code></pre>
<p>Instead of needing to supply <code>tableName</code> three times,
it could be supplied once using <code>%[1]s</code>.</p>
]]></content>
    <source:markdown><![CDATA[
Not sure how I hadn't seen this before:
in Go, you can specify the index of the format argument you want to use for each formatting verb.

Simply enough, from the [package docs](https://pkg.go.dev/fmt#hdr-Explicit_argument_indexes):

```go
fmt.Sprintf("%[2]d %[1]d\n", 11, 22) // => "22 11"
```

In the past, I've actually done something along the lines of:

```go
s := "test"
fmt.Sprintf("%s %s", s, s) // => "test test"
```

Instead, you can do:

```go
s := "test"
fmt.Sprintf("%[1]s %[1]s", s) // => "test test"
```

This came up today at $WORK while providing a table name to a constructed <abbr title="Structured Query Language">SQL</abbr> query -
the table name needed to be supplied multiple times in an upsert, so we could simply do:

```go
query := fmt.Sprintf(`
INSERT INTO %[1]s (...) VALUES ($1, $2)
ON CONFLICT (...) DO UPDATE SET ... = %[1]s.(...) WHERE %[1]s.(...) = $2;
`, tableName)
```

Instead of needing to supply `tableName` three times,
it could be supplied once using `%[1]s`.
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[SQLite Connection Configuration]]></title>
    <link href="https://stefan.vanburen.xyz/til/sqlite-connection-configuration/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/sqlite-connection-configuration/</id>
    <published>2022-04-02T10:54:44-04:00</published>
    <updated>2026-04-23T06:44:40-04:00</updated>
    <content type="html"><![CDATA[<p>These notes are basically cribbed from Ben Johnson&rsquo;s excellent &ldquo;Building Production Applications Using Go &amp; SQLite&rdquo; GopherCon talk,
specifically the <a href="https://youtu.be/XcAYkriuQ1o?t=430">&ldquo;Configuring SQLite&rdquo; section</a>.</p>
<p>Generally speaking, you&rsquo;ll want to set three <code>PRAGMA</code>s on each SQLite connection:</p>
<pre><code class="language-sql">PRAGMA journal_mode = WAL;
PRAGMA busy_timeout = 5000;
PRAGMA foreign_keys = ON;
</code></pre>
<p>In turn,</p>
<ul>
<li>
<p><a href="https://sqlite.org/pragma.html#pragma_journal_mode"><code>PRAGMA journal_mode = WAL;</code></a> sets the database into <a href="https://www.sqlite.org/wal.html"><abbr title="Write-Ahead Logging">WAL</abbr> journaling mode</a>.
Unlike the others,
this doesn&rsquo;t necessarily need to be set on each connection;
once a database is in <a href="https://www.sqlite.org/wal.html"><abbr title="Write-Ahead Logging">WAL</abbr></a> mode <a href="https://sqlite.org/wal.html#persistence_of_wal_mode">it&rsquo;ll stay in that mode across database connections</a>.
<a href="https://www.sqlite.org/wal.html"><abbr title="Write-Ahead Logging">WAL</abbr></a> journaling mode is recommended for most SQLite server applications,
because it makes writers not block readers.</p>
</li>
<li>
<p><a href="https://sqlite.org/pragma.html#pragma_busy_timeout"><code>PRAGMA busy_timeout = 5000;</code></a> sets the <a href="https://sqlite.org/c3ref/busy_timeout.html">busy_timeout</a> to 5000 milliseconds (5 seconds).
Without this setting,
if a write transaction is running,
and another write transaction starts,
the second write transaction will fail immediately.</p>
</li>
<li>
<p><a href="https://sqlite.org/pragma.html#pragma_foreign_keys"><code>PRAGMA foreign_keys = ON;</code></a> turns on SQLite&rsquo;s <a href="https://sqlite.org/foreignkeys.html">foreign key support</a>.
Foreign Keys aren&rsquo;t enabled by default in SQLite for historical reasons,
but foreign keys are great for maintaining data integrity.
So &ndash; use them!</p>
</li>
</ul>
<hr>
<ins datetime="2024-06-30">
  Update(2024-06-30): A more complete discussion of these settings and more can be found over at
  <a href="https://kerkour.com/sqlite-for-servers">kerkour.com/sqlite-for-servers</a>
</ins>
]]></content>
    <source:markdown><![CDATA[
These notes are basically cribbed from Ben Johnson's excellent "Building Production Applications Using Go & SQLite" GopherCon talk,
specifically the ["Configuring SQLite" section](https://youtu.be/XcAYkriuQ1o?t=430).

Generally speaking, you'll want to set three `PRAGMA`s on each SQLite connection:

```sql
PRAGMA journal_mode = WAL;
PRAGMA busy_timeout = 5000;
PRAGMA foreign_keys = ON;
```

In turn,

* [`PRAGMA journal_mode = WAL;`][pragma-journal-mode] sets the database into <a href="https://www.sqlite.org/wal.html"><abbr title="Write-Ahead Logging">WAL</abbr> journaling mode</a>.
  Unlike the others,
  this doesn't necessarily need to be set on each connection;
  once a database is in <a href="https://www.sqlite.org/wal.html"><abbr title="Write-Ahead Logging">WAL</abbr></a> mode [it'll stay in that mode across database connections](https://sqlite.org/wal.html#persistence_of_wal_mode).
  <a href="https://www.sqlite.org/wal.html"><abbr title="Write-Ahead Logging">WAL</abbr></a> journaling mode is recommended for most SQLite server applications,
  because it makes writers not block readers.

* [`PRAGMA busy_timeout = 5000;`][pragma-busy-timeout] sets the [busy_timeout](https://sqlite.org/c3ref/busy_timeout.html) to 5000 milliseconds (5 seconds).
  Without this setting,
  if a write transaction is running,
  and another write transaction starts,
  the second write transaction will fail immediately.

* [`PRAGMA foreign_keys = ON;`][pragma-foreign-keys] turns on SQLite's [foreign key support](https://sqlite.org/foreignkeys.html).
  Foreign Keys aren't enabled by default in SQLite for historical reasons,
  but foreign keys are great for maintaining data integrity.
  So -- use them!

[pragma-journal-mode]: https://sqlite.org/pragma.html#pragma_journal_mode
[pragma-foreign-keys]: https://sqlite.org/pragma.html#pragma_foreign_keys
[pragma-busy-timeout]: https://sqlite.org/pragma.html#pragma_busy_timeout

* * *

<ins datetime="2024-06-30">
  Update(2024-06-30): A more complete discussion of these settings and more can be found over at
  <a href="https://kerkour.com/sqlite-for-servers">kerkour.com/sqlite-for-servers</a>
</ins>
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Shell in Markdown]]></title>
    <link href="https://stefan.vanburen.xyz/til/markdown-shell/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/markdown-shell/</id>
    <published>2022-01-28T16:23:20-05:00</published>
    <updated>2026-04-16T19:36:49-04:00</updated>
    <content type="html"><![CDATA[<p>For a long time,
I&rsquo;ve used <code>commandline</code> as the name for the syntax of code fences in markdown whenever I&rsquo;ve wanted to denote a shell command or session.</p>
<p>I&rsquo;ve now realized that I&rsquo;ve been using the wrong name,
and also that there are two separate scenarios to keep in mind:</p>
<hr>
<p>The first scenario is one-off commands, which should use the syntax <a href="https://github.com/github/linguist/blob/73e2d735c3c26577fc89c1cb3f8342e5a8ff1d82/lib/linguist/languages.yml#L5602"><code>sh</code>, or <code>shell</code></a>.
This would be showing something you&rsquo;d enter directly at the command line.</p>
<p>For example:</p>
<pre><code class="language-sh">brew install git
</code></pre>
<p>I leave out the <a href="https://en.wikipedia.org/wiki/Command-line_interface#Command_prompt">command prompt</a>,
because it&rsquo;s implied by the context that the line is to be entered in a command line.
Also, it helps with copy-paste.</p>
<hr>
<p>The other scenario is showing a shell <em>session</em>,
which typically shows the command prompt, an entered command, and <em>the response to the command</em>.
In this instance I&rsquo;d use the <a href="https://github.com/github/linguist/blob/cddf7476af4c95d1572956ffc5c0cb84f7e431c5/lib/linguist/languages.yml#L5921"><code>console</code>, or <code>sh-session</code></a> syntax.</p>
<p>For example:</p>
<pre><code class="language-console">$ git st
?? content/til/markdown-shell.md
</code></pre>
<p>🐚</p>
]]></content>
    <source:markdown><![CDATA[
For a long time,
I've used `commandline` as the name for the syntax of code fences in markdown whenever I've wanted to denote a shell command or session.

I've now realized that I've been using the wrong name,
and also that there are two separate scenarios to keep in mind:

* * *

The first scenario is one-off commands, which should use the syntax [`sh`, or `shell`](https://github.com/github/linguist/blob/73e2d735c3c26577fc89c1cb3f8342e5a8ff1d82/lib/linguist/languages.yml#L5602).
This would be showing something you'd enter directly at the command line.

For example:

```sh
brew install git
```

I leave out the [command prompt](https://en.wikipedia.org/wiki/Command-line_interface#Command_prompt),
because it's implied by the context that the line is to be entered in a command line.
Also, it helps with copy-paste.

* * *

The other scenario is showing a shell _session_,
which typically shows the command prompt, an entered command, and _the response to the command_.
In this instance I'd use the [`console`, or `sh-session`](https://github.com/github/linguist/blob/cddf7476af4c95d1572956ffc5c0cb84f7e431c5/lib/linguist/languages.yml#L5921) syntax.

For example:

```console
$ git st
?? content/til/markdown-shell.md
```

🐚
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[PostgreSQL and jsonb type casts]]></title>
    <link href="https://stefan.vanburen.xyz/til/postgres-jsonb-casting/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/postgres-jsonb-casting/</id>
    <published>2022-01-19T18:30:21-05:00</published>
    <updated>2026-04-23T06:44:40-04:00</updated>
    <content type="html"><![CDATA[<p>Found a bug in one of our systems at work that deals with <a href="https://www.postgresql.org/docs/current/datatype-json.html">jsonb data</a> stored in Postgres today.
The quick summary is that one of our systems was looking for the maximum numerical value of a jsonb integer in a table.</p>
<p>A very simplified example:</p>
<pre><code class="language-postgresql">SELECT
  max(balances)
FROM
  unnest(ARRAY[
    '{&quot;balance&quot;: 7}'::jsonb-&gt;&gt;'balance',
    '{&quot;balance&quot;: 17}'::jsonb-&gt;&gt;'balance'
  ]) as balances
</code></pre>
<p>This returns <code>7</code>, because while the &ldquo;balance&rdquo; field is a numeric <abbr title="JavaScript Object Notation">JSON</abbr> value, the <a href="https://www.postgresql.org/docs/current/functions-json.html#FUNCTIONS-JSON-PROCESSING"><code>-&gt;&gt;</code> operator</a> turns the value into text! &mdash; which makes the comparison a lexicographical one.</p>
<p>Instead, you need to make sure to <a href="https://www.postgresql.org/docs/current/sql-expressions.html#SQL-SYNTAX-TYPE-CASTS">cast the values</a> before comparing:</p>
<pre><code class="language-postgresql">SELECT
  max(balances)
FROM
  unnest(ARRAY[
    ('{&quot;balance&quot;: 7}'::jsonb-&gt;&gt;'balance')::integer,
    ('{&quot;balance&quot;: 17}'::jsonb-&gt;&gt;'balance')::integer
  ]) as balances
</code></pre>
<p>Which returns the expected <code>17</code>.</p>
]]></content>
    <source:markdown><![CDATA[
Found a bug in one of our systems at work that deals with [jsonb data](https://www.postgresql.org/docs/current/datatype-json.html) stored in Postgres today.
The quick summary is that one of our systems was looking for the maximum numerical value of a jsonb integer in a table.

A very simplified example:

```postgresql
SELECT
  max(balances)
FROM
  unnest(ARRAY[
    '{"balance": 7}'::jsonb->>'balance',
    '{"balance": 17}'::jsonb->>'balance'
  ]) as balances
```

This returns `7`, because while the "balance" field is a numeric <abbr title="JavaScript Object Notation">JSON</abbr> value, the [`->>` operator](https://www.postgresql.org/docs/current/functions-json.html#FUNCTIONS-JSON-PROCESSING) turns the value into text! --- which makes the comparison a lexicographical one.

Instead, you need to make sure to [cast the values](https://www.postgresql.org/docs/current/sql-expressions.html#SQL-SYNTAX-TYPE-CASTS) before comparing:

```postgresql
SELECT
  max(balances)
FROM
  unnest(ARRAY[
    ('{"balance": 7}'::jsonb->>'balance')::integer,
    ('{"balance": 17}'::jsonb->>'balance')::integer
  ]) as balances
```

Which returns the expected `17`.
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[PostgreSQL IN versus ANY]]></title>
    <link href="https://stefan.vanburen.xyz/til/psql-in-versus-any/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/psql-in-versus-any/</id>
    <published>2022-01-11T08:40:46-05:00</published>
    <updated>2025-11-16T19:49:53-05:00</updated>
    <content type="html"><![CDATA[<p>I still feel rather new to PostgreSQL,
and a few times now in Go I&rsquo;ve tried to do something along the lines of:</p>
<pre><code class="language-go">type pgdb struct {
	db *sql.DB
}

func (db *pgdb) getEntityByID(ctx context.Context, ids []string) ([]Entity, error) {
	query := &quot;SELECT * FROM entities WHERE entities.id IN ($1)&quot;

	rows, err := db.db.QueryContext(ctx, query, pq.StringArray(ids))
	/// ...
}
</code></pre>
<p>But the query would always fail or retrieve no rows.
I&rsquo;ve always fixed it by switching the <code>IN $1</code> for a <code>= ANY($1)</code>,
but never quite understood why.</p>
<p>Researching this a bit more today,
I realized that the <a href="https://www.postgresql.org/docs/current/functions-comparisons.html#FUNCTIONS-COMPARISONS-IN-SCALAR"><code>IN</code></a> function takes a list of literals,
whereas <a href="https://www.postgresql.org/docs/current/functions-comparisons.html#id-1.5.8.30.16"><code>ANY</code></a> is an array function that takes a single array literal.
Thus, when I&rsquo;m passing a <code>pq.StringArray</code>, it only works with the array function.</p>
<hr>
<p>I found this out going through <a href="https://github.com/lib/pq">lib/pq</a>&rsquo;s issues,
finding <a href="https://github.com/lib/pq/issues/600">this issue</a> with <a href="https://github.com/lib/pq/issues/600#issuecomment-294143990">this comment</a> explaining the difference quite well,
which also pointed to a <a href="https://github.com/lib/pq/issues/515">simpler case</a> where <a href="https://github.com/lib/pq/issues/515#issuecomment-252393112">this comment</a> cleared things up for me.</p>
]]></content>
    <source:markdown><![CDATA[
I still feel rather new to PostgreSQL,
and a few times now in Go I've tried to do something along the lines of:

```go
type pgdb struct {
	db *sql.DB
}

func (db *pgdb) getEntityByID(ctx context.Context, ids []string) ([]Entity, error) {
	query := "SELECT * FROM entities WHERE entities.id IN ($1)"

	rows, err := db.db.QueryContext(ctx, query, pq.StringArray(ids))
	/// ...
}
```

But the query would always fail or retrieve no rows.
I've always fixed it by switching the `IN $1` for a `= ANY($1)`,
but never quite understood why.

Researching this a bit more today,
I realized that the [`IN`] function takes a list of literals,
whereas [`ANY`] is an array function that takes a single array literal.
Thus, when I'm passing a `pq.StringArray`, it only works with the array function.

* * *

I found this out going through [lib/pq](https://github.com/lib/pq)'s issues,
finding [this issue](https://github.com/lib/pq/issues/600) with [this comment](https://github.com/lib/pq/issues/600#issuecomment-294143990) explaining the difference quite well,
which also pointed to a [simpler case](https://github.com/lib/pq/issues/515) where [this comment](https://github.com/lib/pq/issues/515#issuecomment-252393112) cleared things up for me.

[`IN`]: https://www.postgresql.org/docs/current/functions-comparisons.html#FUNCTIONS-COMPARISONS-IN-SCALAR
[`ANY`]: https://www.postgresql.org/docs/current/functions-comparisons.html#id-1.5.8.30.16
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Go&rsquo;s package fmt %q verb for strings]]></title>
    <link href="https://stefan.vanburen.xyz/til/gofmt-q/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/gofmt-q/</id>
    <published>2021-09-23T10:00:45-04:00</published>
    <updated>2026-04-16T19:36:49-04:00</updated>
    <content type="html"><![CDATA[<p>I wasn&rsquo;t aware of the Go <code>fmt</code> package <code>%q</code> verb, for quoting strings.
Typically, I&rsquo;ve been escaping the quotes manually and using the <code>%s</code> verb:</p>
<pre><code class="language-go">fmt.Sprintf(&quot;this needs quoting: \&quot;%s\&quot;&quot;, &quot;input&quot;)
</code></pre>
<p>But the <code>%q</code> verb obviates the need for that manual quoting.</p>
<p>From the <a href="https://pkg.go.dev/fmt">package documentation</a>:</p>
<blockquote>
<p>%s    the uninterpreted bytes of the string or slice</p>
<p>%q    a double-quoted string safely escaped with Go syntax</p>
</blockquote>
<p>And a quick example (on the <a href="https://play.golang.org/p/w-DfnVMSi_k">Go Playground</a>):</p>
<pre><code class="language-go">package main

import (
	&quot;fmt&quot;
)

func main() {
	test := &quot;I'm a test string&quot;

	fmt.Printf(&quot;\&quot;%s\&quot;&quot;, test)
	// Output: &quot;I'm a test string&quot;
	fmt.Println()
	fmt.Printf(&quot;%q&quot;, test)
	// Output: &quot;I'm a test string&quot;
}
</code></pre>
]]></content>
    <source:markdown><![CDATA[
I wasn't aware of the Go `fmt` package `%q` verb, for quoting strings.
Typically, I've been escaping the quotes manually and using the `%s` verb:

```go
fmt.Sprintf("this needs quoting: \"%s\"", "input")
```

But the `%q` verb obviates the need for that manual quoting.

From the [package documentation](https://pkg.go.dev/fmt):

> %s    the uninterpreted bytes of the string or slice
>
> %q    a double-quoted string safely escaped with Go syntax

And a quick example (on the [Go Playground](https://play.golang.org/p/w-DfnVMSi_k)):

```go
package main

import (
	"fmt"
)

func main() {
	test := "I'm a test string"

	fmt.Printf("\"%s\"", test)
	// Output: "I'm a test string"
	fmt.Println()
	fmt.Printf("%q", test)
	// Output: "I'm a test string"
}
```
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Go Templates Whitespace]]></title>
    <link href="https://stefan.vanburen.xyz/til/go-templates-whitespace/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/go-templates-whitespace/</id>
    <published>2021-08-31T18:41:20-04:00</published>
    <updated>2026-04-23T06:44:40-04:00</updated>
    <content type="html"><![CDATA[<p>When writing <abbr title="HyperText Markup Language">HTML</abbr> templates in Go, knowing about the <a href="https://pkg.go.dev/text/template#hdr-Text_and_spaces">whitespace modifiers</a> is crucial for keeping both the templates and the output <abbr title="HyperText Markup Language">HTML</abbr> looking good.</p>
<p>For example, if you had the following template, with <code>.SomeText</code> being <code>&quot;foo&quot;</code> and <code>.Something</code> being <code>true</code>:</p>
<pre><code class="language-go-html-template">&lt;a href=&quot;/posts&quot;&gt;
  &lt;span&gt;
  {{ if .Something }}
  Text
  {{ else }}
  Image
  {{ end }}
  &lt;/span&gt;
  {{ .SomeText }}
&lt;/a&gt;
</code></pre>
<p>The actual output <abbr title="HyperText Markup Language">HTML</abbr> would look something like:</p>
<pre><code class="language-html">&lt;a href=&quot;/posts&quot;&gt;&lt;span&gt; Text &lt;/span&gt; foo &lt;/a&gt;
</code></pre>
<p>Which isn&rsquo;t what you want, because there&rsquo;s extra spaces &mdash; both around &ldquo;Text&rdquo; and around &ldquo;foo&rdquo;.</p>
<p>Instead, you could do:</p>
<pre><code class="language-go-html-template">&lt;a href=&quot;/posts&quot;&gt;
  &lt;span&gt;
  {{ if .Something }}
  {{- Text -}}
  {{ else }}
  {{- Image -}}
  {{ end }}
  &lt;/span&gt;
  {{- .SomeText -}}
&lt;/a&gt;
</code></pre>
<p>to get</p>
<pre><code class="language-html">&lt;a href=&quot;/posts&quot;&gt;&lt;span&gt;Text&lt;/span&gt;foo&lt;/a&gt;
</code></pre>
<p>Which makes both the source code and <abbr title="HyperText Markup Language">HTML</abbr> nice and neat.</p>
]]></content>
    <source:markdown><![CDATA[
When writing <abbr title="HyperText Markup Language">HTML</abbr> templates in Go, knowing about the [whitespace modifiers](https://pkg.go.dev/text/template#hdr-Text_and_spaces) is crucial for keeping both the templates and the output <abbr title="HyperText Markup Language">HTML</abbr> looking good.

For example, if you had the following template, with `.SomeText` being `"foo"` and `.Something` being `true`:

```go-html-template
<a href="/posts">
  <span>
  {{ if .Something }}
  Text
  {{ else }}
  Image
  {{ end }}
  </span>
  {{ .SomeText }}
</a>
```

The actual output <abbr title="HyperText Markup Language">HTML</abbr> would look something like:

```html
<a href="/posts"><span> Text </span> foo </a>
```

Which isn't what you want, because there's extra spaces --- both around "Text" and around "foo".

Instead, you could do:

```go-html-template
<a href="/posts">
  <span>
  {{ if .Something }}
  {{- Text -}}
  {{ else }}
  {{- Image -}}
  {{ end }}
  </span>
  {{- .SomeText -}}
</a>
```

to get

```html
<a href="/posts"><span>Text</span>foo</a>
```

Which makes both the source code and <abbr title="HyperText Markup Language">HTML</abbr> nice and neat.
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[<code>time.Ticker</code> in Go]]></title>
    <link href="https://stefan.vanburen.xyz/til/ticker/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/ticker/</id>
    <published>2021-05-21T20:25:49-04:00</published>
    <updated>2026-05-11T20:01:13-04:00</updated>
    <content type="html"><![CDATA[<p>The <a href="https://pkg.go.dev/time#Ticker"><code>time.Ticker</code></a> type in Go is incredibly useful for situations in which <a href="https://en.wikipedia.org/wiki/Polling_(computer_science)">polling</a> is needed.</p>
<p>The easiest way to use the Ticker is via the <a href="https://pkg.go.dev/time#example-Tick"><code>time.Tick</code></a> function,
which just provides access to the ticking channel,
which makes it easy to <code>range</code> over:</p>
<pre><code class="language-go">package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

func main() {
	for currentTime := range time.Tick(time.Second) {
		fmt.Println(&quot;current time: &quot;, currentTime)
	}
}
</code></pre>
<p>For more control, <a href="https://pkg.go.dev/time#NewTicker"><code>time.NewTicker</code></a> works wonders &mdash;
there&rsquo;s no better example than the one <a href="https://go.dev/play/p/nG23A6LEd19">from the docs</a>!</p>
]]></content>
    <source:markdown><![CDATA[
The [`time.Ticker`](https://pkg.go.dev/time#Ticker) type in Go is incredibly useful for situations in which [polling](https://en.wikipedia.org/wiki/Polling_(computer_science)) is needed.

The easiest way to use the Ticker is via the [`time.Tick`](https://pkg.go.dev/time#example-Tick) function,
which just provides access to the ticking channel,
which makes it easy to `range` over:

```go
package main

import (
	"fmt"
	"time"
)

func main() {
	for currentTime := range time.Tick(time.Second) {
		fmt.Println("current time: ", currentTime)
	}
}
```

For more control, [`time.NewTicker`](https://pkg.go.dev/time#NewTicker) works wonders ---
there's no better example than the one [from the docs](https://go.dev/play/p/nG23A6LEd19)!
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[<code>run</code> vs <code>errgroup</code>]]></title>
    <link href="https://stefan.vanburen.xyz/til/errgroup-vs-run/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/errgroup-vs-run/</id>
    <published>2021-05-11T10:38:26-04:00</published>
    <updated>2026-05-11T20:01:13-04:00</updated>
    <content type="html"><![CDATA[<p>I typically don&rsquo;t do much with concurrency in Go, but messed around this morning with both <a href="https://github.com/oklog/run">oklog/run</a> and <a href="https://golang.org/x/sync/errgroup">sync/errgroup</a>.</p>
<p>I&rsquo;ve defaulted to using oklog/run in the past, but I realized that while they have similar interfaces, they&rsquo;re useful for different things:</p>
<ul>
<li>oklog/run is useful for long-running processes.
<ul>
<li>think starting up http servers alongside other components, and waiting for one to finish, in which case all other components are signalled to finish.</li>
</ul>
</li>
<li>sync/errgroup is useful for short-lived, parallel processes.
<ul>
<li>think units of work to be done in parallel, where one process resulting in an error should stop the entire computation.</li>
</ul>
</li>
</ul>
]]></content>
    <source:markdown><![CDATA[
I typically don't do much with concurrency in Go, but messed around this morning with both [oklog/run](https://github.com/oklog/run) and [sync/errgroup](https://golang.org/x/sync/errgroup).

I've defaulted to using oklog/run in the past, but I realized that while they have similar interfaces, they're useful for different things:

* oklog/run is useful for long-running processes.
  * think starting up http servers alongside other components, and waiting for one to finish, in which case all other components are signalled to finish.
* sync/errgroup is useful for short-lived, parallel processes.
  * think units of work to be done in parallel, where one process resulting in an error should stop the entire computation.
]]></source:markdown>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Use <code>jq</code> to see if a JSON key exists]]></title>
    <link href="https://stefan.vanburen.xyz/til/jq-key-exists/" rel="alternate" type="text/html"/>
    <id>https://stefan.vanburen.xyz/til/jq-key-exists/</id>
    <published>2021-04-22T11:11:03-04:00</published>
    <updated>2026-05-11T20:01:13-04:00</updated>
    <content type="html"><![CDATA[<p>I&rsquo;m constantly using <a href="https://stedolan.github.io/jq/"><code>jq</code></a> to deal with <abbr title="JavaScript Object Notation">JSON</abbr> via the <abbr title="Command-Line Interface">CLI</abbr>.</p>
<p>Today I needed to figure out the difference between a key existing with a <code>null</code> value or not existing at all in a bit of <abbr title="JavaScript Object Notation">JSON</abbr>.</p>
<p>By default, &ldquo;querying&rdquo; a key via <code>jq</code> will return <code>null</code> whether the key exists and is <code>null</code>, <strong>or</strong> the key doesn&rsquo;t exist:</p>
<pre><code class="language-fish">△ # NOTE: the following is in fish, but should be straightforward to port to other shells

△ set json '{&quot;test&quot;: null}'

△ echo $json | jq .test
null

△ echo $json | jq .nonexistent
null
</code></pre>
<p>Instead, you can use the <code>jq</code>&rsquo;s <a href="https://stedolan.github.io/jq/manual/#has(key)"><code>has</code></a> function to determine the difference:</p>
<pre><code class="language-fish">△ echo $json | jq 'has(&quot;test&quot;)'
true

△ echo $json | jq 'has(&quot;nonexistent&quot;)'
false
</code></pre>
]]></content>
    <source:markdown><![CDATA[
I'm constantly using [`jq`](https://stedolan.github.io/jq/) to deal with <abbr title="JavaScript Object Notation">JSON</abbr> via the <abbr title="Command-Line Interface">CLI</abbr>.

Today I needed to figure out the difference between a key existing with a `null` value or not existing at all in a bit of <abbr title="JavaScript Object Notation">JSON</abbr>.

By default, "querying" a key via `jq` will return `null` whether the key exists and is `null`, **or** the key doesn't exist:

```fish
△ # NOTE: the following is in fish, but should be straightforward to port to other shells

△ set json '{"test": null}'

△ echo $json | jq .test
null

△ echo $json | jq .nonexistent
null
```

Instead, you can use the `jq`'s [`has`](https://stedolan.github.io/jq/manual/#has(key)) function to determine the difference:

```fish
△ echo $json | jq 'has("test")'
true

△ echo $json | jq 'has("nonexistent")'
false
```
]]></source:markdown>
  </entry>
  
</feed>
