Tables of files with Org mode

Literate programming is a superb way of encoding knowledge in a collaboration with a machine, and Org mode is one of the best environments for interacting with text and images out there.

As part of my work to maintain my TIL streak, I’m creating MDX files with dates that determine when a page should go live. This allows me to queue up TILs so I can get away for a few days when a friend is getting married.

While I’ve yet to fully automate the drafting process, I did want a quick way to see what’s queued up and which days are taken care of. Something, Org-mode is brilliantly equipped to help me with this.

We start with a little ripgrep to find files with a date: (.*) pattern in the relevant content directory.

The output from ripgrep needs some massaging as we want the date first and don’t want the leading date: string included in our output, so we make use of --replace like so:

rg '^date: (.*)' --replace '$1' .

The directory is specified using the :dir header argument to the source block so there’s no need to cd around in our snippet.

With ripgrep returning the right search results, we move on to formatting the output. As we’re going to produce a table, we provide the column names, too, using :colnames and a quoted list.

#+begin_src sh :dir src/content/tils :colnames '("Date" "File")
rg '^date: (.*)' --replace '$1' . | awk -F: '{ print $2 "\t" $1 }' | sort
#+end_src

With awk , we can split our results on colons, reverse the fields, and inject a tab, which Org mode helpfully recognises as a column delimiter.

Putting it all together, we execute the source block, and Org-mode drops the following output below our source block.

#+results:
|       Date | File                                              |
|------------+---------------------------------------------------|
| 2024-01-02 | ./installing-aspell-dicts-with-nix.mdx            |
| 2024-01-03 | ./removing-backticks-from-tailwind-typography.mdx |
| 2024-01-04 | ./scheduling-a-vercel-deployment.mdx              |
| 2024-01-05 | ./blocking-a-domain-with-adguard.mdx              |
| 2024-01-06 | ./stable-scrollbars.mdx                           |
| 2024-01-07 | ./finding-project-files-in-emacs.mdx              |
| 2024-01-08 | ./flake-parts-and-unfree-packages.mdx             |
| 2024-01-09 | ./system-appearance-in-emacs-on-macos.mdx         |
| 2024-01-10 | ./creating-clis-with-sub.mdx                      |
| 2024-01-11 | ./silencing-the-message-of-the-day.mdx            |
| 2024-01-12 | ./when-pkg-wont-update.mdx                        |
| 2024-01-13 | ./rip-statistical-mechanics.mdx                   |
| 2024-01-14 | ./lite-system-configuration.mdx                   |

Note, that while I was working this out, I was using Org mode to execute my source block so I could interrogate the machine and learn by doing. This is what I think of when I hear test-driven development these days. To me, it’s about tightening feedback loops rather than dogmatic adherence to prescriptive processes.