Emacs Function to Rename Hugo Blog Post

Writing a Function to Practice Lisp and Complete an Uncommon Task

As part of writing for my blog, I need to start with a file. I derive the filename from the post’s title. Sometimes, I find myself wanting to change the post’s title.

As a matter of preference, I want the title, the filename, and the slug of the Uniform Resource Locator (URL 🔍) to align. I previously wrote an elisp function (tor-post-new) to create a new blog post. That function follows my naming preferences.

Below is that function.

The tor-post-new function

This is the Elisp: dialect of Lisp used in GNU Emacs (Elisp 🔍) to create a new TakeOnRules.com blog post.


(defun tor-post-new (title &optional)
  "Create and visit a new draft blog post for the prompted TITLE.

The file for the blog post conforms to the path schema of posts
for TakeOnRules.com."
  (interactive "sTitle: ")

  (let* ((default-directory (concat tor--repository-path
                                   "/content/posts/"
                                   (format-time-string "%Y/")))
         (fpath (concat default-directory (s-dashed-words title) ".md"))
         (slug (s-dashed-words title)))
    (write-region (concat
                   "---"
                   "\ndate: " (format-time-string "%Y-%m-%d %H:%M:%S %z")
                   "\ndraft: true"
                   "\nlayout: post"
                   "\nlicenses:\n- all-rights-reserved"
                   "\nslug: " slug
                   "\ntitle: '" title "'"
                   "\ntype: post"
                   "\n---\n")
                  nil (expand-file-name fpath) nil nil nil t)
    (find-file (expand-file-name fpath))))

With the above, I type M-x tor-post-new and fill in the blog posts title. This creates a configured file (and buffer) for me to start writing a blog post.

Earlier today, in writing , I had a different working title. I decided to change the title.

To conform to my preference, I chose to replace the title, slug, and renamed the file. Nothing complicated.

I do this a few times a year, but figured I’d practice my Elisp and write jnf/retitle-tor-content, a function that retitles a blog post. Below is that function.

The jnf/retitle-tor-content function

This is the Elisp to re-title a TakeOnRules.com blog post.


(defun jnf/retitle-tor-content (&optional title)
  "Replace the given buffer's title with the new TITLE.

This function will: replace the content's title, update the slug,
and rename the buffer."
    (interactive "sTitle: ")
    (let* ((metadataTitle (concat "title: '" title "'"))
           (slug (s-dashed-words title))
           (metadataSlug (concat "slug: " slug))
           (filename (buffer-file-name))
           (new-filename (concat (file-name-directory filename)
                                 slug
                                 ".md")))

      ;; Replace the title metadata entry
      (goto-char (point-min))
      (while (search-forward-regexp "^title:.*$" nil t)
        (replace-match metadataTitle))

      ;; Replace the slug metadata entry
      (goto-char (point-min))
      (while (search-forward-regexp "^slug:.*$" nil t)
        (replace-match metadataSlug))

      ;; Need to save before we rename the buffer
      (save-buffer)

      ;; Rename the buffer, accounting for version control
      (cond
       ((vc-backend filename)
        (vc-rename-file filename new-filename))
         (t
          (rename-file filename new-filename t)
          (set-visited-file-name new-filename t t)))

      ;; Report filename change
      (message "Renamed %s -> %s" filename new-filename)))

All told, this took about 45 minutes; I’ll never save that much time from this function. However, I continued to learn more about Emacs (Emacs 🔍). I took actions reinforcing that I can extend my text editor to conform to my uses. And I have something to contribute to the larger group of Emacs adopters.