This is still the header! Main site

Adding a Key to Toggle Post Draft Status


... just another quick post on how easy it is to extend Emacs.

My post-writing workflow did not change a lot recently: it's still just writing HTML in HTML.

One thing I didn't write about yet though is how draft posts work.

In theory, we wouldn't even need a special "draft" status. We could just store new posts somewhere else before publishing them? Actually, this is a pretty obvious idea once you get down to writing a blog post about drafts. (This is part of what's nice about writing blog posts.)

Instead, in practice, draft posts are marked by an underscore at the beginning of the directory name. This does need some extra filtering in the RSS code, but has the extra benefit of having one single overview of published and unpublished posts when you look at the relevant directory.

a listing of posts

This way we can just filter them out in the Lisp code that generates the front page and the RSS.

(defun draft-p (article-path)
  "Checks whether ARTICLE-PATH is a draft (by looking for underscores)"
  (not (not (cl-ppcre:scan "^_" (car (last (pathname-directory article-path)))))))

This enables the following workflow. You create a post, you start writing it. You eventually realize that you, for the time being, do not have enough ideas and/or time to finish it and want to jump over to writing another one instead. So, you just open the directory, put an underscore in front of the name, and proceed with creating a new one.

This is too many steps though. Wouldn't it be nice if there was a single key you could toggle underscores with?

This is fortunately Emacs, so doing so is extremely simple.

(defun ssafar-dired-toggle-draftness ()
  (let* ((file (dired-get-filename nil t))  ; Get the filename at point without prompting.
         (basename (file-name-nondirectory file))  ; Extract basename.
         (dirname (file-name-directory file))  ; Extract directory.
         (newname (if (string-prefix-p "_" basename)
                      (substring basename 1)  ; Remove leading underscore.
                    (concat "_" basename))))  ; Add leading underscore.
    (rename-file file (concat dirname newname))  ; Perform renaming.
    (revert-buffer)  ; Refresh Dired buffer to show the change.

Especially given how the entire function has been written by GPT-4.

We can just bind it to the actual underscore key in dired mode.

(with-eval-after-load 'dired
  (define-key dired-mode-map (kbd "_") 'ssafar-dired-toggle-draftness))

You might be wondering whether this is smart enough to notice that we changed the directory name from under an already possibly open file. How do we handle this? The thing is, we currently don't. It wouldn't be hard though! (Maybe a follow-up post?)