I wrote about Molding Emacs to Reinforce Habits I Want to Develop. 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.