Further Molding Emacs to Reinforce Habits

It Ain't Emacs if You Ain't Hacking on Your Config Daily

I wrote about . In that post, I outlined how I wrote some functions to accelerate grabbing some text and starting a new blog post.

I refined and further extended those functions. To start, I wrote down the desired behavior.

Desired Behavior

I want a function that will pre-populate an Amplifying post from an elfeed entry.

If there’s an active region (e.g., selected text), I will wrap that region in a blockquote shortcode. The elfeed entry’s title will be the cite parameter and the entry’s url will be the cite_url.

If there’s no active region, add wrap an A-tag in a CITE-tag. The A-tag’s href will be the entry’s url. And the A-tag’s inner html will be the entry’s title.

For Elfeed Mode

I use elfeed for my Rich Site Summary (RSS 📖) feed reader. By implementing the above functional behavior, I’ll more quickly be able to add entries that I read to my Amplifying the Blogosphere series.

(use-package elfeed
  :straight t
  :after org
  :config
  (setq-default elfeed-search-filter "@2-days-ago +unread ")
  (defun jnf/amplify-elfeed ()
    "Amplify the current `elfeed-show-entry'"
    (interactive)
    (let* ((citeURL (elfeed-entry-link elfeed-show-entry))
           (citeTitle (elfeed-entry-title elfeed-show-entry)))
      (tor-post-amplifying-the-blogosphere citeTitle
                                           :citeTitle citeTitle
                                           :citeURL citeURL)))
  :bind (:map elfeed-search-mode-map
              ("q" . jnf/elfeed-save-db-and-bury))
  :bind (:map elfeed-show-mode-map
             ("" . jnf/amplify-elfeed)
             ("s-7" . jnf/amplify-elfeed)
             ("q" . jnf/elfeed-save-db-and-bury)))

For EWW Mode

In implementing the desired behavior in elfeed, it became trivial to implement this in eww; a text based browser for Emacs 📖.

In cases where the RSS feed is a summary, I often open the elfeed entry in eww. With a small refinement, I created jnf/amplify-eww, a function analogous to jnf/amplify-elfeed.

(use-package eww
  :straight t
  :config
  (defun jnf/amplify-eww ()
    "Amplify the current `eww-data'"
    (interactive)
    (let* ((citeURL (plist-get eww-data :url))
           (citeTitle (plist-get eww-data :title)))
      (tor-post-amplifying-the-blogosphere citeTitle
                                           :citeTitle citeTitle
                                           :citeURL citeURL)))
  :bind (:map eww-mode-map
              ("U" . eww-up-url)
              ("" . jnf/amplify-eww)
              ("s-7" . jnf/amplify-eww))
  :hook ((eww-mode . jnf/reader-visual)))

For All Other Modes

The tor-post-amplifying-the-blogosphere is independently a useful function. In adding the optional parameters citeTitle and citeURL, I’ve extended it’s usefulness.

(global-set-key (kbd "s-7") 'tor-post-amplifying-the-blogosphere)
(global-set-key (kbd "<f7>") 'tor-post-amplifying-the-blogosphere)

(defun tor-post-amplifying-the-blogosphere (subheading &rest ARGS)
  "Create and visit draft post for amplifying the blogosphere.

If there's an active region, prompt for the `SUBHEADING'.  The file
for the blog post conforms to the path schema of posts for
TakeOnRules.com.

Pull the `citeTitle' and `citeURL' from `ARGS' and pass those
along to the `tor-post---create-or-append'"
  (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 "response to other blogs"
   :citeTitle (plist-get ARGS :citeTitle)
   :citeURL (plist-get ARGS :citeURL)))

Extended Create or Append Behavior

And here’s the extended function. I’ve added optional parameters for citeURL and citeTitle.

See Github for the tor-post—create-or-append definition.

(defun tor-post---create-or-append (title &rest ARGS)
  "Create or append a post with `TITLE'.

The following `ARGS' are optional:

`:tags' one or more tags, as a list or string, to add to the
        frontmatter.
`:series' the series to set in the frontmatter.
`:toc' whether to include a table of contents in the post.
`:citeTitle' the title of the URL cited (if any)
`:citeURL' the URL cited (if any)
`: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))
         (citeTitle (plist-get ARGS :citeTitle))
         (citeURL (plist-get ARGS :citeURL))
         (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))
                                   (flatten-tree 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")
            (if citeTitle (concat "\n## " citeTitle "\n")))
          (if citeURL (concat
                       "\n{{< blockquote cite=\""
                       citeTitle "\" cite_url=\""
                       citeURL "\" >}}\n"))
          (buffer-substring (region-beginning) (region-end))
          (if citeURL "\n{{< /blockquote >}}"))
         nil fpath t)
      ;; Without an active region, if we have a citeURL insert a link
      ;; to it.
      (if citeURL
          (write-region
           (concat
            "\n<cite><a href=\"" citeURL
            "\" class=\"u-url p-name\" rel=\"cite\">"
            (or (citeTitle) (citeURL)) "</a></cite>\n")
           nil fpath t)))
    ;; Finally open that file for editing.
    (find-file fpath)))

Conclusion

With just a bit of work, I expanded the function that I am using for capturing and amplifying posts from the blogosphere.

Along the way, I learned more about plist-get; This is similar to older versions of Ruby 📖 using hashes as named parameters.

And with these modifications, I’m beginning to suspect that I’ll want to use something like jnf/amplify-eww and jnf/amplify-elfeed to quickly add to a blog post that isn’t part of the Amplifying the Blogosphere series.