💾 Archived View for hoseki.iensu.me › posts › setting-stuff-up.gmi captured on 2023-12-28 at 15:21:15. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2022-03-01)

-=-=-=-=-=-=-

Setting stuff up

Today I wrote a build script for converting my Org mode files into gmi files and publish them. In doing so I also wanted to generate post listings both by category and by publish date. This allowed me to venture into topics such as Org file parsing and the Emacs Lisp cl-loop macro.

Working with Org files

I write my posts as separate .org files and each file has at least three properties defined at the top: `TITLE`, `DATE` and `FILETAGS`. Using the `org-collect-keywords` function it was trivial to retrieve their values:

(with-temp-buffer
  (insert-file-contents org-file-path)
  (org-collect-keywords '("TITLE" "DATE" "FILETAGS")))

Org mode also comes with a few handy date comparator which I could use with the `sort` function, like `org-time>`, `org-time<` and so on.

Equality in Emacs Lisp

Sorting by topic (or Org mode tag in this case) was a bit more involved as each file can potentially have multiple tags and each tag was to become a sub heading in the resulting file. I decided to use a hash table to group all the posts by tags and at the beginning it didn't work at all. It took me about 20-30 minutes to realize that the equality check wasn't working when trying to retrieve a value by key. In Emacs Lisp hash tables use `eq` as the default equality test function and `eq` only checks for object equality. That means that it works fine if you use symbols like `:tag` or `'tag` as keys, but not if you're using strings as I was. Luckily `make-hash-table` allows you to pass a `:test` option where you specify which equality function you want to use:

This distinction caught me a little off guard, but I guess the mnemonic is the longer the function name, the more complex the equality check. So in the end I went with `equal`.

(make-hash-table :test 'equal)

Nested for loops in the cl-loop macro

The last thing that surprised me was how nested `for` expressions work in the `cl-loop` macro. I assumed an expression like the following would result in nested `for` loops:

(cl-loop for x from 10 to 15
	 for y from 0 to 5
	 collect (list x y))

But the result turns out to be: `((10 0) (11 1) (12 2) (13 3) (14 4) (15 5))` so the two `for` expressions run in parallel. In order to achieve nested loops it appears you have to be more explicit:

(cl-loop for x from 10 to 15
	 append (cl-loop for y from 0 to 5
			 collect (list x y)))

The above results in `((10 0) (10 1) (10 2) (10 3) (10 4) (10 5) (11 0) (11 1) (11 2) (11 3) (11 4) (11 5) ...)` as expected.

イェンス - 2021-12-12

hoseki.iensu.me