Book logging in Emacs

I’ve kept a list of books I’ve read as a plain text (well, technically, Markdown) file for years. I wrote about it here . The public version is rendered using Github Pages at books.baty.net . This is fine, but at some point last year I also started logging books in an Org mode file, just to see how it felt. It felt pretty good!

My books.org file is just an outline with some custom properties. An entry looks like this:

** DONE Leonardo da Vinci
CLOSED: [2022-04-11 Mon 11:10]
:PROPERTIES:
:author:  Walter Isaacson
:year:    2017
:name:    Leonardo da Vinci
:url:     https://www.goodreads.com/book/show/34684622-leonardo-da-vinci
:pages:   600
:rating:  *****
:END:

The outline looks like this:

That’s fine, but doesn’t show much information other than a short title. That’s where Org’s Column View comes in. Column view shows a summary of a set of headings in a customizable view. The setup for mine is this:

#+columns: %50ITEM(Title) %author(Author) %pages(Pages){+} %8rating

This sets columns, widths, titles, and even a total of the number of pages (via the {+} flag). Then, I have a block which generates and saves the column view for me. Here’s that block.

#+BEGIN: columnview :hlines 1 :id global :skip-empty-rows t :indent t :match "-noexport"
#+END
My books.org file

I like it. It’s like a little plain-text database.

I probably won’t bother backfilling it with earlier entries, but I plan to keep it updated from now on. I haven’t yet created any fancy org-mode “Capture templates” because let’s be honest, I don’t finish enough books to benefit from that kind of automation. I simply copy and paste an earlier entry and modify that. Maybe I’ll do something smarter at some point, just for fun.

Org mode is pretty great and can do just about anything.

Publishing portions of my Org-roam database

I’m trying something new.

I’ve become a pretty heavy user of Org-roam  for personal notes. I put nearly everything there now; technical notes, contact information, project notes, vendor info, etc. These notes are all nicely linked and backlinked and live in my main ~/org directory so I can easily find things right within Emacs.

A portion of these notes might be useful to other people. So I’m exporting the shareable notes from Org-roam as Hugo -compatible Markdown files. This turned out to be surprisingly easy. You can see the results at https://notes.baty.net and the details of how it works makes a good example.

I’m sure there are a dozen ways to do this, but this seems to work quite well.

Aligning comments in Emacs

I want my per-line code comments to line up nicely, so I’ll often add a bunch of spaces by hand to make things just so. I realized that, being Emacs, there must be an easier way to handle this. Of course there is.

Two minutes of searching revealed a short bit of lisp that does the job nicely:

;; Align comments in marked region
;; Via https://stackoverflow.com/a/20278032
(defun jab/align-comments (beginning end)
  "Align comments within marked region."
  (interactive "*r")
  (let (indent-tabs-mode align-to-tab-stop)
    (align-regexp beginning end (concat "\(\s-*\)"
                                        (regexp-quote comment-start)))))

Here’s an example of what I was working on, with horribly un-aligned comments.

(setq org-roam-capture-templates
  '(("d" "default" plain "%?"
    :target (file+head "%<%Y%m%d>-${slug}.org"
                       "#+title: ${title}n#+index: n#+setupfile: ~/org/_SETUP/EXPORTn#+setupfile: ~/org/_SETUP/org-roam-publish-fancy.setup")
    :unnarrowed t)
    ("P" ;; Key
     "Public (published in /public)" ;; Description
     plain  ;; Type
     (file "~/org/roam/templates/PublicTemplate.org")  ;; Template
    :target (file "public/${slug}.org") ;; Target
    :unnarrowed t)
    ("p" ;; Key
     "project"  ;; Description
     plain   ;; Type
     (file "~/org/roam/templates/ProjectTemplate.org") ;; Template
    :target (file "projects/%<%Y%m%d>-${slug}.org")    ;; Target
    :unnarrowed t)))

Then, here’s that same thing after executing jab/align-comments

(setq org-roam-capture-templates
  '(("d" "default" plain "%?"
    :target (file+head "%<%Y%m%d>-${slug}.org"
                       "#+title: ${title}n#+index: n#+setupfile: ~/org/_SETUP/EXPORTn#+setupfile: ~/org/_SETUP/org-roam-publish-fancy.setup")
    :unnarrowed t)
    ("P"                                               ;; Key
     "Public (published in /public)"                   ;; Description
     plain                                             ;; Type
     (file "~/org/roam/templates/PublicTemplate.org")  ;; Template
    :target (file "public/${slug}.org")                ;; Target
    :unnarrowed t)
    ("p"                                               ;; Key
     "project"                                         ;; Description
     plain                                             ;; Type
     (file "~/org/roam/templates/ProjectTemplate.org") ;; Template
    :target (file "projects/%<%Y%m%d>-${slug}.org")    ;; Target
    :unnarrowed t)))

Much better. It’s cool because it uses comment-start so it works with any language’s comment syntax. There are probably 17 other ways of doing this that I haven’t discovered, but this works.

Every day is a new day in Emacs.

Configuring the org-download save directory

When I drag and drop an image into Emacs, I want the attached file to end up in ./img/YYYY/. This is how I tried configuring org-download in my setup (I use Doom Emacs):

(setq org-download-method 'directory
        org-download-image-dir (concat "img/"  (format-time-string "%Y") "/")
        org-download-image-org-width 600
        org-download-heading-lvl 1)
(setq org-download-method 'directory
        org-download-image-dir (concat "img/"  (format-time-string "%Y") "/")
        org-download-image-org-width 600
        org-download-heading-lvl 1)

For some reason, org-download-method was being reset from 'directory to 'attachafter loading, and this broke things. I thought maybe I needed to set the variables afterorg-download was loaded, so I did this:

(after! org-download
  (setq org-download-method 'directory
        org-download-image-dir (concat "img/"  (format-time-string "%Y") "/")
        org-download-image-org-width 600
        org-download-heading-lvl 1))

That didn’t work. At startup I was seeing this error:

Error (org-mode-hook): Error running hook “org-fancy-priorities-mode” because: (void-variable org-download-image-dir)

Huh. I guess not everything can be set after org-download, so I tried only setting org-download-method

(after! org-download
  (setq org-download-method 'directory))

This worked. The other settings are done in the (after! org block.

It feels like I have to fight Doom too often, but the details and refinement of Doom is worth the trouble.

Doom Emacs from scratch

A week ago I decided to cancel Doom Emacs and go back to building Emacs from Scratch , and once again I was reminded what a terrible idea that is.

Seriously, stock Emacs, even with a leg up from Nano Emacs , gets so many things “wrong” that I could spend the rest of my life fixing things and still wanting more. I thought building from scratch would help me avoid Configuration Fatigue . Wow, was I wrong.

So, back to Doom. I started from scratch with the usual…

git clone --depth 1 https://github.com/hlissner/doom-emacs ~/.emacs.d~/.emacs.d/bin/doom install

Then I edited init.el and enabled just a few non-stock things. “Zen” mode, org-journal, and pandoc-mode. Otherwise, it’s right out of the box.

I copied the gotta-haves from my original config.el. Most of these are around file paths, Org mode, and LaTeX. Plus a few of my favorite key bindings. Otherwise, I left it alone. So far.

Doom Emacs is simply too good to pass up. It handles all of the little behavioral and visual tweaks that would otherwise take forever to learn about and modify on my own. Half of the things it does for me I just expect to be part of Emacs, and am surprised when I find they’re not.

I’m still using the default Doom theme, which isn’t my favorite, but I’m trying to resist farting around with that for at least a couple of days while I get settled back in.