Fourth Note

2026-01-12

This note was created by calling a single function using the keybinding C-c n n! It is surprisingly hard. Despite all the flexibility that is built into Org capture, the one thing that it cannot do is to take a string from the user, and use that string both in the captured file’s name and within the captured file’s content.

So, I had to write a bit of Elisp to get around this pesky limitation, that I have run into in other places as well:

(defun kannan/capture-new-note ()
  (interactive)
  (let* ((note-title (read-string "Note title: "))
         (note-file (expand-file-name (format "%s.org" (string-to-slug-with-date note-title)) local/notebook-location))
         (note-template '"#+title: %s
#+date: %%U
")
         (note-content (format note-template note-title)))
    (with-temp-buffer
      (insert (org-capture-fill-template note-content))
      (write-file note-file))
    (find-file note-file)
    (end-of-buffer)))

This function reads a note title from user input, converts it into a file name by replacing spaces with hyphens and converting everything to lower-case, writes the content of the capture template into a temporary buffer and saves it to said file, and then opens the created file and moves to the end of that new buffer.

The only part that org-capture is not able to do is select a dynamic filename. The solution suggested by ox-hugo is to use a single file and put multiple posts inside that file. I don’t like this solution much, because it ties me down to using Emacs exclusively to work with the list of posts.

For instance, I am thinking of creating a pre-commit hook that will fail when a .org file in content-org/ does not have a corresponding .md file in content/note/. This would have to be implemented within Emacs if I used a single file.

(Converting Org to Markdown in CI or in a pre-commit hook would be much better. But I would have to invoke Emacs from a pre-commit hook which would increase commit time significantly. I don’t much like pre-commit hooks anyway.)