Molding Emacs to Reinforce Habits I Want to Develop

But Also, Don't Go Out and Implement a Bunch of Things

Before I switched to Emacs 🔍, I had a Rake 🔍 task that I invoked to create new blog posts. I’d hop on the terminal, run the task. That task would both stub out a new blog post and open the task in my editor of choice.

This worked, but the script wasn’t integrated into my text editor. So there was a slight context shift to go from I have an idea for a blog post to I’m starting that blog post.

I decided to rewrite it as a Emacs function. This interactive function, named tor-post-new, prompts for the posts title. I fill out the title, and the function create the file with the appropriate Hugo 🔍 front matter and opens that file in a buffer. Later in this post, I share the functions I’ve created.

By moving the function into my text editor, I reduced the friction of creating a new blog post.

, I in the Amplifying the Blogosphere. Which go me thinking, I really should create an interactive function to ease writing entries to the Amplifying the Blogosphere series.

So I wrote tor-post-amplifying-the-blogosphere. This function doesn’t prompt for a title, but instead derives the title based on the day. So I extracted a common function so I could have the two interactive functions use the same basic function for creating the file, filling in the front matter, and editing the new file.

And as I was thinking about it, I realized “You know, if I have an active Emacs region, I may as well grab that regions text and copy that into the new buffer.”

Elisp Functions to Ease Creating Posts

update: I’ve updated the code below to provide a bit more utility. I’ve also favored a plist instead of positional parameters.

The Elisp 🔍 functions

The following code is available on Github.

(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: ")
  (tor-post---create-or-append title))
(defun tor-post-amplifying-the-blogosphere (subheading &optional)
  "Create and visit draft blog post for amplifying the blogosphere.

The file for the blog post conforms to the path schema of posts
for TakeOnRules.com."
  (interactive (list (if (use-region-p)
                         (read-string "Sub-Heading: ")
                       nil)))
  (tor-post---create-or-append
   (format-time-string "Amplifying the Blogosphere (v%Y-%m-%d)")
   :toc "true"
   :subheading subheading
   :series "amplifying-the-blogosphere"
   :tags (list "response to other blogs")))

The tor-post--create function is called by both of the above functions. It’s purpose is to encode the logic and procedures for creating a new post based on the given parameters.

(defun tor-post---create-or-append (title &rest ARGS)
  "Create or append a post with TITLE, any ARGS are optional.

ARGS:

`:tags' a list of tags to add to the frontmatter.
`:series' the series to set in the frontmatter.
`:toc' whether to include a table of contents in the post.
`:subheading' if you have an active region, use this header

If there's an active region, select that text and place it."
  (let* ((default-directory (concat tor--repository-path
                                    "/content/posts/"
                                    (format-time-string "%Y/")))
         (slug (s-dashed-words title))
         (series (plist-get ARGS :series))
         (tags (plist-get ARGS :tags))
         (toc (plist-get ARGS :toc))
         (subheading (plist-get ARGS :subheading))
         (fpath (expand-file-name (concat default-directory slug ".md"))))
    ;; If the file does not exist, create the file with the proper frontmatter.
    (if (not (file-exists-p fpath))
        (write-region
         (concat "---"
                 "\ndate: " (format-time-string "%Y-%m-%d %H:%M:%S %z")
                 "\ndraft: true"
                 "\nlayout: post"
                 "\nlicenses:\n- all-rights-reserved"
                 "\nslug: " (format "%s" slug)
                 "\ntitle: '" title "'"
                 "\ntype: post"
                 (if series (concat "\nseries: " series))
                 (if toc (concat "\ntoc: true"))
                 (if tags (concat "\ntags:"
                                  (mapconcat
                                   (lambda (tag) (concat "\n- " tag))
                                   tags
                                   "")))
                 "\n---\n")
         nil fpath))
    ;; If we have an active region, append that region's content to
    ;; the given file.
    (if (use-region-p)
        (write-region
         (concat
          (if subheading (concat "\n## " subheading "\n\n"))
          (buffer-substring (region-beginning) (region-end)))
         nil fpath t))
    ;; Finally open that file for editing.
    (find-file fpath)))
                                  "")))
                "\n---\n")
        nil fpath nil nil t))
    ;; If we have an active region, append that region's content to
    ;; the given file.
    (if (use-region-p)
        (write-region
         (concat
          "\n## YOUR H2 HERE\n\n"
          (buffer-substring (region-beginning) (region-end)))
          nil
          fpath
          t nil nil nil))
    ;; Finally open that file for editing.
    (find-file fpath)))

With the new tor-post-amplifying-the-blogosphere function, and the “grab the active region’s text”, I’m aware of further workflow refinements. I’m also seeing that I’m drawing closer to a possible event horizon in which I shift fully to Org-mode 🔍 for blogging. I can almost feel the tug of Org-mode.

Let’s dive into that just a bit.

The goal of the tor-post-amplifying-the-blogosphere function is to make it easy to highlight things I’ve found during the day. And in it’s current implementation, the first thing I find is easier to acknowledge.

For those familiar with Org-mode, I have implemented a naive and rudimentary capture process. I am aware that Org-mode’s current tooling would make easier the Amplifying the Blogosphere process.

However, I’ve only written one post in the Amplifying the Blogosphere, so I’m not about to begin migrating my blog from Hugo to Org-mode. However, knowing that there’s tooling that supports the behavior I want to develop raises the possibility of a migration.

Another way to look at this is to think about the functional desires that I might have. When I’m reading articles, I want an easy way to capture the title, URL, and perhaps a block quote of that article. With that captured information, I want to either create a new for today Amplifying the Blogosphere post or append to an existing one. update: I’ve since updated the code and it now does what I’m describing in the preceding sentence.

Of course, I can mimic quite a bit of this by adding to a copy buffer or Emacs kill ring.

So for now, I’ll proceed with what I have and be mindful of possible future work.

Reflection

An earlier version of myself might have jumped at implementing these speculative changes. But, now in my third decade of professional software development, I see this premature feature development as a questing beast.

In a way, this builds on my observations from ; Yes, I might learn something new in pursuing it, but is it actually worth spending that time?

I don’t know, but I do know that slowing down my personal implementation tendencies has always yielded a better solution and conserved my energy to address the important issues. And realistically, I don’t even know if I have a problem that warrants a solution.