<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Posts with "Programming" tag on Take on Rules</title>
    <link>https://takeonrules.com/</link>
    <description>Posts with "Programming" tag on Take on Rules</description>
    <generator>Hugo -- gohugo.io</generator>
    <copyright>Copyright 2026, Jeremy Friesen</copyright>
      <language>en-us</language>
      <managingEditor>jeremy@takeonrules.com (Jeremy Friesen)</managingEditor>
      <webMaster>jeremy@takeonrules.com (Jeremy Friesen)</webMaster>
      <docs>https://cyber.harvard.edu/rss/rss.html</docs>
      <lastBuildDate>Tue, 23 Dec 2025 08:47:49 -0500</lastBuildDate>
    
    <atom:link href="https://takeonrules.com/tags/programming/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Serializing Somewhat Large Emacs Alists</title>
      <link>https://takeonrules.com/2025/12/23/serializing-somewhat-large-emacs-alists/</link>
      <pubDate>Tue, 23 Dec 2025 08:47:49 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2025/12/23/serializing-somewhat-large-emacs-alists/</guid>
        <category>emacs</category>
        <category>programming</category>
      <description>
        &lt;p&gt;In &lt;a href=&#34;https://git.sr.ht/~jeremyf/mythic-bastionland.el&#34;&gt;my Mythic Bastionland Emacs package&lt;/a&gt; I’ve been populating an &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Emacs&#34;&gt;Emacs&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs”&#34; title=&#34;Other site-wide references of “Emacs”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EMACS&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 &lt;code&gt;alist&lt;/code&gt; with
information related to the state of the map for my Forged from the Worst
campaign.&lt;/p&gt;
&lt;p&gt;I have 14 top-level keys in that &lt;code&gt;alist&lt;/code&gt;: &lt;code&gt;barriers&lt;/code&gt;, &lt;code&gt;curses&lt;/code&gt;, &lt;code&gt;dwellings, escalations&lt;/code&gt;, &lt;code&gt;hazards&lt;/code&gt;, &lt;code&gt;holdings&lt;/code&gt;, &lt;code&gt;known-hexes&lt;/code&gt;, &lt;code&gt;locations&lt;/code&gt;, &lt;code&gt;monuments&lt;/code&gt;, &lt;code&gt;myth, omens-revealed&lt;/code&gt;, &lt;code&gt;rivers&lt;/code&gt;, &lt;code&gt;ruins&lt;/code&gt;, and &lt;code&gt;sanctums&lt;/code&gt;.  Most of those entries have 3 to 6
associated elements, with &lt;code&gt;rivers&lt;/code&gt;, &lt;code&gt;locations&lt;/code&gt;, and &lt;code&gt;barriers&lt;/code&gt; having more.&lt;/p&gt;
&lt;p&gt;Along the way, I found that when I went to persist the &lt;code&gt;alist&lt;/code&gt; to a file, I was
getting trailing &lt;code&gt;...&lt;/code&gt; characters in a few places.  The process was truncating my
data.  Which meant data loss when I went to load the persisted &lt;code&gt;alist&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;No worries, due to the nature of the package, I could rebuild the map data and
it would be true to the state of play (though the non-revealed information would
be different).  However, I wanted to solve this persistence issue.&lt;/p&gt;
&lt;p&gt;I spent an evening searching and exploring the use of &lt;code&gt;prin1&lt;/code&gt; and &lt;code&gt;(setopt eval-expression-print-level nil)&lt;/code&gt; but Emacs seemed to insist that when I went to
print the full variable out, it would truncate.&lt;/p&gt;
&lt;p&gt;So I set about writing out chunks of the data.  Then reassembling those chunks.&lt;/p&gt;
&lt;h2 id=&#34;writing-the-data-out-in-chunks&#34;&gt;Writing the Data Out in Chunks&lt;/h2&gt;
&lt;p&gt;Below is my &lt;a href=&#34;https://git.sr.ht/~jeremyf/mythic-bastionland.el/tree/6e9688a0ab8782a005e70c47fe64eb3627c91033/mythic-bastionland.el#L463-509&#34;&gt;mythic-bastionland-map-write function available at Sourcehut&lt;/a&gt;.  What
the code does is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a feature called &lt;code&gt;mythic-bastionland-map&lt;/code&gt;, which we’ll write as a
loadable package.&lt;/li&gt;
&lt;li&gt;For each association in the map:
&lt;ul&gt;
&lt;li&gt;Chunk that data into groups of 8 and write each sub-group into a variable
with name based on the association’s &lt;code&gt;car&lt;/code&gt; and incremental suffix.&lt;/li&gt;
&lt;li&gt;Store those incremental variable names in another variable.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Store the name of each association’s &lt;code&gt;car&lt;/code&gt; rendered in yet another variable.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun mythic-bastionland-map-write (&amp;amp;optional map)
  &amp;quot;Write the MAP into a re-loadable format.

Emacs is truncating things so I need to jump through some hoops.&amp;quot;
  (setq mythic-bastionland-map (or map (mythic-bastionland-map)))
  (with-temp-buffer
    (let ((features nil))
      (insert &amp;quot;;;; mbm ---  -*- lexical-binding: t -*-\n&amp;quot;)
      (cl-loop for (feature . values) in mythic-bastionland-map do
               (let (;; In my experience somewhere around 10 elements
                     ;; and we start seeing truncation.  So let&#39;s be
                     ;; under that.
                     (size 8)
                     ;; This will be a list of the variable names that,
                     ;; when reassembled, will be the values.
                     (segment-names nil))
                 (cl-pushnew feature features)
                 (dotimes (i (+ 1 (/ (length values) size)))
                   (let (;; Name of variable that will hold a segment
                         ;; of the values.
                         (segment-name
                          (format &amp;quot;mbm--data-%s-%d&amp;quot; feature i)))
                     ;; Track this segment&#39;s variable name.
                     (push (intern segment-name) segment-names)
                     ;; Grab a subset of values for this segment and
                     ;; store it in the variable with name that is the
                     ;; value of the segment.
                     (insert (format &amp;quot;(defvar %s &#39;&amp;quot; segment-name))
                     ;; Yes yes, this is likely less effecient as I&#39;m
                     ;; always reading the list.  But it was quick
                     (prin1 (seq-take
                             (nthcdr (* i size) values) size)
                            (current-buffer))
                     (insert &amp;quot;)\n&amp;quot;)))
                 ;; Now track all of the segment names associated with
                 ;; this feature.
                 (insert (format &amp;quot;(defvar mbm--data-%s-list &#39;&amp;quot; feature))
                 (prin1 segment-names (current-buffer))
                 (insert &amp;quot;)\n&amp;quot;)))
      ;; Last track all feature names so we may reassemble them.
      (insert (format
               &amp;quot;(defvar mbm--features \&amp;quot;%s\&amp;quot;)\n&amp;quot;
               (mapconcat (lambda (e) (format &amp;quot;%s&amp;quot; e))
                          features &amp;quot; &amp;quot;))))
    (insert &amp;quot;(provide &#39;mbm)\n&amp;quot;
            &amp;quot;;;; mythic-bastionland-map.el ends here\n&amp;quot;)
    (write-file mythic-bastionland-map-state-file)))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;reading-the-data-back-in&#34;&gt;Reading the Data Back In&lt;/h2&gt;
&lt;p&gt;I use the &lt;a href=&#34;https://git.sr.ht/~jeremyf/mythic-bastionland.el/tree/6e9688a0ab8782a005e70c47fe64eb3627c91033/mythic-bastionland.el#L519-545&#34;&gt;mythic-bastionland-map-read&lt;/a&gt; to reassemble that segmented data.  When
done I call &lt;code&gt;(unload-feature &#39;mbm)&lt;/code&gt; to remove the fragmented variables, leaving
only the &lt;code&gt;mythic-bastionland-map&lt;/code&gt; variable.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun mythic-bastionland-map-read ()
  &amp;quot;Load the unduly complicated encoding of the map.&amp;quot;
  (unless (f-file-p mythic-bastionland-map-state-file)
    (user-error &amp;quot;No file found at %s&amp;quot;
                mythic-bastionland-map-state-file))
  (require &#39;mbm mythic-bastionland-map-state-file)
  (let ((map nil))
    ;; Our serialized map has a variable mbm--map-features; we use that
    ;; to start our loading of data.
    (dolist (map-feature (s-split &amp;quot; &amp;quot; mbm--features))
      (let* ((values nil)
             ;; The name of each of the variables that houses a segment
             ;; of the feature&#39;s data.
             (segment-names
              (symbol-value
               (intern (format &amp;quot;mbm--data-%s-list&amp;quot; map-feature)))))
        (dolist (segment-name segment-names)
          (dolist (value (symbol-value segment-name))
            (cl-pushnew value values)))
        ;; Now that we&#39;ve reassembled (in reverse order) the values for
        ;; this feature, add them to the underlying map.
        (cl-pushnew (cons (intern map-feature) values) map)))
    ;; With all features and their values loaded, we assign the map to
    ;; something more durable.
    (setq mythic-bastionland-map map))
  ;; And last clean up all those variables we used for reassembly.
  (unload-feature &#39;mbm))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;perhaps-another-way&#34;&gt;Perhaps Another Way?&lt;/h2&gt;
&lt;p&gt;It seems a bit odd that this is how I could reliably read and write the data.
And I’m open for other approaches.  However, I felt it worth sharing this
bespoke method as it might help others.&lt;/p&gt;
&lt;p&gt;If you know of another way, &lt;a href=&#34;https://takeonrules.com/contact-me/&#34;&gt;please contact me&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;structured-data-and-iterating&#34;&gt;Structured Data and Iterating&lt;/h2&gt;
&lt;p&gt;While working on &lt;a href=&#34;https://git.sr.ht/~jeremyf/mythic-bastionland.el&#34;&gt;my Mythic Bastionland Emacs package&lt;/a&gt;, I have been very pleased
with the malleability of the &lt;code&gt;alist&lt;/code&gt;, and their ease of testing; in part because
of the &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop&#34;&gt;Read-eval-print loop&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Read-eval-print loop&#34;&gt;REPL&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Read-eval-print loop”&#34; title=&#34;Other site-wide references of “Read-eval-print loop”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-REPL&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 but also because of the nature of Lisp.&lt;/p&gt;
&lt;p&gt;I can easily grab a portion of the syntax tree and reliably mash on that in the
&lt;abbr title=&#34;Read-eval-print loop&#34;&gt;REPL&lt;/abbr&gt;
.  Think about other programming languages, if you want to use a portion of
the inner logic of a function, what steps do you need to take to use it?&lt;/p&gt;
&lt;p&gt;Due to the primacy of the &lt;code&gt;alist&lt;/code&gt; there are fantastic functions for working
with them.&lt;/p&gt;
&lt;p&gt;Segmenting the data was a bit odd, I was hoping to simply dump the &lt;code&gt;alist&lt;/code&gt; to a
file.  However, with the problems I encountered, I started exploring other
options.  Maybe write to JSON and load from JSON.  But then I would’ve needed to
establish a mechanism for describing that transformation.&lt;/p&gt;
&lt;ins aria-labelledby=&#34;section-update-2025-12-23&#34; class=&#34;update&#34; datetime=&#34;2025-12-23&#34;&gt;&lt;h2 id=&#34;section-update-2025-12-23&#34;&gt;&lt;time datetime=&#34;2025-12-23&#34;&gt;Dec 23, 2025&lt;/time&gt; update&lt;/h2&gt; &lt;p&gt;
Reader’s rallied and submitted some options.  The following refactor works in
place of the previous implementations.
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun mythic-bastionland-map-write (&amp;amp;optional map)
  &amp;quot;Write the MAP into a re-loadable format.&amp;quot;
  (setq mythic-bastionland-map (or map (mythic-bastionland-map)))
  (with-temp-buffer
    (let ((print-level nil)
          (print-length nil))
      (prin1 mythic-bastionland-map (current-buffer)))
    (write-file mythic-bastionland-map-state-file)))

(defun mythic-bastionland-map-read ()
  &amp;quot;Load the persisted map.&amp;quot;
  (if-let ((file mythic-bastionland-map-state-file))
      (if (f-file-p file)
          (progn
            (setq mythic-bastionland-map
                  (read (with-temp-buffer
                          (insert-file-contents file)
                          (buffer-string))))
            (message &amp;quot;Loaded mythic-bastionland-map from %s&amp;quot; file))
        (user-error &amp;quot;No file found at %s&amp;quot;
                    mythic-bastionland-map-state-file))
    (user-error &amp;quot;&#39;mythic-bastionland-state-file is nil&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;
&lt;/ins&gt;


      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Extending Core Emacs Bookmark Package</title>
      <link>https://takeonrules.com/2025/12/10/extending-core-emacs-bookmark-package/</link>
      <pubDate>Wed, 10 Dec 2025 21:01:36 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2025/12/10/extending-core-emacs-bookmark-package/</guid>
        <category>emacs</category>
        <category>programming</category>
      <description>
        &lt;p&gt;&lt;time datetime=&#34;2025-12-09&#34; title=&#34;2025-12-09&#34;&gt;Yesterday&lt;/time&gt; I wrote &lt;a href=&#34;https://takeonrules.com/2025/12/09/extending-emacs-to-play-mythic-bastionland/&#34;&gt;Extending Emacs to Play Mythic Bastionland&lt;/a&gt; and as I thought
about it, I realized that I was coming very close to re-implementing bookmarks.
What I had worked.  But lacked the elegance of the bookmark ecosystem when
adding to the PDF list.&lt;/p&gt;
&lt;p&gt;And for those who took heart of what I did yesterday, read on, I found some bugs
and fixed them.&lt;/p&gt;
&lt;p&gt;So with time to think about it, I set about exploring how I might open a PDF to
a random page (from a list of possible pages).  Also, how I could capture that I
want this bookmark to be a random page.&lt;/p&gt;
&lt;p&gt;I also thought about how I might generalize my “starting and stopping” game
play.  After all, I have a few solo games that I might pick up.&lt;/p&gt;
&lt;h2 id=&#34;bookmarks&#34;&gt;Bookmarks&lt;/h2&gt;
&lt;p&gt;What follows almost completely replaces the previous implementation; except I
don’t have a nifty re-roll a random table keybinding.&lt;/p&gt;
&lt;p&gt;I had previously written a bookmark handler, so set about writing another one.&lt;/p&gt;
&lt;p&gt;First, we should understand the structure of a PDF bookmark in &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Emacs&#34;&gt;Emacs&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs”&#34; title=&#34;Other site-wide references of “Emacs”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EMACS&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt; (&amp;quot;Tangled Seer&amp;quot;
(filename . &amp;quot;~/mythic=bastionland--core-rules__rules_systems.pdf&amp;quot;)
(position . 1)
(last-modified 26934 62792 320522 78000)
(page . 104)
(slice)
(size . fit-page)
(origin 0.0 . 0.0)
(handler . pdf-view-bookmark-jump-handler))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;pdf-view-bookmark-jump-handler:random&lt;/code&gt; function first checks if there’s an
associated &lt;code&gt;pages&lt;/code&gt; value.  If so, it picks one at random, sets the &lt;code&gt;page&lt;/code&gt; value and
passes it along to the &lt;code&gt;pdf-view-bookmark-jump-handler&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;  (defun pdf-view-bookmark-jump-handler:random (bmk)
    &amp;quot;A handler-function implementing interface for bookmark PDF BMK.

When the handler has a &#39;pages property, which is assumed to be a list,
pick one from that.  Otherwise fallack to the &#39;page property.

See also `pdf-view-bookmark-jump-handler&#39; and
`pdf-view-bookmark-make-record&#39;.&amp;quot;
    (let ((pages
            (bookmark-prop-get bmk &#39;pages)))
      (bookmark-prop-set bmk &#39;page
        (or (seq-random-elt pages) (bookmark-prop-get bmk &#39;page)))
      (pdf-view-bookmark-jump-handler bmk)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To test, I backed-up my bookmarks, and manually changed the handler to and added
a &lt;code&gt;pages&lt;/code&gt; attribute.  I reloaded that file, and everything worked.  Next, how
could I avoid manually editing the file?don’t&lt;/p&gt;
&lt;p&gt;I don’t want to &lt;em&gt;always&lt;/em&gt; have my PDF bookmarks to be random tables.  So
I figured I would again repurpose the existing PDF bookmark making.  This time
with using an advising function.&lt;/p&gt;
&lt;p&gt;First, I call the original &lt;code&gt;pdf-view-bookmark-make-record&lt;/code&gt;; then if I have
enabled 1) prompting for random pages and 2) said I want to specify the pages,
then I prompt for the pages to use in randomization (yup, I had to manually
enter those pages…or at least generate that list of pages programmatically, add
it to the kill ring, then yank it into the prompt).&lt;/p&gt;
&lt;p&gt;Once I had the list of pages, I change the handler from
&lt;code&gt;pdf-view-bookmark-jump-handler&lt;/code&gt; to &lt;code&gt;pdf-view-bookmark-jump-handler:random&lt;/code&gt;.  And
returned the modified bookmark.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;  (defun pdf-view-bookmark-make-record:with-randomizer (&amp;amp;rest app)
    &amp;quot;Conditionally randomize which page we&#39;ll open in a PDF.

See `pdf-view-bookmark-make-record:prompt-for-random&#39;.&amp;quot;
    (let ((bmk
            (apply app)))
      (if (and
            pdf-view-bookmark-make-record:prompt-for-random
            (yes-or-no-p &amp;quot;Specify Random Pages?&amp;quot;))
        (let* ((attributes
                (cdr bmk))
               (integers-as-string
                 (split-string
                   (read-string &amp;quot;Enter pages (comma-separated): &amp;quot;
                     (format &amp;quot;%s,&amp;quot; (alist-get &#39;page attributes)))
                   &amp;quot;[,; ]+&amp;quot; t &amp;quot;[[:space:]]+&amp;quot;)))
          ;; We clobber the existing handler replacing it with one of
          ;; our own devising.
          (setcdr (assoc &#39;handler attributes)
            &#39;pdf-view-bookmark-jump-handler:random)
          (add-to-list &#39;attributes
            (cons &#39;pages
              (mapcar #&#39;string-to-number integers-as-string)))
          ;; We need to return an object of the same form (e.g. a `cons&#39;
          ;; cell).
          (cons (car bmk) attributes))
        bmk)))

  (advice-add #&#39;pdf-view-bookmark-make-record
    :around #&#39;pdf-view-bookmark-make-record:with-randomizer)

  (defvar pdf-view-bookmark-make-record:prompt-for-random
    nil
    &amp;quot;When non-nil, prompt as to whether or not to create a bookmark
that is randomization.&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, I wanted to continue popping those pages into a dedicated side window.
Enter some more advice.  This time, advising the &lt;code&gt;bookmark-jump&lt;/code&gt;.  Reading that
implementation, I was surprised that the default wasn’t a variable; which might
have made things easier.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defvar default-bookmark-display-function
  nil
  &amp;quot;When non-nil, favor opening bookmarks with this function.&amp;quot;)

(defun bookmark-jump-with-display (fn bookmark &amp;amp;optional display-func)
  (let ((display-func
          (or display-func
            default-bookmark-display-function
            (when current-prefix-arg &#39;switch-to-buffer-side-window))))
    (funcall fn bookmark display-func)))
(advice-add #&#39;bookmark-jump :around #&#39;bookmark-jump-with-display)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And last, a little bit of glamour.  I visually show that the bookmark will be
randomized by showing a the 6-face of a die with the word PDF.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;;; Show that I&#39;ll be opening this PDF to a random page.
(put &#39;pdf-view-bookmark-jump-handler:random &#39;bookmark-handler-type &amp;quot;⚅PDF&amp;quot;)

&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;starting-and-stopping&#34;&gt;Starting and Stopping&lt;/h2&gt;
&lt;p&gt;With the new bookmark handling, I set about rethinking the implementation.  As I
needed to and unset more values, the &lt;code&gt;lambda&lt;/code&gt; approach seemed cumbersome and
repetitive.  Also, in my experimentation, I wasn’t properly changing bookmarks
files.  The result was a steady appending to my default bookmarks.&lt;/p&gt;
&lt;p&gt;What follows addresses that issue.  First a variable of no significant insight.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defvar playing-a-game nil
  &amp;quot;When non-nil, indicates that I&#39;m playing a game.

See `playing-a-game-candidates&#39; and `start-playing&#39;.&amp;quot;)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, I define what it means to start and stop playing my &lt;a href=&#34;https://takeonrules.com/series/forged-from-the-worst/&#34;&gt;Forged from the Worst&lt;/a&gt;;
using keywords.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defvar playing-a-game-candidates
  `(
     (&amp;quot;Forged from the Worst (Mythic Bastionland)&amp;quot; .
       ((start .
          ((bmk-display-func . switch-to-buffer-side-window)
            (bmk-prompt-for-random . t)
            (bmk-file . &amp;quot;~/forged=from=the=worst--bookmarks.el&amp;quot;)))
         (stop .
           ((bookmark-display-function . nil)))))
     )
  &amp;quot;Possible games I might be playing via Emacs.  A game you are playing
should have both a &#39;start&#39; and &#39;stop&#39; property.&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then the function that prompts for the game played and applies the
configuration; first stopping the previous game.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun start-playing (game)
  &amp;quot;Start playing the GAME; stopping any currently played game.

A GAME has a &#39;start&#39; and &#39;stop&#39; property, that is an alist.  That alist
has the following properties:

- &#39;bmk-file&#39; :: what file we&#39;ll find our working bookmarks.
- &#39;bmk-display-func&#39; :: the function we use to display bookmarks.
- &#39;bmk-prompt-for-random&#39; :: if we&#39;ll prompt for possible random pages
  in PDF bookmarks.

When a property is not provided, \&amp;quot;suitable\&amp;quot; defaults are assigned.&amp;quot;
  (interactive
    (list
      (let ((handle
              (completing-read &amp;quot;Start Playing: &amp;quot;
                playing-a-game-candidates nil t)))
        (alist-get handle playing-a-game-candidates nil nil #&#39;string=))))
  ;; Stop playing what we were playing...if anything
  ;; Then start playing what we are playing...if anything
  (dolist (config (list playing-a-game (alist-get &#39;start game)))
    (when config
      (let ((file
              (or
                (alist-get &#39;bmk-file config)
                fallback-bookmark-file)))
        (setq default-bookmark-display-function
          (alist-get &#39;bmk-display-func config))
        (setq pdf-view-bookmark-make-record:prompt-for-random
          (alist-get &#39;bmk-prompt-for-random config))
        (bookmark-save)
        (setopt bookmark-default-file file)
        (bookmark-load file t nil t))))
  ;; Last register how to stop playing.
  (setq playing-a-game (alist-get &#39;stop game)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And for symmetry and ease of thinking, I have added the related &lt;code&gt;stop-playing&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun stop-playing ()
  &amp;quot;Stop playing a game.&amp;quot;
  (interactive)
  (start-playing &#39;(&amp;quot;Nothing&amp;quot; . nil)))

&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Consolidating file lookup functions feels like the correct path.  That is reduce
the number of ways I’m opening up files.  And extending existing functionality.
Also learn a bit more about that implementation.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Extending Emacs to Play Mythic Bastionland</title>
      <link>https://takeonrules.com/2025/12/09/extending-emacs-to-play-mythic-bastionland/</link>
      <pubDate>Tue, 09 Dec 2025 19:11:23 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2025/12/09/extending-emacs-to-play-mythic-bastionland/</guid>
        <category>emacs</category>
        <category>programming</category>
        <category>technologies</category>
      <description>
        &lt;p&gt;For playing &lt;cite&gt;&lt;a href=&#34;https://www.drivethrurpg.com/en/product/514996/mythic-bastionland?affiliate_id=318171&#34;&gt;Mythic Bastionland&lt;/a&gt;&lt;/cite&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Mythic Bastionland”&#34; title=&#34;Other site-wide references of “Mythic Bastionland”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-MYTHIC-BASTIONLAND&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
, I’ve been using or building out tooling.  First,
I’m leaning on &lt;a href=&#34;https://github.com/jeremyf/random-table.el&#34;&gt;my random-tables package&lt;/a&gt;.  Next, while playing, I manually
swapped out my baseline &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Emacs&#34;&gt;Emacs&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs”&#34; title=&#34;Other site-wide references of “Emacs”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EMACS&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 bookmarks for game specific bookmarks.  Last, I
began thinking about flipping to random PDF pages for inspiration.&lt;/p&gt;
&lt;h2 id=&#34;swapping-out-bookmarks&#34;&gt;Swapping Out Bookmarks&lt;/h2&gt;
&lt;p&gt;What I posted in &lt;a href=&#34;https://takeonrules.com/2025/12/08/forged-from-the-worst-session-1/&#34;&gt;Forged from the Worst: Session 1&lt;/a&gt; worked, but I started thinking
about how I might alter &lt;span&gt;Emacs&lt;/span&gt;
 while running/playing the game.  At first, this
felt akin to turning on a minor mode.  But the more I thought about it, it was
more equivalent to using &lt;code&gt;org-clock&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A quick brainstorm, and I realized that while playing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I wanted different bookmarks.&lt;/li&gt;
&lt;li&gt;Additional snippets (for my knight and squires name).&lt;/li&gt;
&lt;li&gt;An indicator that I was playing the game.&lt;/li&gt;
&lt;li&gt;And depending on how I organize my campaign world notes, maybe I’d start a
clock on the headline associated with my world notes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I haven’t yet implemented the world notes, but I have made adjustments for the
others.  Here’s what I have:&lt;/p&gt;
&lt;p&gt;First, I establish a variable to track the state of “playing/not playing.”&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defvar playing-forged-from-the-worst nil
  &amp;quot;When non-nil, indicates that I&#39;m playing Forged from the Worst.&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I created a command to toggle that on and off:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun toggle-forged-from-the-worst ()
  &amp;quot;Begin or end playing Forged from the Worst.&amp;quot;
  (interactive)
  (load &amp;quot;jf-mythic-bastionland.el&amp;quot;)
  (setq playing-forged-from-the-worst
    (not playing-forged-from-the-worst))
  (bookmark-load
    (if playing-forged-from-the-worst
      &amp;quot;~/SyncThings/source/forged-from-the-worst/forged=from=the=worst--bookmarks.el&amp;quot;
      &amp;quot;~/emacs-bookmarks.el&amp;quot;)
    t nil t))

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command loads my random tables for the campaign.  Toggles state.  The loads
the correct bookmarks based on state.&lt;/p&gt;
&lt;p&gt;To indicate that I’m “playing”, I then added a variable that I could use with my
modeline:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defvar-local jf/mode-line-format/playing-fftw
    &#39;(:eval
       (when (and (boundp playing-forged-from-the-worst)
               playing-forged-from-the-worst
               (mode-line-window-selected-p))
         (concat
           (propertize &amp;quot; 🎲 &amp;quot; &#39;face &#39;mode-line-highlight) &amp;quot; &amp;quot;))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I add the variable into my &lt;code&gt;mode-line-format&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(setq-default mode-line-format
    &#39;(&amp;quot;%e&amp;quot; &amp;quot; &amp;quot;
       jf/mode-line-format/timeclock
       jf/mode-line-format/org-clock
       jf/mode-line-format/vterm
       jf/mode-line-format/kbd-macro
       jf/mode-line-format/narrow
       jf/mode-line-format/playing-fftw
       jf/mode-line-format/buffer-name-and-status &amp;quot; &amp;quot;
       jf/mode-line-format/major-mode &amp;quot; &amp;quot;
       jf/mode-line-format/project &amp;quot; &amp;quot;
       jf/mode-line-format/vc-branch &amp;quot; &amp;quot;
       jf/mode-line-format/flymake &amp;quot; &amp;quot;
       jf/mode-line-format/eglot
       jf/mode-line-format/which-function
       ))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And ensure that I mark that variable as a &lt;code&gt;risky-local-variable&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(dolist (construct &#39;(
                        jf/mode-line-format/buffer-name-and-status
                        jf/mode-line-format/eglot
                        jf/mode-line-format/flymake
                        jf/mode-line-format/kbd-macro
                        jf/mode-line-format/playing-fftw
                        jf/mode-line-format/major-mode
                        jf/mode-line-format/misc-info
                        jf/mode-line-format/narrow
                        jf/mode-line-format/org-clock
                        jf/mode-line-format/timeclock
                        jf/mode-line-format/project
                        jf/mode-line-format/vc-branch
                        jf/mode-line-format/vterm
                        jf/mode-line-format/which-function
                        ))
    (put construct &#39;risky-local-variable t))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that, when I’m playing the game, I see a little dice in my mode-line and
have access to game specific bookmarks.  That clock part is going to gnaw at me,
so I assume I’ll work through that once I’ve published this post.&lt;/p&gt;
&lt;h2 id=&#34;flipping-to-random-pdf-page-in-emacs&#34;&gt;Flipping to Random PDF Page in Emacs&lt;/h2&gt;
&lt;p&gt;In &lt;a href=&#34;https://takeonrules.com/2025/12/09/mythic-bastionland-session-reflection/&#34;&gt;Mythic Bastionland Session Reflection&lt;/a&gt;, I thought about the fact that I now
had the PDF bookmarked and could quickly, I assume, access the oracular
information at the bottom of the Knight/Seer and Myths pages.&lt;/p&gt;
&lt;p&gt;My first pass was “what was the minimum viable command to open a random page in
a PDF.”  This involved reading the &lt;code&gt;pdf-view-bookmark-jump-handler&lt;/code&gt; code and then
setting about making it happen.&lt;/p&gt;
&lt;p&gt;What I’m presenting is not the first nor second pass, but instead a third
iteration that introduces a bit more utility.  But I digress.&lt;/p&gt;
&lt;p&gt;The algorithm I wanted was:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prompt for whether I wanted a Seer/Knight or a Myth page.&lt;/li&gt;
&lt;li&gt;Open the PDF in a dedicated window.&lt;/li&gt;
&lt;li&gt;Go to a random page based on selection.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are 72 Seer/Knight pages and 72 Myth pages.  On a spread, the left page is
a Seer/Knight and the right page is a Myth.  The Seer/Knight starts on page 28.&lt;/p&gt;
&lt;p&gt;The random function started as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(+ (if seer-knight 28 29)
   (* (random 72) 2))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is pick a number between 0 and 71, multiple that by 2, then add 28 or 29
depending on Seer/Knight or Myth.&lt;/p&gt;
&lt;p&gt;I would then use &lt;code&gt;find-file&lt;/code&gt; and in that buffer call &lt;code&gt;pdf-view-goto-page&lt;/code&gt;.  It was
inelegant but was quick to verify general behavior.&lt;/p&gt;
&lt;p&gt;Then I set about creating a better user experience.  Below is the &lt;code&gt;random-pages&lt;/code&gt;
to choose from, and their relevant information of what file and how to pick a
page.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defvar random-pages
  &#39;((&amp;quot;Knights/Seers&amp;quot; .
     (:file
      &amp;quot;~/Documents/RPGs/Mythic Bastionland/mythic=bastionland--core-rules__rules_systems.pdf&amp;quot;
      :callback
      (lambda () (pdf-view-goto-page (+ 28 (* (random 72) 2))))))
    (&amp;quot;Myths&amp;quot; .
     (:file
      &amp;quot;~/Documents/RPGs/Mythic Bastionland/mythic=bastionland--core-rules__rules_systems.pdf&amp;quot;
      :callback
      (lambda ()
        (pdf-view-goto-page (+ 29 (* (random 72) 2)))))))
  &amp;quot;An alist where `car&#39; is the label and `cdr&#39; is a plist with :file and
optional :callback.

We&#39;ll open the :file, then if a :callback is present, we&#39;ll run that
callback on the newly opened file.&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next up is the function to open the random page in a dedicated window; with the
happy little “bind &lt;kbd&gt;g&lt;/kbd&gt; to pick a new random page.”&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun random-page (&amp;amp;optional label set)
  &amp;quot;Open the file from SET with given LABEL.

SET is assumed to be an alist with `car&#39; as the label and `cdr&#39; a plist
with :file and :callback.  See `random-pages&#39; for more information.&amp;quot;
  (interactive)
  (let* ((set
           (or set random-pages))
          (label
           (or label
             (completing-read &amp;quot;Source: &amp;quot; set nil t)))
          (source
            (alist-get label set nil nil #&#39;string=))
          (file
            (plist-get source :file))
          (display-buffer-mark-dedicated
            t)
          (buffer (or
                    (find-buffer-visiting file)
                    (find-file-noselect file))))
    ;; We&#39;ll pop open a dedicated side window with ample space for
    ;; viewing a new file.
    (pop-to-buffer buffer &#39;((display-buffer-in-side-window)
                             (side . right)
                             (window-width 72)
                             (window-parameters
                               (tab-line-format . none)
                               (mode-line-format . none)
                               (no-delete-other-windows . t))))
    (with-current-buffer buffer
      ;; As a courtesy let&#39;s bind &amp;quot;g&amp;quot; to refresh re-invoke the
      ;; random-page using the same label.
      (local-set-key (kbd &amp;quot;g&amp;quot;)
        (lambda () (interactive)
          (random-page label)))
      ;; I envision that not every random-page would have a callback.
      ;; Which highlights that perhaps the function name &#39;random-page&#39;
      ;; is a misnomer based on my nascent understanding of what this
      ;; could be.
      (when-let ((callback
                   (plist-get source :callback)))
        (funcall callback)))))

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What the above does is pop open a window on the right, with plenty of space to
view the whole page.  That window gets focus and I can close it &lt;kbd&gt;q&lt;/kbd&gt; or
re-roll with &lt;kbd&gt;g&lt;/kbd&gt;.  It also does the work to re-use a buffer if it
already exists.&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;An animated GIF demontsrating the functions along with a list of commands called.&lt;/summary&gt;

&lt;figure  aria-hidden=&#34;true&#34;&gt;
  &lt;img src=&#34;https://takeonrules.com/images/2025-12-09-demo.gif&#34; alt=&#34;&#34; data-original-url=&#34;https://takeonrules.com/images/2025-12-09-demo.gif&#34; width=&#34;720&#34; height=&#34;438&#34; data-width=&#34;720&#34; data-height=&#34;438&#34; /&gt;
&lt;/figure&gt;

&lt;ul class=&#34;org-ul&#34;&gt;
&lt;li&gt;&lt;code&gt;M-x consult-bookmark&lt;/code&gt; to show starting bookmarks.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-x jf/mode-line-format/playing-fftw&lt;/code&gt; to start playing “Forged from the Worst.”&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-x consult-bookmark&lt;/code&gt; show a list of the game specific bookmarks.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-x random-page REG Seer/Knight RET&lt;/code&gt; to pop open a random Knight/Seer page from
the &lt;cite&gt;Mythic Bastionland&lt;/cite&gt;
 rule book.&lt;/li&gt;
&lt;li&gt;Then &lt;kbd&gt;g&lt;/kbd&gt; a few times to pick a new random Knight/Seer page each time.&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I love the virtuous cycle of playing a game, having a tool to support that
game-play, and knowing that I can extend the tool to facilitate play.  The
result tends towards a generative feedback loop.&lt;/p&gt;
&lt;p&gt;And both my during play moments of reflection as well as after play write-ups
helped me consider what might be interesting to add to my tool chain.  Which fed
into exploring existing functionality and implementation to craft something just
a bit new.&lt;/p&gt;
&lt;p&gt;Now to think about my next session of &lt;a href=&#34;https://takeonrules.com/series/forged-from-the-worst&#34;&gt;Forged from the Worst&lt;/a&gt;.  And attending to
how I write up campaign notes while running.  See what’s missing, maybe work and
clocking time there.  That would mean I’d have access to capture content to that
clock, and could leverage more native &lt;span&gt;&lt;a href=&#34;https://orgmode.org/&#34;&gt;Org-Mode&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Mode”&#34; title=&#34;Other site-wide references of “Org-Mode”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-MODE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 functionality.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Managing Light/Dark Scheme in MacOS and Linux</title>
      <link>https://takeonrules.com/2025/12/05/managing-lightdark-scheme-in-macos-and-linux/</link>
      <pubDate>Fri, 05 Dec 2025 21:04:34 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2025/12/05/managing-lightdark-scheme-in-macos-and-linux/</guid>
        <category>emacs</category>
        <category>programming</category>
        <category>technologies</category>
      <description>
        &lt;p&gt;On my personal machine I’m using &lt;span&gt;&lt;a href=&#34;http://debian.org/&#34;&gt;Debian&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Debian”&#34; title=&#34;Other site-wide references of “Debian”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-DEBIAN&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 with the &lt;span&gt;&lt;a href=&#34;https://www.gnome.org/&#34;&gt;Gnome&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Gnome”&#34; title=&#34;Other site-wide references of “Gnome”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-GNOME&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 desktop.  And my work
machine runs MacOS.  I have written an &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Emacs&#34;&gt;Emacs&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs”&#34; title=&#34;Other site-wide references of “Emacs”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EMACS&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 function (&lt;code&gt;M-x jf/dark&lt;/code&gt;) that toggles
between light and dark for either my personal machine or work machine.  You can
&lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/c636f26559b09617a11c0ee82875b6cc12078e0d/emacs.d/init.el#L2533-L2632&#34;&gt;find the code up on Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First we have the general function (and associated alias for ease of typing):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/color-scheme-system-toggle ()
  &amp;quot;Toggle system-wide Dark or Light setting.&amp;quot;
  (interactive)
  (funcall
    (intern
      (format &amp;quot;jf/color-scheme-system-toggle:%s&amp;quot; system-type))))

(defalias &#39;jf/dark &#39;jf/color-scheme-system-toggle)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m opting to use a dispatch pattern, in which I dynamically construct the
function name(s) to call based on the &lt;code&gt;system-type&lt;/code&gt; variable.  A disadvantage of
this approach is that I’m defining functions for an &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Operating_system&#34;&gt;Operating System&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Operating System&#34;&gt;OS&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Operating System”&#34; title=&#34;Other site-wide references of “Operating System”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-OS&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 that is not relevant to
the machine.&lt;/p&gt;
&lt;p&gt;It would be simple to refactor, but for reasons of the example, I’ll keep them
separate.&lt;/p&gt;
&lt;p&gt;For themes I have the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defvar jf/themes-plist
  &#39;(:dark ef-owl :light ef-elea-light))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And I use the following command to set the theme based on the color scheme:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/color-scheme:emacs (&amp;amp;optional given-scheme)
  &amp;quot;Function to load named theme.&amp;quot;
  (let ((scheme
         (or given-scheme
             (funcall
              (intern
               (format &amp;quot;jf/color-scheme-func:%s&amp;quot; system-type))))))
    (modus-themes-select (plist-get jf/themes-plist scheme))))
&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&#34;for-macos&#34;&gt;For MacOS&lt;/h1&gt;
&lt;p&gt;I have the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/color-scheme-system-toggle:darwin ()
  &amp;quot;Toggle the darwin system scheme.&amp;quot;1’
  (shell-command
   (concat &amp;quot;osascript -e &#39;tell application \&amp;quot;System Events\&amp;quot; &amp;quot;
           &amp;quot;to tell appearance preferences &amp;quot;
           &amp;quot;to set dark mode to not dark mode&#39;&amp;quot;))
  (jf/color-scheme-set-for-emacs))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To determine the MacOS color scheme:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/color-scheme-func:darwin ()
  &amp;quot;Determine MacOS preferred/current theme.&amp;quot;
  (if (equal &amp;quot;Dark&amp;quot;
             (substring
              (shell-command-to-string
               &amp;quot;defaults read -g AppleInterfaceStyle&amp;quot;) 0 4))
      :dark :light))
&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&#34;for-gnulinux-with-gnome&#34;&gt;For GNU/Linux with Gnome&lt;/h1&gt;
&lt;p&gt;The command for Linux and Gnome is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/color-scheme-system-toggle:gnu/linux ()
  &amp;quot;Toggle the gnu/linux system scheme.&amp;quot;
  (let* ((target_scheme
          (plist-get &#39;(:dark :light :light :dark)
                     (jf/color-scheme-func:gnu/linux))))
    ;; Instead of all of the shelling out, we could assemble the shell
    ;; commands into a singular command and issue that.
    (dolist (setting jf/color-scheme-commands:gnu/linux)
      ;; In essence pipe the output to /dev/null
      (shell-command-to-string
       (format (plist-get setting :template)
               (plist-get setting target_scheme))))
    (jf/color-scheme:emacs target_scheme)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The list of settings to change are as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defvar jf/color-scheme-system-toggle/gnome-settings
  &#39;((:template &amp;quot;gsettings set org.gnome.settings-daemon.plugins.color night-light-enabled %s&amp;quot;
               :light &amp;quot;false&amp;quot; :dark &amp;quot;true&amp;quot;)
    (:template &amp;quot;gsettings set org.gnome.desktop.interface color-scheme %s&amp;quot;
               :light &amp;quot;default&amp;quot; :dark &amp;quot;prefer-dark&amp;quot;)
    (:template &amp;quot;gsettings set org.gnome.desktop.interface gtk-theme %s&amp;quot;
               :light &amp;quot;default&amp;quot; :dark &amp;quot;prefer-dark&amp;quot;))
  &amp;quot;A list of plists with three parts:

- :template :: command to run.
- :dark :: what the setting should be to be in \&amp;quot;dark\&amp;quot; mode.
- :light :: what the setting should be to be in \&amp;quot;light\&amp;quot; mode.&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To determine the current color scheme in Gnome:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/color-scheme-func:gnu/linux ()
  &amp;quot;Determine Gnome preferred/current theme.&amp;quot;
  (if (equal
        &amp;quot;&#39;prefer-dark&#39;&amp;quot;
        (s-trim
          (shell-command-to-string
            &amp;quot;gsettings get org.gnome.desktop.interface color-scheme&amp;quot;)))
    :dark :light))
&lt;/code&gt;&lt;/pre&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Automating Adding Books to My Org-Mode Document</title>
      <link>https://takeonrules.com/2025/04/17/automating-adding-books-to-my-org-mode-document/</link>
      <pubDate>Thu, 17 Apr 2025 17:41:43 -0400</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2025/04/17/automating-adding-books-to-my-org-mode-document/</guid>
        <category>emacs</category>
        <category>org-mode</category>
        <category>programming</category>
      <description>
        &lt;h2 id=&#34;the-problem&#34;&gt;The “Problem”&lt;/h2&gt;
&lt;p&gt;I have a lot of books and I want to keep track of what I “own.”  I also have an
&lt;span&gt;&lt;a href=&#34;https://orgmode.org/&#34;&gt;Org-Mode&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Mode”&#34; title=&#34;Other site-wide references of “Org-Mode”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-MODE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 document that has a set of books that I:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;have highlighted one or more quotes&lt;/li&gt;
&lt;li&gt;are on my shopping list&lt;/li&gt;
&lt;li&gt;are books I’ve read or am reading&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, I didn’t really have a concept of “and I &lt;em&gt;own&lt;/em&gt; this book.”  To address
that issue, I set about the process of using a mobile application to track books
I owned.&lt;/p&gt;
&lt;p&gt;However, that meant I had two conceptual sources of data.  Ownership and “a book
of interest” if you will.&lt;/p&gt;
&lt;h2 id=&#34;the-spark&#34;&gt;The Spark&lt;/h2&gt;
&lt;p&gt;&lt;time datetime=&#34;2025-04-16&#34; title=&#34;2025-04-16&#34;&gt;Yesterday&lt;/time&gt; I saw &lt;a href=&#34;https://lars.ingebrigtsen.no/2025/04/15/a-book-tracking-package-for-emacs/&#34;&gt;A Book Tracking Package for Emacs&lt;/a&gt; by &lt;a href=&#34;https://lars.ingebrigtsen.no/about/&#34;&gt;Lars Ingebrigtsen&lt;/a&gt;.  In that
post Lars shares his book tracking solution.  It involves a bar code scanner and
&lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Emacs&#34;&gt;Emacs&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs”&#34; title=&#34;Other site-wide references of “Emacs”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EMACS&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
.&lt;/p&gt;
&lt;p&gt;Curious, I set about getting that code working.  And with a few adjustments,
namely ignoring playing audio files during workflow steps, I was able to get it
working.&lt;/p&gt;
&lt;h2 id=&#34;the-pivot&#34;&gt;The Pivot&lt;/h2&gt;
&lt;p&gt;I spent a bit of time hacking on it, but paused as I considered that what I
wanted was a different.&lt;/p&gt;
&lt;p&gt;Namely, given an &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/International_Standard_Book_Number&#34;&gt;International Standard Book Number&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;International Standard Book Number&#34;&gt;ISBN&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “International Standard Book Number”&#34; title=&#34;Other site-wide references of “International Standard Book Number”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ISBN&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
, I wanted to get the associated book information and
either add the book to my &lt;span&gt;Org-Mode&lt;/span&gt;
 document or update the entry in that
document.&lt;/p&gt;
&lt;p&gt;Also, I myself had a bar-code scanner, and wanted to use that as the thing that
typed the &lt;abbr title=&#34;International Standard Book Number&#34;&gt;ISBN&lt;/abbr&gt;
 into the buffer.  I also considered that I wanted to intervene
during the workflow; namely once I had retrieved the book information from the
&lt;abbr title=&#34;International Standard Book Number&#34;&gt;ISBN&lt;/abbr&gt;
, I needed to decide if I added the book or updated an existing entry.&lt;/p&gt;
&lt;h2 id=&#34;establishing-a-workflow&#34;&gt;Establishing a Workflow&lt;/h2&gt;
&lt;p&gt;Given that I needed to make a decision, I reconsidered my workflow.  Namely, I
would grab a pile of ten or so books, and scan their &lt;abbr title=&#34;International Standard Book Numbers&#34;&gt;ISBNs&lt;/abbr&gt;
 into a buffer.  Then,
with that pile, I would reconcile each book.&lt;/p&gt;
&lt;p&gt;The idea being two-fold:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It is a lot of fun to rapidly point and shoot a bar-code scanner.&lt;/li&gt;
&lt;li&gt;Looking at a list of &lt;abbr title=&#34;International Standard Book Numbers&#34;&gt;ISBNs&lt;/abbr&gt;
 with no other context doesn’t tell me much.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Therefore, build a manageable list of &lt;abbr title=&#34;International Standard Book Numbers&#34;&gt;ISBNs&lt;/abbr&gt;
 then flip to the other task.  Namely
reconciling the remote information with what I have.&lt;/p&gt;
&lt;h2 id=&#34;implementation&#34;&gt;Implementation&lt;/h2&gt;
&lt;p&gt;I drew some inspiration from Lars’s isbn.el; but ultimately set about my own
implementation.  Let’s walk through that.&lt;/p&gt;
&lt;h3 id=&#34;defining-the-structure&#34;&gt;Defining the Structure&lt;/h3&gt;
&lt;p&gt;I defined the &lt;code&gt;jf/book&lt;/code&gt; structure.  I would use this to create a common mapping
for the data retrieved via &lt;abbr title=&#34;International Standard Book Number&#34;&gt;ISBN&lt;/abbr&gt;
 process and my bibliography.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(require &#39;request)
(require &#39;s)

(cl-defstruct jf/book
  &amp;quot;A basic representation of a book as it relates to my personal
bibliography.

Slots:
- label:     Used for comparing to labels from my bibliography; expected
             to conform to `jf/book-make-label&#39; function.
- title:     The ubiquitous human readable identifier of a work.
- author:    The author(s) of the book; separated by \&amp;quot; and \&amp;quot;.
- subtitle:  Usually the words after the colon of a title.
- tags:      A list of tags for the book; these are internal values.
- isbn:      The ISBN for the given book.  One of the unique
             identifiers.
- custom_id: The `org-mode&#39; headline CUSTOM_ID property, used for
             helping find the headline.&amp;quot;
  label
  label
  title
  author
  subtitle
  tags
  isbn
  custom_id)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;caching-that-which-i-already-have&#34;&gt;Caching That Which I Already Have&lt;/h3&gt;
&lt;p&gt;Given that I had an existing set of books already stored locally, I wanted to
cache that information for processing multiple &lt;abbr title=&#34;International Standard Book Numbers&#34;&gt;ISBNs&lt;/abbr&gt;
.  I use &lt;code&gt;my-cache-of-books&lt;/code&gt;
to store that information.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defvar my-cache-of-books
  (make-hash-table :test &#39;equal)
  &amp;quot;We use this as a cache of my bibliography entries that are books,
reprsented as an alist, and for each pair the `car&#39; is a
`jf/book-label&#39; (as formated by `jf/book-make-label&#39;) and the `cdr&#39;
being an instance of `jf/book&#39;.

See `my-cache-of-books/populate&#39; for details on populating
this structure.

Normally I&#39;d prefix this kind thing with \&amp;quot;jf/\&amp;quot;, however I like how
this variable reads.&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;avoiding-magic-strings&#34;&gt;Avoiding Magic Strings&lt;/h3&gt;
&lt;p&gt;As a matter of practice, I tend to avoid using “magic strings”, instead favoring
defined values.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defconst jf/bibliography/tag-own
  &amp;quot;own&amp;quot;
  &amp;quot;The tag used to indicate ownership of a work.&amp;quot;)

(defconst jf/bibliography/tag-books
  &amp;quot;books&amp;quot;
  &amp;quot;The tag used to indicate that a work is book.&amp;quot;)

&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;populating-the-cache&#34;&gt;Populating the Cache&lt;/h3&gt;
&lt;p&gt;As I was working through adding a book via &lt;abbr title=&#34;International Standard Book Number&#34;&gt;ISBN&lt;/abbr&gt;
, I didn’t want to rebuild a list
of all of my books.  The &lt;code&gt;my-cache-of-books/populate&lt;/code&gt; function handles this logic.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;  (defun my-cache-of-books/populate (&amp;amp;optional clear-cache)
  &amp;quot;Populates `my-cache-of-books&#39; with my current books.

When CLEAR-CACHE is non-nil, clobber the cache and rebuild.&amp;quot;
  (when clear-cache (clrhash my-cache-of-books))
  (when (hash-table-empty-p my-cache-of-books)
    (save-excursion
      (with-current-buffer
          (find-file-noselect jf/filename/bibliography)
        (org-map-entries
         (lambda ()
           ;; For some reason the org-map-entries is not filtering
           ;; on only items tagged as books.  Hence the
           ;; conditional.
           (when-let* ((tags
                        (org-element-property
                         :tags (org-element-at-point)))
                       (_
                        (member jf/bibliography/tag-books tags)))
             (let* ((title
                     (org-element-property
                      :title (org-element-at-point)))
                    (author
                     (org-entry-get
                      (org-element-at-point) &amp;quot;AUTHOR&amp;quot;))
                    (subtitle
                     (org-entry-get
                      (org-element-at-point) &amp;quot;SUBTITLE&amp;quot;))
                    (label (jf/book-make-label
                            title subtitle author)))
               (puthash label
                        (make-jf/book
                         :label label
                         :tags tags
                         :title title
                         :subtitle subtitle
                         :author author
                         :custom_id (org-entry-get
                                     (org-element-at-point)
                                     &amp;quot;CUSTOM_ID&amp;quot;)
                         :isbn (org-entry-get
                                (org-element-at-point)
                                &amp;quot;ISBN&amp;quot;))
                        my-cache-of-books))))
         (concat &amp;quot;+level=2+&amp;quot; jf/bibliography/tag-books) &#39;file))))
  my-cache-of-books)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;fetch-a-book-from-an-isbn&#34;&gt;Fetch a Book from an ISBN&lt;/h3&gt;
&lt;p&gt;In &lt;code&gt;jf/book-from-isbn&lt;/code&gt; I convert the &lt;abbr title=&#34;International Standard Book Number&#34;&gt;ISBN&lt;/abbr&gt;
 into a &lt;code&gt;jf/book&lt;/code&gt; data structure.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/book-from-isbn (isbn)
  &amp;quot;Fetch the associated ISBN from Google API and return a `jf/book&#39;.

  TODO: Instead of returning the book, consider taking a function that
  operates on the book.  There would need to be an inversion of behavior.&amp;quot;
  (let ((book nil))
    (request &amp;quot;https://www.googleapis.com/books/v1/volumes&amp;quot;
      :params (list (cons &amp;quot;q&amp;quot; (concat &amp;quot;isbn:&amp;quot; isbn)))
      :parser (lambda ()
                (let ((json-object-type &#39;plist))
                  (json-read)))
      :sync t
      :success (cl-function
                (lambda (&amp;amp;key data &amp;amp;allow-other-keys)
                  (let* ((item
                          (aref (plist-get data :items) 0))
                         (volumeInfo
                          (plist-get item :volumeInfo)))
                    (setq book
                          (let ((title
                                 (plist-get volumeInfo :title))
                                (subtitle
                                 (plist-get volumeInfo :subtitle))
                                (author
                                 (s-join &amp;quot; and &amp;quot;
                                         (plist-get
                                          volumeInfo :authors))))
                            (make-jf/book
                             :isbn isbn
                             :label (jf/book-make-label
                                     title subtitle author)
                             :tags (list
                                    jf/bibliography/tag-own
                                    jf/bibliography/tag-books)
                             :subtitle subtitle
                             :author author
                             :title title)))))))
    book))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;here-i-enter-the-isbn&#34;&gt;Here I Enter the ISBN&lt;/h3&gt;
&lt;p&gt;In &lt;code&gt;jf/add-to-bibliography&lt;/code&gt; function is the entry point into this workflow.  As
the docstring states, I use the function to: “Append or amend to my bibliography
the book associated with the ISBN.”&lt;/p&gt;
&lt;p&gt;It is also the function where I intervene, namely determining if the given book
is already in my bibliography or not.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/add-to-bibliography (isbn &amp;amp;optional clear-cache force)
  &amp;quot;Append or amend to my bibliography the book associated with the ISBN.

When CLEAR-CACHE is non-nil, clobber and rebuild `my-cache-of-books&#39;.

When FORCE ignore already existing ISBN; a bit of a refresh.&amp;quot;
  (interactive (list (read-string &amp;quot;ISBN: &amp;quot;)))
  (let ((books
         (my-cache-of-books/populate clear-cache)))
    (when (or force (not (my-cache-of-books/contains-isbn-p isbn)))
      (let* ((book-from-isbn
              (jf/book-from-isbn isbn))
             (completed-value
              (completing-read
               (format &amp;quot;Match %s: &amp;quot; (jf/book-label book-from-isbn))
               books nil nil
               ;; Maybe we&#39;ll get a direct hit?
               (jf/book-label book-from-isbn))))
        (if-let ((book-from-bibliography
                  (gethash completed-value books)))
            (jf/bibliography/update-book-via-merge
             book-from-bibliography
             book-from-isbn)
          (jf/bibliography/insert-book
           book-from-isbn))))))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;insert-a-book&#34;&gt;Insert a Book&lt;/h3&gt;
&lt;p&gt;When the book I fetched via an &lt;abbr title=&#34;International Standard Book Number&#34;&gt;ISBN&lt;/abbr&gt;
 is not in my &lt;span&gt;Org-Mode&lt;/span&gt;
 file, the
&lt;code&gt;jf/bibliography/insert-book&lt;/code&gt; function inserts a record.  The inline comments
describe some false starts and the why of the solution.&lt;/p&gt;
&lt;p&gt;Restating the comments, I use the &lt;span&gt;Org-Mode&lt;/span&gt;
 capture ecosystem to perform the
heavy lifting of adding a book entry to the document.  Namely by using variable
binding and then calling &lt;code&gt;org-capture&lt;/code&gt;; an approach that felt as though I
leveled-up in my understanding of what was possible.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/bibliography/insert-book (book)
  &amp;quot;Insert BOOK into bibliography.

Where BOOK is a `jf/book&#39; struct.&amp;quot;
  ;; NOTE: My first incarnation was to use `org-capture-string&#39; which
  ;; meant adding to `org-capture-templates&#39; a conceptually \&amp;quot;private\&amp;quot;
  ;; capture template.  That incarnation used \&amp;quot;?\&amp;quot; as the template
  ;; body.  However, when I&#39;d test the behavior, I was getting an empty
  ;; entry.
  ;;
  ;; Instead I deconstructed the concise `org-capture-string&#39; and
  ;; shifted towards binding `kill-ring&#39; and using the \&amp;quot;%c\&amp;quot; capture
  ;; variable.  I like this approach as it eschews adding a useless
  ;; capture template while leveraging the power of the `org-capture&#39;
  ;; ecosystem.
  (let* ((kill-ring
          (list
           (concat (jf/book-title book)
                   &amp;quot; :&amp;quot; (s-join &amp;quot;:&amp;quot; (jf/book-tags book)) &amp;quot;:\n&amp;quot;
                   &amp;quot;:PROPERTIES:\n&amp;quot;
                   &amp;quot;:CUSTOM_ID: &amp;quot;
                   (jf/denote-sluggify-title (jf/book-label book)) &amp;quot;\n&amp;quot;
                   (when (s-present? (jf/book-subtitle book))
                     (concat &amp;quot;:SUBTITLE: &amp;quot;
                             (jf/book-subtitle book) &amp;quot;\n&amp;quot;))
                   (when (s-present? (jf/book-author book))
                     (concat &amp;quot;:AUTHOR: &amp;quot; (jf/book-author book) &amp;quot;\n&amp;quot;))
                   &amp;quot;:ISBN: &amp;quot; (jf/book-isbn book) &amp;quot;\n&amp;quot;
                   &amp;quot;:END:\n&amp;quot;)))
         (org-capture-entry
          &#39;(&amp;quot;B&amp;quot; &amp;quot;Book from ISBN Lookup&amp;quot;
            entry (file+headline jf/filename/bibliography &amp;quot;Works&amp;quot;)
            &amp;quot;%c&amp;quot;
            :immediate-finish t)))
    (org-capture)
    (puthash (jf/book-label book) book my-cache-of-books)
    (message &amp;quot;Appended %s to bibliography&amp;quot; (jf/book-label book))))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;update-a-book&#34;&gt;Update a Book&lt;/h3&gt;
&lt;p&gt;When the book I fetched via an &lt;abbr title=&#34;International Standard Book Number&#34;&gt;ISBN&lt;/abbr&gt;
 is in my &lt;span&gt;Org-Mode&lt;/span&gt;
 file, the
&lt;code&gt;jf/bibliography/update-via-merge&lt;/code&gt; function merges and updates the document.&lt;/p&gt;
&lt;p&gt;In essence, this is about finding the &lt;code&gt;CUSTOM_ID&lt;/code&gt; and adding the &lt;code&gt;own&lt;/code&gt; tag and &lt;abbr title=&#34;International Standard Book Number&#34;&gt;ISBN&lt;/abbr&gt;

to the book.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/bibliography/update-via-merge (from-bibliography from-isbn)
  &amp;quot;Update a book FROM-BIBLIOGRAPHY with FROM-ISBN information.

Where both FROM-BIBLIOGRAPHY and FROM-ISBN are `jf/book&#39; structs.&amp;quot;
  (setf (jf/book-isbn from-bibliography) (jf/book-isbn from-isbn))
  (setf (jf/book-tags from-bibliography)
        (sort (seq-union
               (jf/book-tags from-bibliography)
               (jf/book-tags from-isbn)
               #&#39;string=)))
  (save-restriction
    (widen)
    (save-excursion
      (with-current-buffer
          (find-file-noselect jf/filename/bibliography)
        (org-map-entries
         (lambda ()
           (let ((hl (org-element-at-point)))
             (when (string=
                    (org-entry-get hl &amp;quot;CUSTOM_ID&amp;quot;)
                    (jf/book-custom_id from-bibliography))
               (progn
                 (org-set-property &amp;quot;ISBN&amp;quot;
                                   (jf/book-isbn from-bibliography))
                 (org-set-tags
                  (jf/book-tags from-bibliography))
                 (save-buffer)))))
         (concat &amp;quot;+&amp;quot; jf/bibliography/tag-books &#39;file))
        (message &amp;quot;Updated %s with ISBN %s&amp;quot;
                 (jf/book-label from-bibliography)
                 (jf/book-isbn from-bibliography))))))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;In writing this, I’m thinking of a few next steps.  There’s a &lt;code&gt;TODO&lt;/code&gt; item in my
docstring.  Namely to refactor &lt;code&gt;jf/book-from-isbn&lt;/code&gt;.  Instead of returning a
&lt;code&gt;jf/book&lt;/code&gt;, I would pass a function which would receive a &lt;code&gt;jf/book&lt;/code&gt;.  I’d call that
function on success.&lt;/p&gt;
&lt;p&gt;Why consider that refactor?  It touches back on that mobile application.  I have
already scanned 80 or so books.  And I can export that application’s data and
feed that into my process.  I wouldn’t need to call the Google function but
instead develop the method for creating a &lt;code&gt;jf/book&lt;/code&gt; structure from that exported
data.&lt;/p&gt;
&lt;p&gt;And you may ask, where’s the code?  It is a bit in flux.  In part because I
realized how trivial these next steps were.  And I have this bar code scanner
that demands I start “shooting books.”&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;With this new functionality, I’ve been able to add more functionality into my
“bibliography.”  It now serves as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A repository of quotes associated with their source&lt;/li&gt;
&lt;li&gt;A shopping list&lt;/li&gt;
&lt;li&gt;A reading tracker&lt;/li&gt;
&lt;li&gt;An inventory of my currently owned books&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All in a rich, yet structured, format.&lt;/p&gt;
&lt;p&gt;Further, the resulting workflow and functions helps me “chunk my work”, making
it easier to review without simply mashing “accept.”&lt;/p&gt;
&lt;h2 id=&#34;postscript&#34;&gt;Postscript&lt;/h2&gt;
&lt;p&gt;I used the &lt;span&gt;Emacs&lt;/span&gt;
 &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop&#34;&gt;Read-eval-print loop&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Read-eval-print loop&#34;&gt;REPL&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Read-eval-print loop”&#34; title=&#34;Other site-wide references of “Read-eval-print loop”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-REPL&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 to iterate on the solution.  And all of the code was in my
Bibliography file; usable via &lt;span&gt;Org-Mode&lt;/span&gt;
’s tangle process.&lt;/p&gt;
&lt;p&gt;Why do I mention this?&lt;/p&gt;
&lt;p&gt;I found myself first writing prose, and thinking through Lars’ solution and how
I might modify or extend that implementation in relation to the problem as I
understood it.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Extending consult-notes Package to Add Draft Blog Post Candidates</title>
      <link>https://takeonrules.com/2025/04/11/extending-consult-notes-package-to-add-draft-blog-post-candidates/</link>
      <pubDate>Fri, 11 Apr 2025 16:56:13 -0400</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2025/04/11/extending-consult-notes-package-to-add-draft-blog-post-candidates/</guid>
        <category>emacs</category>
        <category>knowledge-management</category>
        <category>programming</category>
      <description>
        &lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I’m provisionally using the &lt;a href=&#34;https://github.com/mclear-tools/consult-notes&#34;&gt;consult-notes package&lt;/a&gt; to provide find and search
functionality for the notes I write using &lt;span&gt;&lt;a href=&#34;https://protesilaos.com/emacs/denote&#34;&gt;Denote&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Denote”&#34; title=&#34;Other site-wide references of “Denote”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-DENOTE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
.  I write provisionally as I
want to explore its utility relative to other things (such as the &lt;a href=&#34;https://protesilaos.com/emacs/consult-denote&#34;&gt;consult-denote
package&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But that is not why I’m writing this post, instead I’m writing to draw attention
to an approach I took at re-using implementation details in &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Emacs&#34;&gt;Emacs&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs”&#34; title=&#34;Other site-wide references of “Emacs”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EMACS&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 in a way that
is different from other languages.  Namely scoped variable binding.&lt;/p&gt;
&lt;p&gt;I find this important as it is a conceptually different approach from every
other programming languages I’ve used (e.g., Ruby, Python, Javascript, PHP,
Basic, etc.)&lt;/p&gt;
&lt;p&gt;Let’s dig in.&lt;/p&gt;
&lt;h2 id=&#34;consult-notes-denote-implementation&#34;&gt;Consult Notes Denote Implementation&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&#34;https://github.com/mclear-tools/consult-notes/blob/6ece62337d6065e88a91b222fac5e252c00a8d53/consult-notes-denote.el#L84-L118&#34;&gt;consult-notes-denote&amp;ndash;source&lt;/a&gt; is defined as follows.  Importantly, the &lt;code&gt;:items&lt;/code&gt;
property is a chunky lambda.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; By default, I’m hiding the following code, as it is a lot to read through.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;Implementation of the &lt;code&gt;consult-notes-denote--source&lt;/code&gt; constant.&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defconst consult-notes-denote--source
  (list :name     (propertize &amp;quot;Denote notes&amp;quot; &#39;face &#39;consult-notes-sep)
        :narrow   ?d
        :category consult-notes-category
        :annotate consult-notes-denote-annotate-function
        :items    (lambda ()
                    (let* ((max-width 0)
                           (cands (mapcar (lambda (f)
                                            (let* ((id (denote-retrieve-filename-identifier f))
                                                   (title-1 (or (denote-retrieve-title-value f (denote-filetype-heuristics f)) (denote-retrieve-filename-title f)))
                                                   (title (if consult-notes-denote-display-id
                                                              (concat id &amp;quot; &amp;quot; title-1)
                                                            title-1))
                                                   (dir (file-relative-name (file-name-directory f) denote-directory))
                                                   (keywords (denote-extract-keywords-from-path f)))
                                              (let ((current-width (string-width title)))
                                                (when (&amp;gt; current-width max-width)
                                                  (setq max-width (+ consult-notes-denote-title-margin current-width))))
                                              (propertize title &#39;denote-path f &#39;denote-keywords keywords)))
                                          (funcall consult-notes-denote-files-function))))
                      (mapcar (lambda (c)
                                (let* ((keywords (get-text-property 0 &#39;denote-keywords c))
                                       (path (get-text-property 0 &#39;denote-path c))
                                       (dirs (directory-file-name (file-relative-name (file-name-directory path) denote-directory))))
                                  (concat c
                                          ;; align keywords
                                          (propertize &amp;quot; &amp;quot; &#39;display `(space :align-to (+ left ,(+ 2 max-width))))
                                          (propertize (funcall consult-notes-denote-display-keywords-function keywords) &#39;face &#39;consult-notes-name)
                                          (when consult-notes-denote-dir
                                            (propertize (funcall consult-notes-denote-display-dir-function dirs) &#39;face &#39;consult-notes-name)))))
                              cands)))
        ;; Custom preview
        :state  #&#39;consult-notes-denote--state
        ;; Create new note on match fail
        :new     #&#39;consult-notes-denote--new-note))
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;I wanted to re-use the implementation details of the &lt;code&gt;:items&lt;/code&gt; property, but
specify my own &lt;code&gt;consult-notes-denote-files-function&lt;/code&gt;.  Namely one that would
create a candidate list of all denote notes tagged with &lt;code&gt;blogPosts&lt;/code&gt; but did not
have an associated published URL; which in my case is a note lacking a &lt;code&gt;ROAM_REFS&lt;/code&gt;
property.&lt;/p&gt;
&lt;h2 id=&#34;custom-candidate-function-for-draft-blog-posts&#34;&gt;Custom Candidate Function for Draft Blog Posts&lt;/h2&gt;
&lt;p&gt;In a shell, I can query for draft blog posts as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;fd &amp;quot;_blogPosts.*\.org&amp;quot; /path/to/denote/dir | xargs rg &amp;quot;^#\+ROAM_REFS:&amp;quot; \
--ignore-case --files-without-match --sortr modified
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;rsquo;s break that down:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;cite&gt;&lt;a href=&#34;https://github.com/sharkdp/fd&#34;&gt;fd&lt;/a&gt;&lt;/cite&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “fd”&#34; title=&#34;Other site-wide references of “fd”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-FD&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 to find denote name conformant &lt;span&gt;&lt;a href=&#34;https://orgmode.org/&#34;&gt;Org-Mode&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Mode”&#34; title=&#34;Other site-wide references of “Org-Mode”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-MODE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 files with the tag &lt;code&gt;blogPosts&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Pipe those files to &lt;span&gt;&lt;a href=&#34;https://github.com/BurntSushi/ripgrep&#34;&gt;Ripgrep&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Ripgrep”&#34; title=&#34;Other site-wide references of “Ripgrep”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-RIPGREP&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 selecting from that file list files that do not
have a line starting with &lt;code&gt;#+ROAM_REFS:&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;re-using-the-existing&#34;&gt;Re-Using the Existing&lt;/h2&gt;
&lt;p&gt;My first implementation copied the logic of &lt;code&gt;consult-notes-denote--source&lt;/code&gt;.
However, that was a lot of duplicate logic.  I set about what it would take to
re-use much of that logic.&lt;/p&gt;
&lt;p&gt;The following, with &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/d4535301c4c4779f99a1adada1a1dfeb22e7f157/emacs.d/init.el#L5360-L5392&#34;&gt;code available on Github&lt;/a&gt;, is what I settled:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(use-package consult-notes
  :config
  (require &#39;consult-notes-denote)
  ;; Add a draft blog post section to my consult notes.
  (add-to-list &#39;consult-notes-all-sources
    `(:name ,(propertize &amp;quot;Draft Blog Posts&amp;quot; &#39;face &#39;consult-notes-sep)
       :narrow ?D
       :cateogry consult-notes-category
       :items jf/consult-notes/draft-blog-posts/items
       :state  consult-notes-denote--state))
  (defun jf/consult-notes/draft-blog-posts/items ()
    &amp;quot;Return a propertized list of draft blog posts.

The `consult-notes-denote--source&#39; :items value has most all of the
logic I want (encoded as a `lambda&#39;).  However, I want to provide my own
files used in generating the candidates; this is done by way of a
contextual override of `consult-notes-denote-files-function&#39;.

By convention, a draft blog post is one that is tagged with blogPosts
but does not yet have a ROAM_REFS property (meaning I have not
associated the org-mode document with the corresponding published URL of
the document).&amp;quot;
    (let ((consult-notes-denote-files-function
            (lambda ()
              (split-string-and-unquote
                (shell-command-to-string
                  ;; First narrow to files with tags
                  (concat
                    &amp;quot;fd \&amp;quot;_&amp;quot; jf/denote/keywords/blogPosts &amp;quot;.*\\.&amp;quot;
                    (symbol-name denote-file-type) &amp;quot;\&amp;quot; &amp;quot;
                    (denote-directory) &amp;quot; | &amp;quot;
                    &amp;quot;xargs rg \&amp;quot;^#\\+ROAM_REFS:\&amp;quot; -i --files-without-match --sortr modified&amp;quot;))
                &amp;quot;\n&amp;quot;))))
      (funcall (plist-get consult-notes-denote--source :items)))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, instead of my &lt;code&gt;:items&lt;/code&gt; having that chunky lambda, I specified a function
(e.g. &lt;code&gt;jf/consult-notes/draft-blog-posts/items&lt;/code&gt;).  For the context of that
function&amp;rsquo;s evaluation it overwrote the definition of
&lt;code&gt;consult-notes-denote-files-function&lt;/code&gt;.  Then within that context called the &lt;code&gt;:items&lt;/code&gt;
property function stored in &lt;code&gt;consult-notes-denote--source&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The docstring of &lt;code&gt;jf/consult-notes/draft-blog-posts/items&lt;/code&gt; contains much of the
relevant information.&lt;/p&gt;
&lt;p&gt;&lt;time datetime=&#34;2025-04-11&#34; title=&#34;2025-04-11&#34;&gt;Today&lt;/time&gt;’s implementation might look “chunky” but much of it is defining the
overriding function.  Below is a theoretical refactoring that might further
clarify what is happening:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/consult-notes/draft-blog-posts/items ()
  (let ((consult-notes-denote-files-function
         #&#39;jf/consult-notes/draft-blog-posts/files-function))
    (funcall (plist-get consult-notes-denote--source :items))))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;alternatives&#34;&gt;Alternatives?&lt;/h2&gt;
&lt;p&gt;I consider this somewhat magical coming from most other languages.  I &lt;em&gt;might&lt;/em&gt; be
able to accomplish this in &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Ruby_(programming_language)&#34;&gt;Ruby&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Ruby”&#34; title=&#34;Other site-wide references of “Ruby”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-RUBY&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
, but this would likely not be feasible in any
other languages in which I’ve worked.&lt;/p&gt;
&lt;p&gt;Other languages might require that I pass the
&lt;code&gt;consult-notes-denote-files-function&lt;/code&gt; as a parameter (either directly or by way of
a property on a scoping context).&lt;/p&gt;
&lt;p&gt;However the variable scoping meant that I:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;could re-use code&lt;/li&gt;
&lt;li&gt;didn’t need to submit a pull request&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I wanted to have a function to find my draft blog posts.  I also wanted to
minimize duplicate effort.  I could&amp;rsquo;ve used the underlying &lt;code&gt;completing-read&lt;/code&gt; to do
this lookup, but I also wanted to explore tying into a package I have been
using.&lt;/p&gt;
&lt;p&gt;And in tying into that usage, I am encouraging myself to use the package and
make sure it is something I want to keep; or jettison and favor something else.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Extending Org-Mode Export to Include Acronyms Section</title>
      <link>https://takeonrules.com/2025/04/10/extending-org-mode-export-to-include-acronyms-section/</link>
      <pubDate>Thu, 10 Apr 2025 22:41:49 -0400</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2025/04/10/extending-org-mode-export-to-include-acronyms-section/</guid>
        <category>emacs</category>
        <category>programming</category>
      <description>
        &lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2022/10/09/denote-emacs-configuration/&#34;&gt;Denote Emacs Configuration&lt;/a&gt;&lt;/cite&gt; I wrote about adding &lt;code&gt;abbr&lt;/code&gt; and &lt;code&gt;abbr-plural&lt;/code&gt; link
types.  In short, when I exported these link types the process would render an
abbreviation and its title, based on my glossary entries.  At least that’s what
they did for &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/HTML&#34;&gt;Hypertext Markup Language&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Hypertext Markup Language&#34;&gt;HTML&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Hypertext Markup Language”&#34; title=&#34;Other site-wide references of “Hypertext Markup Language”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-HTML&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 and plain text.&lt;/p&gt;
&lt;p&gt;But until &lt;time datetime=&#34;2025-04-10&#34; title=&#34;2025-04-10&#34;&gt;today&lt;/time&gt;, I had deferred on handling the LaTeX export.  There was a
rudimentary handling of it, but I figured I could do more.  So I did.&lt;/p&gt;
&lt;h2 id=&#34;abbreviations-on-my-blog&#34;&gt;Abbreviations on My Blog&lt;/h2&gt;
&lt;p&gt;First, I want to share how I handle this for my blog, as its different from
other export backends.&lt;/p&gt;
&lt;p&gt;I write my blog posts in &lt;span&gt;&lt;a href=&#34;https://orgmode.org/&#34;&gt;Org-Mode&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Mode”&#34; title=&#34;Other site-wide references of “Org-Mode”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-MODE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 and use &lt;span&gt;&lt;a href=&#34;https://ox-hugo.scripter.co&#34;&gt;Ox-Hugo&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Ox-Hugo”&#34; title=&#34;Other site-wide references of “Ox-Hugo”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-OX_HUGO&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 to export into a Markdown
format.&lt;/p&gt;
&lt;p&gt;When exporting for my blog, I pass all of the acronyms through a custom my
glossary &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Hugo_(software)&#34;&gt;Hugo&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Hugo”&#34; title=&#34;Other site-wide references of “Hugo”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-HUGO&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 short-code.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See &lt;a href=&#34;https://github.com/jeremyf/takeonrules-hugo-theme/blob/d909b121e8dcee22fba6acacb42867050fcb4fdd/layouts/shortcodes/glossary.html#L29&#34;&gt;Github for my glossary short-code implementation&lt;/a&gt;; warning this is a
complicated short-code that I don’t want to touch.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
 During the processing, the first time I
encounter a glossary entry, I render the title/name and its abbreviation.  After
that I use the &lt;code&gt;abbr&lt;/code&gt; &lt;abbr title=&#34;Hypertext Markup Language&#34;&gt;HTML&lt;/abbr&gt;
 tag.&lt;/p&gt;
&lt;h2 id=&#34;extending-latex-export&#34;&gt;Extending LaTeX Export&lt;/h2&gt;
&lt;p&gt;For &lt;span&gt;&lt;a href=&#34;https://latex-project.org&#34;&gt;LaTeX&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “LaTeX”&#34; title=&#34;Other site-wide references of “LaTeX”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-LATEX&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 exports and thus generating &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/PDF&#34;&gt;Portable Document Formats&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Portable Document Formats&#34;&gt;PDFs&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Portable Document Formats”&#34; title=&#34;Other site-wide references of “Portable Document Formats”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-PDF&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 I would like similar behavior as my
blog.&lt;/p&gt;
&lt;p&gt;I had found &lt;a href=&#34;https://tex.stackexchange.com/questions/492175/how-to-generate-list-of-abbreviations-in-latex&#34;&gt;How to generate list of abbreviations in LaTeX? (from the LaTeX
Stack Exchange)&lt;/a&gt;; which demonstrates using one of two &lt;span&gt;LaTeX&lt;/span&gt;
 packages:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;acro&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;declare the acronyms in the header and then reference throughout.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;acronym&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;explicitly render the acronymes in their own section.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Due to my initial approach and understanding, I went with the &lt;code&gt;acronym&lt;/code&gt; package.&lt;/p&gt;
&lt;p&gt;Let’s look at the code changes I made.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; Here’s the &lt;a href=&#34;https://github.com/jeremyf/dotemacs/commit/c6231b5c4c27316193b1c240349056eb4f85c227&#34;&gt;Github commit that shows the totality of changes&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
  There are four steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#register-an-encountered-abbreviation&#34;&gt;Register an Encountered Abbreviation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#conditionally-render-an-acronym-section&#34;&gt;Conditionally Render an Acronym Section&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#conditionally-use-the-acronym-package&#34;&gt;Conditionally Use the Acronym Package&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#add-export-handling-functions&#34;&gt;Add Export Handling Functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In summary, these described changes append a section named “List of Acronyms”
that assist in untangling the acronyms I’ve used within the document.&lt;/p&gt;
&lt;p&gt;Let’s dive in.&lt;/p&gt;
&lt;h3 id=&#34;register-an-encountered-abbreviation&#34;&gt;Register an Encountered Abbreviation&lt;/h3&gt;
&lt;p&gt;I was already handling abbreviations in &lt;span&gt;LaTeX&lt;/span&gt;
; though they were somewhat broken
in that I was rendering the associated name/title of the item.&lt;/p&gt;
&lt;p&gt;Based on my read through of the Stack exchange suggestions, I wanted to add to a
list of abbreviations I’d encountered.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; I suppose I could’ve generated a full list of abbreviations for each &lt;span&gt;LaTeX&lt;/span&gt;&lt;br /&gt;
export, but I have 400+ abbreviations and that seemed rather gross and
excessive.&lt;br /&gt;&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;p&gt;I added the &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/c6231b5c4c27316193b1c240349056eb4f85c227/emacs.d/init.el#L712-L719&#34;&gt;following comments and code&lt;/a&gt; to my
&lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/c6231b5c4c27316193b1c240349056eb4f85c227/emacs.d/init.el#L686-L733&#34;&gt;jf/denote/link-ol-abbr-with-property function&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;;; When we encounter an abbreviation, add that to the list.  We&#39;ll
;; later use that list to build a localized abbreviation element.
(let ((abbr-links
        (plist-get info :abbr-links)))
  (unless (alist-get keyword-value abbr-links nil nil #&#39;string=)
    (progn
      (add-to-list &#39;abbr-links (cons keyword-value title))
      (plist-put info :abbr-links abbr-links))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this, each time I encounter an abbreviation, I make not of it for later
processing.  The note includes the abbreviation key and its title (e.g. “PDF”
and “Portable Document Format”).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Based on my debugging, there is a caching layer that minimizes calls to
this function.  That is, we will only call the link generating function once for
a given link (where the link identity is the key and description).&lt;/p&gt;
&lt;h3 id=&#34;conditionally-render-an-acronym-section&#34;&gt;Conditionally Render an Acronym Section&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/c6231b5c4c27316193b1c240349056eb4f85c227/emacs.d/init.el#L3818-L3840&#34;&gt;jf/ox/filter-body/latex function&lt;/a&gt; checks if we’ve encountered abbreviations.
If so we append to the body of the document each encountered abbreviation
(sorted alphabetically) along with its descriptive “title.”&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/ox/filter-body/latex (body backend info)
  &amp;quot;Conditionally add a list of acronyms to the exported LaTeX document.

To have a meaningful render, this requires using the acronym LaTeX
package.  The `jf/ox/filter-final-output/latex&#39; handles injecting that
LaTeX package.&amp;quot;
  (if-let ((abbr-links (plist-get info :abbr-links)))
    ;; We encountered some links, let&#39;s add a section.
    (progn
      (concat
        body
        &amp;quot;\n\\section{List of Acronyms}\n&amp;quot;
        &amp;quot;\\begin{acronym}\n&amp;quot;
        (mapconcat
          (lambda (cell)
            &amp;quot;Create an acro for link.&amp;quot;
            (format &amp;quot;\\acro{%s}{%s}&amp;quot; (car cell) (cdr cell)))
          ;; Sort the keys alphabetically.  Otherwise they are rendered
          ;; in the reverse order in which they are encountered.
          (sort abbr-links :key #&#39;car)
          &amp;quot;\n&amp;quot;)
        &amp;quot;\n\\end{acronym}\n&amp;quot;))
    body))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case the &lt;code&gt;body&lt;/code&gt; parameter is the inner-content of the eventual &lt;span&gt;LaTeX&lt;/span&gt;

document.  It does not contain the header information nor the closing
&lt;code&gt;\end{document}&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;conditionally-use-the-acronym-package&#34;&gt;Conditionally Use the Acronym Package&lt;/h3&gt;
&lt;p&gt;The purpose of this step is to ensure that we have are using the &lt;code&gt;acronym&lt;/code&gt; &lt;span&gt;LaTeX&lt;/span&gt;

package.  I could’ve updated all of my class declarations, but opted for this
route.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/45b409e8ab40739f0b1f8242c10282c1be434c33/emacs.d/init.el#L3806-L3816&#34;&gt;jf/ox/filter-final-output/latex function&lt;/a&gt; injects the &lt;code&gt;acronym&lt;/code&gt; package into
the final &lt;span&gt;LaTeX&lt;/span&gt;
 document.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/ox/filter-final-output/latex (body backend info)
  &amp;quot;Conditionally add an acronym package to exported LaTeX document.&amp;quot;
  (if-let ((abbr-links (plist-get info :abbr-links)))
    (replace-regexp-in-string
      &amp;quot;^\\\\documentclass\\(.*\\)&amp;quot;
      (lambda (md)
        &amp;quot;Acronym package to matching line.&amp;quot;
        (concat &amp;quot;\\\\documentclass&amp;quot; (match-string 1 md)
          &amp;quot;\n\\\\usepackage[printonlyused,withpage]{acronym}&amp;quot;))
      body)
    body))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this context, the &lt;code&gt;body&lt;/code&gt; parameter is the totality of content we will write to
the interstitial &lt;code&gt;tex&lt;/code&gt; file.  That is it contains the &lt;span&gt;LaTeX&lt;/span&gt;
 header information as
well as the begin and end blocks.&lt;/p&gt;
&lt;p&gt;I’m not enamored with using a regular expression, and might tinker with this a
bit more.&lt;/p&gt;
&lt;h3 id=&#34;add-export-handling-functions&#34;&gt;Add Export Handling Functions&lt;/h3&gt;
&lt;p&gt;None of the above matters, until I append these filters to my &lt;span&gt;LaTeX&lt;/span&gt;
 export.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/c6231b5c4c27316193b1c240349056eb4f85c227/emacs.d/init.el#L3785-L3804&#34;&gt;jf/org-export-change-options function&lt;/a&gt; and adding to the
&lt;code&gt;org-export-filter-options-functions&lt;/code&gt; ensures that we call the functions that
&lt;a href=&#34;#conditionally-render-an-acronym-section&#34;&gt;conditionally render an acronym section&lt;/a&gt; and &lt;a href=&#34;#conditionally-use-the-acronym-package&#34;&gt;conditionally use the acronym
package&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/org-export-change-options (plist backend)
  &amp;quot;Conditinally add filter functions to our org-export.&amp;quot;
  (cond
   ((equal backend &#39;latex)
    (if-let ((filter-body
              (plist-get plist :filter-body)))
        (progn
          (add-to-list &#39;filter-body jf/ox/filter-body/latex)
          (plist-put plist :filter-body filter-body))
      (plist-put plist :filter-body &#39;(jf/ox/filter-body/latex)))
    (if-let ((filter-final-output
              (plist-get plist :filter-final-output)))
        (progn
          (add-to-list &#39;filter-final-output jf/ox/filter-final-output/latex)
          (plist-put plist :filter-final-output filter-final-output))
      (plist-put plist :filter-final-output &#39;(jf/ox/filter-final-output/latex)))))
  plist)

(add-to-list &#39;org-export-filter-options-functions
             &#39;jf/org-export-change-options)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code is a bit chatty, but I wanted to ensure that I did not clobber other
filter functions; instead appending to the list of possible filters.&lt;/p&gt;
&lt;h2 id=&#34;a-bit-of-how-i-got-there&#34;&gt;A Bit of How I Got There&lt;/h2&gt;
&lt;p&gt;While working towards this solutions, I took a few different pathways.
Ultimately, I leveraged the &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Emacs&#34;&gt;Emacs&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs”&#34; title=&#34;Other site-wide references of “Emacs”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EMACS&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 debugger and inline documentation of the &lt;code&gt;ox&lt;/code&gt;
package: the &lt;span&gt;Org-Mode&lt;/span&gt;
 export “framework” package.&lt;/p&gt;
&lt;p&gt;I allude to the revelatory moment in the change of the
&lt;code&gt;jf/denote/link-ol-abbr-with-property&lt;/code&gt; parameter name and doc string; changing the
parameter name from &lt;code&gt;protocol&lt;/code&gt; to &lt;code&gt;info&lt;/code&gt;.  I had carried &lt;code&gt;protocol&lt;/code&gt; over from some
other implementation; but a bit of debugging showed me that this was very much
the information channel shared throughout the export.&lt;/p&gt;
&lt;p&gt;With that knowledge, I added to the &lt;code&gt;info&lt;/code&gt; parameter and set about finding a
meaningful place to check the content.&lt;/p&gt;
&lt;p&gt;It became a matter of reading through some source code to see how I might apply
filters; something I knew existed based on previous reads of the &lt;code&gt;ox&lt;/code&gt; package.&lt;/p&gt;
&lt;h2 id=&#34;why-this-vanity-project&#34;&gt;Why This “Vanity Project”?&lt;/h2&gt;
&lt;p&gt;Using a glossary of abbreviations is an endeavor that started with a two-fold
goal:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#registering-as-back-links&#34;&gt;Registering as Back-Links&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#initial-descriptions-of-abbreviations&#34;&gt;Initial Descriptions of Abbreviations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And a third goal that has emerged over time: &lt;a href=&#34;#untangling-the-acronyms-used-at-work&#34;&gt;Untangling the Acronyms Used At
Work&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;registering-as-back-links&#34;&gt;Registering as Back-Links&lt;/h3&gt;
&lt;p&gt;When I was writing my posts in Markdown and directly into my &lt;span&gt;Hugo&lt;/span&gt;
 project, I
established back-link capabilities for glossary items.  As I moved to &lt;span&gt;Org-Mode&lt;/span&gt;

for writing and first &lt;span&gt;&lt;a href=&#34;https://www.orgroam.com/&#34;&gt;Org-Roam&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Roam”&#34; title=&#34;Other site-wide references of “Org-Roam”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-ROAM&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 and then &lt;span&gt;&lt;a href=&#34;https://protesilaos.com/emacs/denote&#34;&gt;Denote&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Denote”&#34; title=&#34;Other site-wide references of “Denote”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-DENOTE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
, I wanted to continue to have
access to back-links.&lt;/p&gt;
&lt;p&gt;And since my &lt;code&gt;abbr&lt;/code&gt; and &lt;code&gt;abbr-plural&lt;/code&gt; conform to &lt;span&gt;Denote&lt;/span&gt;
’s linking schema; using an
abbreviation link registers as a back-link.  Which means later on I can easily
find written references to those glossary terms.&lt;/p&gt;
&lt;h3 id=&#34;initial-descriptions-of-abbreviations&#34;&gt;Initial Descriptions of Abbreviations&lt;/h3&gt;
&lt;p&gt;We live in a world of acronyms.  Consider the three letters `RPG`:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rocket Propelled Grenade&lt;/li&gt;
&lt;li&gt;Role-Playing Game&lt;/li&gt;
&lt;li&gt;Report Program Generator&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of those are terms I’ve used when I’ve typed or spoken `RPG`.&lt;/p&gt;
&lt;p&gt;When blogging about role-playing games, I don’t want to keep writing
“Role-Playing Game” over and over.  I want to use the abbreviation.  But the
first time I introduce an abbreviation, I want to provide the full name.&lt;/p&gt;
&lt;p&gt;In using that strategy, I hope I’m improving the accessibility of my writing.
Helping the reader acclimate to the terms I’m using, while also not maintaining
a verbosity that might be off-putting for readers familiar with the domain.&lt;/p&gt;
&lt;h3 id=&#34;untangling-the-acronyms-used-at-work&#34;&gt;Untangling the Acronyms Used At Work&lt;/h3&gt;
&lt;p&gt;Since I started blogging, I have changed jobs four times.  I have joined:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An academic library&lt;/li&gt;
&lt;li&gt;An early stage start-up&lt;/li&gt;
&lt;li&gt;A software consultancy&lt;/li&gt;
&lt;li&gt;A new-to-me tech domain of product development/engineering&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At each of these, management and other folks would use new-to-me terms.  Each
time, I’d clarify then write down the acronym and its “title”.&lt;/p&gt;
&lt;p&gt;This helped me remember what we were chattering about.  And in some cases,
depending on the documentation maturity of the organization, I’d contribute my
glossary terms back to the organization’s glossary; or my team’s glossary.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Given that I write via &lt;span&gt;Org-Mode&lt;/span&gt;
 documents for different audiences and that I
have a glossary of abbreviated terms, I think it is useful to share at least a
bit about that term.&lt;/p&gt;
&lt;p&gt;For the future, I did note that the &lt;code&gt;acronym&lt;/code&gt; package allows for me to include a
description as a third parameter to rendering the list.  My glossary also
includes descriptions, so at some point, I’m certain I’ll be adding that to my
&lt;span&gt;LaTeX&lt;/span&gt;
 output.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Tending to my Writing Ecosystem and Existing Notes</title>
      <link>https://takeonrules.com/2025/04/09/tending-to-my-writing-ecosystem-and-existing-notes/</link>
      <pubDate>Wed, 09 Apr 2025 22:05:18 -0400</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2025/04/09/tending-to-my-writing-ecosystem-and-existing-notes/</guid>
        <category>knowledge-management</category>
        <category>programming</category>
      <description>
        &lt;p&gt;&lt;time datetime=&#34;2025-04-09&#34; title=&#34;2025-04-09&#34;&gt;Last night&lt;/time&gt; I took some time to re-work my &lt;span&gt;&lt;a href=&#34;https://protesilaos.com/emacs/denote&#34;&gt;Denote&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Denote”&#34; title=&#34;Other site-wide references of “Denote”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-DENOTE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 structure.&lt;/p&gt;
&lt;h2 id=&#34;why-the-re-work&#34;&gt;Why the Re-Work?&lt;/h2&gt;
&lt;p&gt;In part I wanted to move past a pinned version of &lt;span&gt;Denote&lt;/span&gt;
; as I had found a
behavior change that introduced enough chaos in my workflow that I chose to
stick with a known version.&lt;/p&gt;
&lt;p&gt;The observed problem with my pinned version was in back-links.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; I think there might have been another reason for pinning, but that reason is
lost to me (and maybe in my &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Git&#34;&gt;Git&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Git”&#34; title=&#34;Other site-wide references of “Git”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-GIT&#34;&gt;📖&lt;/a&gt;&lt;/small&gt;
commit history).&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;p&gt;Namely, &lt;span&gt;Denote&lt;/span&gt;
 would find back-links, but in my version the link to those files
would point to a missing file; in that the domain was treated as a sub-folder of
the current note.  This was not ideal, as it would mean if I followed that I’d
create a new file (with the same identifier as the back-linking note).&lt;/p&gt;
&lt;p&gt;Related to that problem was my using of an early concept of &lt;a href=&#34;https://protesilaos.com/emacs/denote-silo&#34;&gt;Denote Silos&lt;/a&gt;.  I
wrote about my domains of &lt;span&gt;Denote&lt;/span&gt;
 in 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2022/10/09/denote-emacs-configuration/&#34;&gt;Denote Emacs Configuration&lt;/a&gt;&lt;/cite&gt;.  The idea of the
domains was that some of my notes would travel a bit; that is my glossary would
be on multiple machines, either personal or owned by my employer.&lt;/p&gt;
&lt;p&gt;Each domain was its own git repository, allowing for synchronization between
machines.&lt;/p&gt;
&lt;p&gt;However, I decided to excise my glossary from my work machine.  The shared
glossary was not as useful as I thought.  Which was the linchpin that held the
functional need for a domain; and in removing it, the need collapsed.&lt;/p&gt;
&lt;p&gt;With the need collapsed, I looked towards a simplification.&lt;/p&gt;
&lt;h2 id=&#34;towards-simplification&#34;&gt;Towards Simplification&lt;/h2&gt;
&lt;p&gt;My plan: move all notes into the same directory.  But I wanted this change to be
reversible.&lt;/p&gt;
&lt;p&gt;For each file in a domain, I added the domain as a tag to that file.  I used
dired and &lt;span&gt;Denote&lt;/span&gt;
’s &lt;code&gt;denote-dired-rename-marked-files-add-keywords&lt;/code&gt; function to
apply those tags.&lt;/p&gt;
&lt;p&gt;Once I had tagged each file, I again used dired to move those files out of the
domain and into the general bucket.&lt;/p&gt;
&lt;p&gt;I removed my domain macro and calls to that macro.  With the domain macro gone,
I went hunting for unused code.  And tidied up how I exported a blog post from
&lt;span&gt;&lt;a href=&#34;https://orgmode.org/&#34;&gt;Org-Mode&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Mode”&#34; title=&#34;Other site-wide references of “Org-Mode”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-MODE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; The &lt;a href=&#34;https://github.com/jeremyf/dotemacs/commit/6a8bbb52493db975ab8d13b4749b474ba7ee3368&#34;&gt;Github commit 6a8bbb52493db975ab8d13b4749b474ba7ee3368&lt;/a&gt; contains the
changes.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;p&gt;I did some quick and dirty testing, and things worked.  The tags served a
similar function as the domains.&lt;/p&gt;
&lt;h2 id=&#34;tapping-into-a-habit&#34;&gt;Tapping into a Habit&lt;/h2&gt;
&lt;p&gt;Previously, to create a blog post, I would &lt;code&gt;M-x jf/denote/create--blog-post&lt;/code&gt;,
which I bound to &lt;code&gt;H-d c b&lt;/code&gt;.  &lt;time datetime=&#34;2022-10-09&#34; title=&#34;2022-10-09&#34;&gt;Since&lt;/time&gt; creating that domain macro, I started writing a
daily journal.  This used an &lt;code&gt;org-capture-template&lt;/code&gt;.  And had become a habit I was
sustaining.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2021/06/07/molding-emacs-to-reinforce-habits-i-want-to-develop/&#34;&gt;Molding Emacs to Reinforce Habits I Want to Develop&lt;/a&gt;&lt;/cite&gt; for more on this
habit feedback loop.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;p&gt;I spent some time &lt;time datetime=&#34;2025-04-09&#34; title=&#34;2025-04-09&#34;&gt;today&lt;/time&gt; creating capture templates for these previous domains.
The benefit: the preliminary command I use for my note-taking habit is now the
same preliminary command for composing a blog post and making a glossary entry.&lt;/p&gt;
&lt;p&gt;Let’s look first at &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/77e8e9c085825e2af4e356f60dae546671cb7b8f/emacs.d/personal.el#L66-L91&#34;&gt;my Blog Post org-capture-template&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(add-to-list &#39;org-capture-templates
  &#39;(&amp;quot;b&amp;quot; &amp;quot;Blog Post&amp;quot;
     plain (file denote-last-path)
     (function
       (lambda ()
         (let* ((denote-use-title
                  ;; If I don&#39;t provide the title, then it&#39;ll use the
                  ;; active region as the title, and failing that list
                  ;; previous titles I&#39;ve used from which to select.
                  ;; With this let clause, I&#39;m asking for a clean title.
                  (read-string &amp;quot;Blog Post Title: &amp;quot;))
                 (denote-use-keywords
                  `(,jf/denote/keywords/blogPosts))
                 (denote-org-capture-specifiers
                   ;; When I am capturing with an active region, use the
                   ;; capture wrap; that is bring the highlighted region
                   ;; along.  Else, when I&#39;m not capturing with an
                   ;; active region, just prompt to start writing.
                   (if (use-region-p)
                     &amp;quot;%(jf/denote/capture-wrap :link \&amp;quot;%L\&amp;quot; :content \&amp;quot;%i\&amp;quot;)&amp;quot;
                     &amp;quot;&amp;quot;)))
           (denote-org-capture))))
     :no-save t
     :immediate-finish nil
     :kill-buffer t
     :jump-to-captured t))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I wrote this following the &lt;a href=&#34;https://protesilaos.com/emacs/denote#h:656c70cd-cf9a-4471-a0b5-4f0aaf60f881&#34;&gt;“Create note using Org capture” of the Denote Manual&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I prompt for the title, set the keywords to &lt;code&gt;blogPosts&lt;/code&gt; and have a conditional
specifier.  Namely, if I have a highlighted region when I invoke the capture,
use that region as the baseline for the body.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; I wrote about this in
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2024/12/04/refining-my-quotation-capture-process/&#34;&gt;Refining My Quotation Capture Process&lt;/a&gt;&lt;/cite&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;p&gt;Now let’s look at &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/77e8e9c085825e2af4e356f60dae546671cb7b8f/emacs.d/personal.el#L93-L141&#34;&gt;my Glossary Entry org capture template&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(add-to-list &#39;org-capture-templates
&#39;(&amp;quot;g&amp;quot; &amp;quot;Glossary Entry&amp;quot;
   plain (file denote-last-path)
   (function
     (lambda ()
       ;; (setq-local keywords (list))
       (let* ((keywords
                `(,jf/denote/keywords/glossary))
               (title
                (read-string &amp;quot;Glossary Entry Title: &amp;quot;))
               (is-a-game
                 (yes-or-no-p &amp;quot;Is this a game?&amp;quot;))
               (is-a-tag
                 (yes-or-no-p &amp;quot;Is a tag for Take on Rules?&amp;quot;))
               (abbr
                 (read-from-minibuffer &amp;quot;Abbreviation (empty to skip): &amp;quot;))
               (key
                 (downcase (denote-sluggify-title title))))
         (when is-a-game
           (add-to-list &#39;keywords jf/denote/keywords/games))
         (when (s-present? abbr)
           (add-to-list &#39;keywords jf/denote/keywords/abbr))
         (let* ((denote-use-title
                  title)
                 (denote-use-template
                   (concat
                     &amp;quot;#+GLOSSARY_KEY: &amp;quot; key &amp;quot;\n&amp;quot;
                     (when (s-present? abbr)
                       (concat &amp;quot;#+ABBR: &amp;quot; abbr &amp;quot;\n&amp;quot;))
                     (when is-a-game
                       (concat &amp;quot;#+GAME: &amp;quot; key &amp;quot;\n&amp;quot;))
                     (when (s-present? abbr)
                       (concat
                         &amp;quot;#+PLURAL_ABBR: %^{Plural Abbr|&amp;quot; abbr &amp;quot;s}\n&amp;quot;
                         &amp;quot;#+PLURAL_TITLE: %^{Plural Title|&amp;quot; title &amp;quot;s}\n&amp;quot;))
                     (when is-a-tag
                       (concat &amp;quot;#+TAG: &amp;quot; key &amp;quot;\n&amp;quot;))))
                 (denote-use-signature
                   (when (s-present? abbr)
                     (denote-sluggify-signature abbr)))
                 (denote-use-keywords
                   keywords)
                 (denote-org-capture-specifiers
                   &amp;quot;%?&amp;quot;))
           (denote-org-capture)))))
   :no-save t
   :immediate-finish nil
   :kill-buffer t
   :jump-to-captured t))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This one is far more complicated, in part because my Glossary does a lot of work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Defines what terms are abbreviations&lt;/li&gt;
&lt;li&gt;If and when those abbreviations are plural&lt;/li&gt;
&lt;li&gt;Whether or not the entry is a game&lt;/li&gt;
&lt;li&gt;Whether or not the entry represents a tag I use for blogging&lt;/li&gt;
&lt;li&gt;And some other stuff not captured in this capture template (e.g. when
relevant, the URL(s) of the named item).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When I capture a Glossary Entry, I prompt for the relevant information and then
build a conformant file.&lt;/p&gt;
&lt;h2 id=&#34;what-are-my-personal-capture-templates&#34;&gt;What Are My Personal Capture Templates&lt;/h2&gt;
&lt;p&gt;With these changes, my personal capture templates are as follows:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;kbd&gt;b&lt;/kbd&gt; Blog Post&lt;/dt&gt;
&lt;dd&gt;start writing a blog post (as mentioned above).&lt;/dd&gt;
&lt;dt&gt;&lt;kbd&gt;c&lt;/kbd&gt; Content Clock&lt;/dt&gt;
&lt;dd&gt;capture the highlighted region to the currently
clocking headline.&lt;/dd&gt;
&lt;dt&gt;&lt;kbd&gt;d&lt;/kbd&gt; Dictionary&lt;/dt&gt;
&lt;dd&gt;write to my personal dictionary of discovered
words.&lt;/dd&gt;
&lt;dt&gt;&lt;kbd&gt;g&lt;/kbd&gt; Glossary Entry&lt;/dt&gt;
&lt;dd&gt;create a glossary entry (as mentioned above).&lt;/dd&gt;
&lt;dt&gt;&lt;kbd&gt;j&lt;/kbd&gt; Journal Entry&lt;/dt&gt;
&lt;dd&gt;go to “today”, and insert a time stamp and
position to just start writing.  These are personal thoughts.  And ones that I
am comfortable printing and keeping in my house.&lt;/dd&gt;
&lt;dt&gt;&lt;kbd&gt;p&lt;/kbd&gt; Person to Quote&lt;/dt&gt;
&lt;dd&gt;name a person whom I’m likely to quote; this
ties into my 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2024/11/27/refining-my-personal-bibliography-and-epigraph-process/&#34;&gt;Refining My Personal Bibliography and Epigraph Process&lt;/a&gt;&lt;/cite&gt;.&lt;/dd&gt;
&lt;dt&gt;&lt;kbd&gt;q&lt;/kbd&gt; Quote&lt;/dt&gt;
&lt;dd&gt;associate a quote with a source (person or work).&lt;/dd&gt;
&lt;dt&gt;&lt;kbd&gt;r&lt;/kbd&gt; Add to RSS Feed&lt;/dt&gt;
&lt;dd&gt;add an item to my RSS feed; in writing this I
think I should always assign the tag “provisional”.&lt;/dd&gt;
&lt;dt&gt;&lt;kbd&gt;t&lt;/kbd&gt; Task&lt;/dt&gt;
&lt;dd&gt;add a task to my journal.&lt;/dd&gt;
&lt;dt&gt;&lt;kbd&gt;v&lt;/kbd&gt; Add to Today’s Private Thoughts&lt;/dt&gt;
&lt;dd&gt;My journal is personal, but
sometimes I have private thoughts I want to work through.  These are elements
I won’t print out; I haven’t used this much and consider it on probation.&lt;/dd&gt;
&lt;dt&gt;&lt;kbd&gt;w&lt;/kbd&gt; Work&lt;/dt&gt;
&lt;dd&gt;a named work (e.g. a book, a song, an essay, a blog
post).  Used to provide context for a quote as well as manage my “shopping
list” (as written about in 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2024/11/27/extending-my-bibliography-for-an-on-the-go-shopping-list/&#34;&gt;Extending My Bibliography for an On The Go “Shopping List”&lt;/a&gt;&lt;/cite&gt;)&lt;/dd&gt;
&lt;/dl&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;My &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Emacs&#34;&gt;Emacs&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs”&#34; title=&#34;Other site-wide references of “Emacs”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EMACS&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 environment is a personal hobby that supports my professional,
authorial, and thinking life.  Seeing functional needs diminish and adjacent
technical problems bubble up was my impetus to explore.&lt;/p&gt;
&lt;p&gt;I did so with a reversible mindset, and the end result is that I merged past
paradigms into a current working paradigm.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Adding Actionable Indicators to my Emacs Mode Line</title>
      <link>https://takeonrules.com/2025/04/08/adding-actionable-indicators-to-my-emacs-mode-line/</link>
      <pubDate>Tue, 08 Apr 2025 22:07:48 -0400</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2025/04/08/adding-actionable-indicators-to-my-emacs-mode-line/</guid>
        <category>emacs</category>
        <category>programming</category>
      <description>
        &lt;p&gt;I’ve long used the &lt;a href=&#34;https://www.emacswiki.org/emacs/TypographicalPunctuationMarks&#34;&gt;Typopunct Emacs package&lt;/a&gt; for things like &amp;ldquo;smart quotes&amp;rdquo;,
em-dashes, and en-dashes.  I eschew rendering minor modes in my mode-line, as
this is chatty and not very helpful.&lt;/p&gt;
&lt;p&gt;However, I often find myself toggling &lt;code&gt;typopunct-mode&lt;/code&gt; on and off.  Which prompted
me to explore adding an indicator to the mode-line.&lt;/p&gt;
&lt;h2 id=&#34;before-the-change&#34;&gt;Before the Change&lt;/h2&gt;
&lt;p&gt;First, lets look at the current anatomy of my mode-line.  It’s rather compact;
though the buffer name, branch name, and function name can make for quite a bit
of text.&lt;/p&gt;
&lt;p&gt;While writing this document, the following is my mode-line text:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Adding Actionable Indicators to my Emacs Mode Line ¶ “Org” blog-posts  main ⨍ := Before the Change&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Let’s break this down a bit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Adding Actionable Indicators to my Emacs Mode Line&lt;/code&gt;: the buffer name.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;¶&lt;/code&gt; indicates I’m in a text-mode.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;”Org”&lt;/code&gt; indicates the major mode is &lt;span&gt;&lt;a href=&#34;https://orgmode.org/&#34;&gt;Org-Mode&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Mode”&#34; title=&#34;Other site-wide references of “Org-Mode”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-MODE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
, and as this is wrapped in quotes
means that I’ve activated &lt;code&gt;typopunct-mode&lt;/code&gt; for this buffer.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;blog-posts&lt;/code&gt; is the name of the projectile project.&lt;/li&gt;
&lt;li&gt;&lt;code&gt; main&lt;/code&gt; indicates that the version control branch is &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;⨍ := Before the Change&lt;/code&gt; is the name of the “function” that contains point.  In
&lt;span&gt;Org-Mode&lt;/span&gt;
, that is the containing headline for point.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My mode-line conveys more conditional information, so lets look to my
&lt;code&gt;mode-line-format&lt;/code&gt;.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/1caf9ec7c30479204658704a807d56809ed711c0/emacs.d/init.el#L2319-L2332&#34;&gt;Github for more context regarding mode-line-format&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(setq-default mode-line-format
    &#39;(&amp;quot;%e&amp;quot; &amp;quot; &amp;quot;
       jf/mode-line-format/org-clock
       jf/mode-line-format/vterm
       jf/mode-line-format/kbd-macro
       jf/mode-line-format/narrow
       jf/mode-line-format/buffer-name-and-status &amp;quot; &amp;quot;
       jf/mode-line-format/major-mode &amp;quot; &amp;quot;
       jf/mode-line-format/project &amp;quot; &amp;quot;
       jf/mode-line-format/vc-branch &amp;quot; &amp;quot;
       jf/mode-line-format/flymake &amp;quot; &amp;quot;
       jf/mode-line-format/eglot
       jf/mode-line-format/which-function
       ))
&lt;/code&gt;&lt;/pre&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;jf/mode-line-format/org-clock&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Show an indicator when I have an active &lt;span&gt;Org-Mode&lt;/span&gt;
 clock.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;jf/mode-line-format/vterm&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Show when I’m run &lt;code&gt;vterm&lt;/code&gt; (and allow me to quickly
toggle copy mode).&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;jf/mode-line-format/kbd-macro&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Indicate when I’m recording a keyboard macro.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;jf/mode-line-format/narrow&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Indicate when I’ve narrowed the buffer.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;jf/mode-line-format/buffer-name-and-status&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;The name of the buffer and
whether its read-only or not.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;jf/mode-line-format/major-mode&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Indicate the major-mode as well as its type
(e.g. programming mode, text mode, etc).&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;jf/mode-line-format/project&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;What, if any, is the projectile project name.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;jf/mode-line-format/vc-branch&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;What, if any, is the version control branch.
I can click on it to see the &lt;span&gt;&lt;a href=&#34;https://github.com/magit/magit/&#34;&gt;Magit&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Magit”&#34; title=&#34;Other site-wide references of “Magit”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-MAGIT&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 status.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;jf/mode-line-format/flymake&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;When Flymake is active, show its information.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;jf/mode-line-format/eglot&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;When &lt;a href=&#34;https://github.com/joaotavora/eglot&#34;&gt;eglot&lt;/a&gt; is active, show its information.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;jf/mode-line-format/which-function&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Show the name of the “function” at
point.&lt;/dd&gt;
&lt;/dl&gt;
&lt;h2 id=&#34;after-the-change&#34;&gt;After the Change&lt;/h2&gt;
&lt;p&gt;&lt;time datetime=&#34;2025-04-07&#34; title=&#34;2025-04-07&#34;&gt;Yesterday&lt;/time&gt;, I set about updating my mode line to show me when &lt;code&gt;typopunct-mode&lt;/code&gt; is
on or off.  I also set about making that indicator actionable (e.g. I can click
on it).&lt;/p&gt;
&lt;p&gt;Now when &lt;code&gt;typopunct-mode&lt;/code&gt; is on, I wrap in smart quotes the major mode name.
(e.g. &lt;code&gt;“Org Mode”&lt;/code&gt;) and when it is off, the major mode is not wrapped (e.g. &lt;code&gt;Org Mode&lt;/code&gt;).  Further, I can click on the major mode to now toggle the &lt;code&gt;typopunct-mode&lt;/code&gt;
state.&lt;/p&gt;
&lt;p&gt;I needed a function that would force updating the mode line when the &lt;code&gt;typopunct-mode&lt;/code&gt; changed.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/1caf9ec7c30479204658704a807d56809ed711c0/emacs.d/init.el#L2601-L2607&#34;&gt;Github for more context regarding the jf/toggle-typopunct-mode function&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/toggle-typopunct-mode ()
  &amp;quot;Toggle `typopunct-mode&#39;.&amp;quot;
  (interactive)
  (if typopunct-mode
    (typopunct-mode -1)
    (typopunct-mode 1))
  (force-mode-line-update))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To add a click action to the text, I first needed to define a mode map.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/1caf9ec7c30479204658704a807d56809ed711c0/emacs.d/init.el#L2118-L2124&#34;&gt;Github for more context regarding the jf/mode-line-format/major-mode-map variable&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defvar jf/mode-line-format/major-mode-map
  (let ((map
          (make-sparse-keymap)))
    (define-key map [mode-line down-mouse-1]
      #&#39;jf/toggle-typopunct-mode)
    map)
  &amp;quot;Keymap to display `typopunct-mode&#39;.&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then I modified the function that renders the major mode.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/1caf9ec7c30479204658704a807d56809ed711c0/emacs.d/init.el#L2126-L2143&#34;&gt;Github for more context regarding the
jf/mode-line-format/major-mode-name function&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/mode-line-format/major-mode-name ()
    &amp;quot;Render the major mode as text.

When `typopunct-mode&#39; is active, provide an actionable indicator of its
active nature.&amp;quot;
    (let ((fmt
            (if typopunct-mode &amp;quot;“%s”&amp;quot; &amp;quot;%s&amp;quot;)))
      (propertize
        (format fmt
          (capitalize
            (string-replace &amp;quot;-mode&amp;quot; &amp;quot;&amp;quot; (symbol-name major-mode))))
        &#39;face
        (if (mode-line-window-selected-p)
          &#39;mode-line &#39;mode-line-inactive)
        &#39;local-map
        jf/mode-line-format/major-mode-map
        &#39;help-echo
        (concat &amp;quot;mouse-1: #&#39;jf/toggle-typopunct-mode&amp;quot;))))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I want my mode-line to remain compact, yet information rich, actionable, and not
chatty.  I find this minor tweak to be a quality of life improvement.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>On Elfeed and Backups</title>
      <link>https://takeonrules.com/2025/01/22/on-elfeed-and-backups/</link>
      <pubDate>Wed, 22 Jan 2025 12:03:15 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2025/01/22/on-elfeed-and-backups/</guid>
        <category>blogging</category>
        <category>emacs</category>
        <category>programming</category>
      <description>
        
&lt;aside  role=&#34;note&#34; class=&#34;margin&#34;&gt;

&lt;p&gt;&lt;small&gt;I originally wrote this in my daily journal, but extracted it to a full post.
I’m nearing a point in writing where I need to consider how I might more easily
publish elements of my personal journal, while maintaining some as “too
private.”  This is a significant deviation from my blogs current setup.  Much to
consider, but what I have works, albeit with “friction”; a topic of the &lt;a href=&#34;https://vhbelvadi.com/indieweb-carnival-friction&#34;&gt;first
2025 IndieWeb Carnival “On the importance of friction”&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;
&lt;/aside&gt;

&lt;p&gt;I’m smiling as I’m leaning into the robustness of the &lt;span&gt;&lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;elfeed package&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “elfeed package”&#34; title=&#34;Other site-wide references of “elfeed package”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ELFEED&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
.&lt;/p&gt;
&lt;h2 id=&#34;re-introducing-elfeed&#34;&gt;Re-Introducing Elfeed&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;First&lt;/strong&gt;, I have an &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/RSS&#34;&gt;Rich Site Summary&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Rich Site Summary&#34;&gt;RSS&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Rich Site Summary”&#34; title=&#34;Other site-wide references of “Rich Site Summary”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-RSS&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 feed reader.  In which the “news” rolls in according to
when it was published, not some capturing algorithm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Second&lt;/strong&gt;, as I encounter interesting links by feed entries, I can open them in
&lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Eww_(web_browser)&#34;&gt;Emacs Web Wowser&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Emacs Web Wowser&#34;&gt;EWW&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs Web Wowser”&#34; title=&#34;Other site-wide references of “Emacs Web Wowser”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EMACS-WEB-WOWSER&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
.  From there, I give it a read and if I like the general disposition, I can
invoke &lt;code&gt;eww-copy-alternate-url&lt;/code&gt; to see if there are alternate URLs (e.g. an &lt;abbr title=&#34;Rich Site Summary&#34;&gt;RSS&lt;/abbr&gt;

feed).  And add that to my list of feeds.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Third&lt;/strong&gt;, as I read and want to comment, I invoke &lt;code&gt;org-store-link&lt;/code&gt; which will copy
the entry’s URL and title.  I start capturing my thoughts and invoke
&lt;code&gt;org-insert-link&lt;/code&gt; to past the feed entry and title.  This link type is &lt;code&gt;elfeed&lt;/code&gt;.
Meaning when I click on the link, I’m taken to the cached &lt;span&gt;elfeed package&lt;/span&gt;
 version of that
entry.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fourth&lt;/strong&gt;, I extended my &lt;span&gt;elfeed package&lt;/span&gt;
 link type export from &lt;span&gt;&lt;a href=&#34;https://orgmode.org/&#34;&gt;Org-Mode&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Mode”&#34; title=&#34;Other site-wide references of “Org-Mode”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-MODE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 to export the URL of
the feed item.  Thus when I render my notes as &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/HTML&#34;&gt;Hypertext Markup Language&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Hypertext Markup Language&#34;&gt;HTML&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Hypertext Markup Language”&#34; title=&#34;Other site-wide references of “Hypertext Markup Language”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-HTML&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
, the &lt;span&gt;elfeed package&lt;/span&gt;
 link types are
transformed to the well-known &lt;code&gt;http://…&lt;/code&gt; format.  I wrote about this feature in

&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2024/08/11/exporting-org-mode-elfeed-links/&#34;&gt;Exporting Org Mode Elfeed Links&lt;/a&gt;&lt;/cite&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fifth&lt;/strong&gt;, is the local cache/database of &lt;span&gt;elfeed package&lt;/span&gt;
 entries.  All of those feed entries
that have scrolled through my reader.  Those, in their full text, are stored
locally.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; Writing this, I wish I would’ve started using &lt;span&gt;elfeed package&lt;/span&gt;
many years ago.  But
alas, those posts are lost to the ether.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;p&gt;They are available for offline reading, even years past having read them.  And
I’ve treated these as important artifacts for me to “preserve.”  And by that I
mean, make sure I have regular back-up copies of that information.&lt;/p&gt;
&lt;p&gt;Let’s review that process:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generate an occasional copy of the cache.&lt;/li&gt;
&lt;li&gt;Copy that copy to a few different devices.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;generate-an-occasional-copy-of-the-cache&#34;&gt;Generate an Occasional Copy of the Cache&lt;/h3&gt;
&lt;p&gt;I have the following &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Emacs&#34;&gt;Emacs&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs”&#34; title=&#34;Other site-wide references of “Emacs”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EMACS&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/0f520ffb6d35e0c58ba995e80ea5811740bf108a/emacs.d/personal.el#L1-L27&#34;&gt;code, which is available on Github&lt;/a&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/syncthing-aling ()
  &amp;quot;Synchronize files into SyncThing bucket.&amp;quot;
  (interactive)
  ;; Ensure we have our queue and our ready location
  (mkdir (file-truename &amp;quot;~/SyncThings/queue&amp;quot;) t)
  (mkdir (file-truename &amp;quot;~/SyncThings/source&amp;quot;) t)
  (message &amp;quot;Synchronzing denote files to cloud...&amp;quot;)
  ;; There&#39;s a 1 in 10 chance that we&#39;ll perform the sync.  Toss that d10.
  (if (= 0 (random 10))
    (progn
      (message &amp;quot;Syncing elfeed database...&amp;quot;)
      ;; We tar zip into one directory (our queue) and then move that
      ;; file in its complete state into the ready directory.  As move
      ;; is instantaneous and we don&#39;t need to worry about syncthing
      ;; picking up a partially completed file.
      (shell-command
        (concat &amp;quot;tar -cvzf &amp;quot;
          (file-truename &amp;quot;~/SyncThings/queue/elfeed.tar.gz&amp;quot;)
          &amp;quot; &amp;quot; elfeed-db-directory &amp;quot; &amp;amp;&amp;amp; mv -f ~/SyncThings/queue/elfeed.tar.gz ~/SyncThings/source&amp;amp;&amp;quot;)
        &amp;quot;*syncthing-aling*&amp;quot;
        &amp;quot;*syncthing-aling*&amp;quot;))
    (message &amp;quot;I&#39;ll get you next time Gadget&amp;quot;)))

;; Based on the idea of habit stacking, whenever I pull down my RSS
;; feed, I&#39;ll go ahead and sync my notes.
(advice-add #&#39;jf/elfeed-load-db-and-open :before #&#39;jf/syncthing-aling)
(add-hook &#39;after-init-hook #&#39;jf/syncthing-aling)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s pull out the comments&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; I made some adjustments to the comments to improve clarity, I hope.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
 in the order of operation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Based on the idea of habit stacking, whenever I pull down my &lt;abbr title=&#34;Rich Site Summary&#34;&gt;RSS&lt;/abbr&gt;
 feed, I&amp;rsquo;ll go
ahead and sync my notes; maybe.&lt;/li&gt;
&lt;li&gt;Ensure we have our queue and our ready location.&lt;/li&gt;
&lt;li&gt;There&amp;rsquo;s a 1 in 10 chance that we&amp;rsquo;ll perform the sync.  Toss that d10.&lt;/li&gt;
&lt;li&gt;We &lt;em&gt;tar&lt;/em&gt; and &lt;em&gt;zip&lt;/em&gt; into one directory (our queue) and then move that file in its
complete state into the ready directory.  As move is instantaneous we won&amp;rsquo;t
need to worry about &lt;span&gt;&lt;a href=&#34;https://syncthing.net/&#34;&gt;SyncThing&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “SyncThing”&#34; title=&#34;Other site-wide references of “SyncThing”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-SYNCTHING&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 picking up a partially completed file.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Key in this is building the back-up process into a daily or thrice-daily ritual
of mine.&lt;/p&gt;
&lt;p&gt;I accept that my back-up won’t be “immediately up to date” but in using this
process I can more reliably see when there are errors.  That is I’m putting the
“logs” in a place visible during my ritual of reading my &lt;abbr title=&#34;Rich Site Summary&#34;&gt;RSS&lt;/abbr&gt;
 feed.&lt;/p&gt;
&lt;h3 id=&#34;copy-that-copy-to-a-few-different-devices&#34;&gt;Copy That Copy to a Few Different Devices&lt;/h3&gt;
&lt;p&gt;I setup &lt;span&gt;SyncThing&lt;/span&gt;
 on a few different devices.  And the &lt;abbr title=&#34;Rich Site Summary&#34;&gt;RSS&lt;/abbr&gt;
 feed cache is sent to
those devices as “read only.”  I don’t want to fuss with multiple devices having
conflicting versions of this canonical cache, hence writing them to the devices.&lt;/p&gt;
&lt;p&gt;To restore from those backups, I’d unzip and &lt;em&gt;un-tar&lt;/em&gt; the files.  As there’s no
“operational urgency” to the backup, I’d restore at my leisure and then document
accordingly.  In essence, reverse the process of the &lt;span&gt;Emacs&lt;/span&gt;
 function.&lt;/p&gt;
&lt;p&gt;I’ve set my synchronization rules to only run when the devices are on the same
network.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I feel a contentedness of having a repository of things I’ve read (or at least
gathered) from the Internet.  It is something that I should be able to easily
re-build were I to lose or replace my primary machine.&lt;/p&gt;
&lt;p&gt;I’ve chosen to use &lt;span&gt;SyncThing&lt;/span&gt;
 instead of “pushing to the cloud” in part as a
low-stakes experiment on eschewing cloud storage.&lt;/p&gt;
&lt;p&gt;Why?  This little local archipelago I’m creating requires far less resources
than constantly syncing to a “remote” cloud.  And I have more control over how
it’s used as well as how many copies are saved.&lt;/p&gt;
&lt;p&gt;I’m also treating this as a small, concrete, yet reversible experiment with
cause for reflection.  That is “how might I reduce my cloud storage footprint?”
And adjusting my relationship to “always available” versus “available upon
request.”&lt;/p&gt;
&lt;p&gt;And here’s the realization: I don’t need much to always be available.  And, with
the current process, there’s space to identify what I want available outside of
a tarball and thus “readable” on one of those other devices.&lt;/p&gt;
&lt;p&gt;For example, I’ve shifted &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/0f520ffb6d35e0c58ba995e80ea5811740bf108a/emacs.d/init.el#L4992-L5041&#34;&gt;my Shopping List to write to that ready directory&lt;/a&gt;, not
tarred and zipped, but as a plain text file.  Which I can then read on my phone.&lt;/p&gt;
&lt;p&gt;There’s more to think (and thus write) about in regards to how I’m thinking
about this &lt;span&gt;SyncThing&lt;/span&gt;
 ecosystem.  But for now having a personal back-up is an
absolute reassuring joy.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Forking from a Step in a Stacked Habit</title>
      <link>https://takeonrules.com/2025/01/18/forking-from-a-step-in-a-stacked-habit/</link>
      <pubDate>Sat, 18 Jan 2025 07:12:58 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2025/01/18/forking-from-a-step-in-a-stacked-habit/</guid>
        <category>emacs</category>
        <category>personal</category>
        <category>programming</category>
      <description>
        &lt;p&gt;&lt;time datetime=&#34;2025-01-16&#34; title=&#34;2025-01-16&#34;&gt;Ereyesterday&lt;/time&gt; I wrote 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2025/01/16/some-entries-from-my-personal-journal/&#34;&gt;Some Entries from My Personal Journal&lt;/a&gt;&lt;/cite&gt;, mentioning that
I had adopted my personal journal habit for work.  For a week, I had used the
same capture templates, which produced the same structure.&lt;/p&gt;
&lt;p&gt;The experiment worked, but needed refinement.  I was writing engineering journal
entries, but finding that I needed to carry forward blockers.  I chose to sit,
for a bit, without the refinement to ensure that I was sustaining the habit.&lt;/p&gt;
&lt;h2 id=&#34;clarifying-the-functionality&#34;&gt;Clarifying the Functionality&lt;/h2&gt;
&lt;p&gt;&lt;time datetime=&#34;2025-01-17&#34; title=&#34;2025-01-17&#34;&gt;Yesterday&lt;/time&gt;, while waiting on some information to proceed, I started writing out
how I envisioned using my work journal.  I considered my past work, as mentioned
in 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2022/10/24/adding-a-function-to-carry-forward-an-org-mode-agenda-item/&#34;&gt;Adding a Function to Carry Forward an Org-Mode Agenda Item&lt;/a&gt;&lt;/cite&gt; and 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2023/07/29/revisiting-my-org-mode-time-tracking-and-laying-out-a-different-direction/&#34;&gt;Revisiting My Org-Mode Time Tracking and Laying out a Different Direction&lt;/a&gt;&lt;/cite&gt;.&lt;/p&gt;
&lt;p&gt;However, there was a substantive difference.  At my past work, I was responsible
for tracking my time to specific clients and projects.  In which the accuracy of
the time-sheet was of utmost importance.  In any given week, I might have had 4
or 5 different clients to whom I was billing.&lt;/p&gt;
&lt;p&gt;Contrast to my present situation; I don’t bill to a client and I work on a
singular product (albeit with many components).  Instead, I work towards the
completion of quarterly goals.&lt;/p&gt;
&lt;p&gt;I wrote the following as code comments before getting started:&lt;/p&gt;

&lt;blockquote  class=&#34;h-cite&#34;&gt;

&lt;p&gt;At my current employer, I have quarterly managed business objectives
(MBOs).  These focal activities involve: initiation, tracking work,
and completion (with supporting documentation).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Initiation&lt;/strong&gt; :: Writing the stated objective with narrative around
the goal, measurement, and artifacts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tracking Work&lt;/strong&gt; :: As I work through these objectives, I&amp;rsquo;m
recording and tracking tasks towards the larger MBO.  Some tasks
become blocked and I need to work towards their resolution by
providing sustained energy up and out; to get help with my team.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Completion&lt;/strong&gt; :: This involves providing documentation demonstrating
the completion of the MBO.  I can leverage the tracking information
to provide the documentation.&lt;/p&gt;
&lt;p&gt;The two capture template letters reflect what I&amp;rsquo;m using for my
personal (non-work related) notes.  So I&amp;rsquo;m hoping to piggy back on
that muscle memory as I adopt these tracking approaches.&lt;/p&gt;


&lt;/blockquote&gt;

&lt;h2 id=&#34;reviewing-existing-structures&#34;&gt;Reviewing Existing Structures&lt;/h2&gt;
&lt;p&gt;I already had my &lt;span&gt;Management by Objectives&lt;/span&gt; (&lt;abbr title=&#34;Management by Objectives&#34;&gt;MbOs&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Management by Objectives”&#34; title=&#34;Other site-wide references of “Management by Objectives”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-MANAGEMENT-BY-OBJECTIVE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 in an &lt;span&gt;&lt;a href=&#34;https://orgmode.org/&#34;&gt;Org-Mode&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Mode”&#34; title=&#34;Other site-wide references of “Org-Mode”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-MODE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 document.  The structure looked as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-org-mode&#34;&gt;* TODO [0/3] 2025-Q1 :mbos:
** TODO Do the thing
** TODO Do the other thing
** TODO Veer left
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first line is heading level one for the quarterly goals (e.g. “2025-Q1”)
tagged with &lt;code&gt;mbos&lt;/code&gt;.  It is in the state &lt;code&gt;TODO&lt;/code&gt; with the &lt;code&gt;[0/3]&lt;/code&gt; tracking the state of
the sub-headings.&lt;/p&gt;
&lt;p&gt;The next three lines are each heading level two.  Each is in a &lt;code&gt;TODO&lt;/code&gt; state
followed by their terse name.  They inherit the &lt;code&gt;mbos&lt;/code&gt; tag from the parent
heading.&lt;/p&gt;
&lt;p&gt;Throughout the quarter, I’d rarely revisit those goals.  Instead, I’d hold them
in the back of my head, and towards quarter end revisit and begin assembling
documentation supporting their completion.&lt;/p&gt;
&lt;h2 id=&#34;finding-the-crease&#34;&gt;Finding the Crease&lt;/h2&gt;
&lt;p&gt;I then set about thinking of my capture templates from my daily personal habit.
I mapped &lt;kbd&gt;j&lt;/kbd&gt; to kicking off the day and &lt;kbd&gt;J&lt;/kbd&gt; for appending to
the day.&lt;/p&gt;
&lt;p&gt;I wanted to use the &lt;code&gt;BLOCKED&lt;/code&gt; status for tasks.  Meaning, I’d want a level 3 (or
more) sub-heading, as that’s where I can easily track things in &lt;span&gt;Org-Mode&lt;/span&gt;
.  I
spent a bit of time mapping the previous weeks notes to this newly emerging
structure.&lt;/p&gt;
&lt;p&gt;It gave me a good perspective of what I was working on and what was blocked.
And as I started adding time stamps, I could now start seeing things in the
agenda view; that is I could see what my work week included and where I may have
drifted away from tackling a blocker.&lt;/p&gt;
&lt;h2 id=&#34;make-it-so&#34;&gt;Make it So&lt;/h2&gt;
&lt;p&gt;I settled on a structure as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-org-mode&#34;&gt;* TODO [0/3] 2025-Q1 :mbos:
** TODO [1/2] Do the thing
*** DONE Step 1 :tasks:
*** TODO Step 2 :tasks:
** TODO [0/1] Do the other thing
*** TODO A different step 2 :tasks:
** TODO [0/2] Veer left
*** TODO First you turn :tasks:
*** TODO Then move :tasks:
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;starting-a-task&#34;&gt;Starting a Task&lt;/h3&gt;

&lt;aside  role=&#34;note&#34; class=&#34;margin&#34;&gt;

&lt;p&gt;&lt;small&gt;&lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/40affd269283a71575fb016306b5f3e268f65e98/emacs.d/work.el#L1-L140&#34;&gt;The code for what follows is available on Github&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;
&lt;/aside&gt;

&lt;p&gt;I wrote out my &lt;kbd&gt;j&lt;/kbd&gt; capture template&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See &lt;a href=&#34;https://orgmode.org/manual/Capture-templates.html&#34;&gt;Capture templates (The Org Manual)&lt;/a&gt; for details on the structure of a
capture template.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
, that is start a task that maps to an &lt;abbr title=&#34;Management by Objective&#34;&gt;MbO&lt;/abbr&gt;
:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(add-to-list &#39;org-capture-templates
  &#39;(&amp;quot;j&amp;quot; &amp;quot;Journal task for MBO&amp;quot;
     entry (file+function
             jf/work/filename-for-mbos
             jf/work/position-at-start-of-mbo)
     &amp;quot;TODO %^{Task} :tasks:\n:PROPERTIES:\n:ID: %(org-id-new)\n:END:\n%?&amp;quot;
     :empty-lines-before 1
     :empty-lines-after 1
     :clock-in t
     :clock-resume t))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And set about writing up the positioning function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/work/position-at-start-of-mbo ()
  &amp;quot;Position point at start of MBO.

For inserting entity.&amp;quot;
  (let* ((incomplete-mbos
           (org-map-entries
             (lambda ()
               (let* ((mbo
                        (org-element-at-point))
                       (quarter
                         (car (org-element-lineage mbo))))
                 (cons
                   (concat
                     (propertize
                       (org-element-property :title quarter)
                       &#39;face &#39;org-level-1)
                     (propertize
                       &amp;quot; &amp;gt; &amp;quot;
                       &#39;face &#39;consult-separator)
                     (propertize
                       (org-element-property :title mbo)
                       &#39;face &#39;org-level-2)
                     )
                   (org-element-property :begin mbo))))
             &amp;quot;+LEVEL=2+mbos-noexport+TODO!=\&amp;quot;DONE\&amp;quot;&amp;quot;))
          (mbo
            (completing-read
              &amp;quot;MBO: &amp;quot; incomplete-mbos nil t)))
    (goto-char (alist-get mbo incomplete-mbos nil nil #&#39;string=))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A lingering problem is that this does not account for a daily entry that does
not track towards one of my &lt;abbr title=&#34;Management by Objectives&#34;&gt;MbOs&lt;/abbr&gt;
; for example helping get someone else unstuck.
But I can see space for how I’d do that…make another heading level 2 node that I
don’t report.&lt;/p&gt;
&lt;h3 id=&#34;adding-to-a-task&#34;&gt;Adding to a Task&lt;/h3&gt;
&lt;p&gt;Here’s the &lt;kbd&gt;J&lt;/kbd&gt; capture template, that is append a note to a task.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(add-to-list &#39;org-capture-templates
  &#39;(&amp;quot;J&amp;quot; &amp;quot;Journal task progress for MBO&amp;quot;
     plain (file+function
             jf/work/filename-for-mbos
             jf/work/position-at-end-of-mbo-task-entity)
     &amp;quot;%T :: %?&amp;quot;
     :empty-lines-before 1
     :empty-lines-after 1
     :clock-in t
     :clock-resume t))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here’s the function to find the place to insert the note:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defvar jf/work/org-map-entries-mbo-task-filter
  &amp;quot;+LEVEL=3+mbos+tasks-journals+TODO!=\&amp;quot;DONE\&amp;quot;&amp;quot;
  &amp;quot;The default filter for collecting MBO tasks.&amp;quot;)

(defun jf/work/position-at-end-of-mbo-task-entity ()
  &amp;quot;Position point just before content end of MBO task.

For inserting plain text.&amp;quot;
  (let* ((incomplete-mbo-tasks
           (org-map-entries
             (lambda ()
               (let* ((task
                        (org-element-at-point))
                       (mbo
                         (car (org-element-lineage task)))
                       (quarter
                         (cadr (org-element-lineage task))))
                 (cons
                   (concat
                     (propertize
                       (org-element-property :title quarter)
                       &#39;face &#39;org-level-1)
                     (propertize
                       &amp;quot; &amp;gt; &amp;quot;
                       &#39;face &#39;consult-separator)
                     (propertize
                       (org-element-property :title mbo)
                       &#39;face &#39;org-level-2)
                     (propertize
                       &amp;quot; &amp;gt; &amp;quot;
                       &#39;face &#39;consult-separator)
                     (propertize
                       (org-element-property :title task)
                       &#39;face &#39;org-level-3)
                     )
                   (org-element-property :contents-end task))))
             jf/work/org-map-entries-mbo-task-filter))
          (task
            (completing-read
              &amp;quot;Task: &amp;quot; incomplete-mbo-tasks nil t)))
    ;; The contents-end of the task is the begining of the line that
    ;; contains the next heading.  Which the capture process for a
    ;; &amp;quot;plain&amp;quot; item then interprets as &amp;quot;add an item to the current
    ;; heading&amp;quot;.  Not ideal, so move point backwards one character.
    (goto-char
      (1- (alist-get task incomplete-mbo-tasks nil nil #&#39;string=)))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The inline comments reflect a problem I encountered and how I solved it.&lt;/p&gt;
&lt;h3 id=&#34;junk-drawer&#34;&gt;Junk Drawer&lt;/h3&gt;
&lt;p&gt;In reviewing my notes, I found that some entries did not map to tasks.  I &lt;em&gt;could&lt;/em&gt;
make them a task, but they were working notes.  So I decided to add a new level
3 headline: “Engineering Journal”.  And tagged it with &lt;code&gt;journals&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The following capture template mimics the &lt;kbd&gt;J&lt;/kbd&gt; template (&lt;span&gt;example given&lt;/span&gt; (&lt;abbr title=&#34;example given&#34;&gt;e.g.&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “example given”&#34; title=&#34;Other site-wide references of “example given”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EG&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
, append to
a task):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(add-to-list &#39;org-capture-templates
  &#39;(&amp;quot;e&amp;quot; &amp;quot;Engineering Journal entry for MBO&amp;quot;
     plain (file+function
             jf/work/filename-for-mbos
             jf/work/position-in-mbo-journal-entry)
     &amp;quot;%T :: %?&amp;quot;
     :empty-lines-before 1
     :empty-lines-after 1
     :clock-in t
     :clock-resume t))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the function to perform the capture leverages is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/work/position-in-mbo-journal-entry ()
  &amp;quot;Position point just before the selected journal.

Included to allow the re-use of logic for different 3rd level tasks.&amp;quot;
  (let ((jf/work/org-map-entries-mbo-task-filter
          &amp;quot;+LEVEL=3+mbos+tasks+journals&amp;quot;))
    (jf/work/position-at-end-of-mbo-task-entity)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I chose to separate the tasks and journal, in part to reduce the selection
process.  However, I might collapse these two.&lt;/p&gt;
&lt;h2 id=&#34;applying-to-the-personal&#34;&gt;Applying to the Personal&lt;/h2&gt;
&lt;p&gt;I don’t envision supplanting my personal &lt;kbd&gt;j&lt;/kbd&gt; and &lt;kbd&gt;J&lt;/kbd&gt; capture
templates with the more detailed work templates.  However, I’m going to hold
space on how I might use those work steps.  Maybe they can help me accomplish
personal goals?  Or even set them?&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Adding Color and Style to HTML Elements in Emacs&#39;s SHR/EWW</title>
      <link>https://takeonrules.com/2024/12/28/adding-color-and-style-to-html-elements-in-emacss-shreww/</link>
      <pubDate>Sat, 28 Dec 2024 09:44:29 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2024/12/28/adding-color-and-style-to-html-elements-in-emacss-shreww/</guid>
        <category>emacs</category>
        <category>programming</category>
      <description>
        &lt;p&gt;In 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2024/12/18/adding-html5-display-block-elements-to-emacs-shr-and-eww-tag-rendering/&#34;&gt;Adding HTML5 Display Block Elements to Emacs’ SHR (and EWW) Tag Rendering&lt;/a&gt;&lt;/cite&gt; I
wrote about handling additional &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/HTML&#34;&gt;Hypertext Markup Language&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Hypertext Markup Language&#34;&gt;HTML&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Hypertext Markup Language”&#34; title=&#34;Other site-wide references of “Hypertext Markup Language”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-HTML&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 in &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Eww_(web_browser)&#34;&gt;Emacs Web Wowser&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Emacs Web Wowser&#34;&gt;EWW&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs Web Wowser”&#34; title=&#34;Other site-wide references of “Emacs Web Wowser”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EMACS-WEB-WOWSER&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
.&lt;/p&gt;
&lt;p&gt;&lt;time datetime=&#34;2024-12-27&#34; title=&#34;2024-12-27&#34;&gt;Yesterday&lt;/time&gt; I spent some time adding colors to a few elements.  For this I wrote a
macro that did two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Defined a face for the tag&lt;/li&gt;
&lt;li&gt;Add advice around the tag function&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;jf/shr-facify&lt;/code&gt; macro defined below does the heavy lifting.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/8b884404cc47aaf37dc6f9290c1f97c49a3b85eb/emacs.d/init.el#L7903-L7924&#34;&gt;Github for my code that applies the face to an HTML tag&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defmacro jf/shr-facify (tag)
  &amp;quot;Create and apply the face to the given TAG.&amp;quot;
  (let ((face
          (intern (concat &amp;quot;shr-&amp;quot; tag)))
         (docstring-face
          (format &amp;quot;Face for &amp;lt;%s&amp;gt; elements.&amp;quot; tag)))
  `(progn
     (defface ,face
       &#39;((default :inherit shr-text))
       ,docstring-face)
     (advice-add (intern (concat &amp;quot;shr-tag-&amp;quot; ,tag))
       :around
       (lambda (advised-function func &amp;amp;rest args)
         (let ((start (point)))
           (apply advised-function func args)
           (shr-add-font start (point) (intern (concat &amp;quot;shr-&amp;quot; ,tag)))))))))

(jf/shr-facify &amp;quot;blockquote&amp;quot;)
(jf/shr-facify &amp;quot;aside&amp;quot;)
(jf/shr-facify &amp;quot;cite&amp;quot;)
(jf/shr-facify &amp;quot;dfn&amp;quot;)
(jf/shr-facify &amp;quot;dt&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In reading the &lt;span&gt;Simple HTML Renderer&lt;/span&gt; (&lt;abbr title=&#34;Simple HTML Renderer&#34;&gt;SHR&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Simple HTML Renderer”&#34; title=&#34;Other site-wide references of “Simple HTML Renderer”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-SIMPLE-HTML-RENDERER&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 code, I found that when &lt;abbr title=&#34;Simple HTML Renderer&#34;&gt;SHR&lt;/abbr&gt;
 encounters a node (&lt;span&gt;example given&lt;/span&gt; (&lt;abbr title=&#34;example given&#34;&gt;e.g.&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “example given”&#34; title=&#34;Other site-wide references of “example given”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EG&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
, &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;), it
checks if there’s a defined &lt;abbr title=&#34;Simple HTML Renderer&#34;&gt;SHR&lt;/abbr&gt;
 tag function for that name (&lt;abbr title=&#34;example given&#34;&gt;e.g.&lt;/abbr&gt;
, &lt;code&gt;shr-tag-p&lt;/code&gt;) and
calls it.  Otherwise it falls back to a generic function.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;jf/shr-facify&lt;/code&gt; macro, I define a face for the tag but leave it mostly
“empty”.&lt;/p&gt;
&lt;p&gt;I then customize the face as part of &lt;code&gt;ef-themes-with-colors&lt;/code&gt;.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See &lt;a href=&#34;https://protesilaos.com/emacs/ef-themes&#34;&gt;Ef (εὖ) themes for GNU Emacs by Protesilaos Stavrou&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
 Below is that
function.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/8b884404cc47aaf37dc6f9290c1f97c49a3b85eb/emacs.d/init.el#L1383-L1476&#34;&gt;Github for my code on changing colors in ef-themes&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/theme-custom-faces ()
    &amp;quot;Set the various custom faces.&amp;quot;
    (ef-themes-with-colors
      (custom-set-faces
        `(shr-blockquote
           ((,c :foreground ,docstring)))
        `(shr-dfn
           ((,c :slant italic :foreground ,keyword)))
        `(shr-dt
           ((,c :slant italic :foreground ,keyword)))
        `(shr-cite
           ((,c :underline nil :slant italic :bold t :foreground ,mail-cite-0)))
        `(shr-aside
           ((,c :foreground ,comment :background ,bg-alt))))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Last, I register &lt;code&gt;jf/theme-custom-faces&lt;/code&gt; with the &lt;code&gt;after-enable-theme-hook&lt;/code&gt;.  This
means as I change themes, &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Emacs&#34;&gt;Emacs&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs”&#34; title=&#34;Other site-wide references of “Emacs”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EMACS&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 will update the font face colors according to
the themes named colors.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(add-hook &#39;after-enable-theme-hook #&#39;jf/theme-custom-faces)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;tags-with-custom-faces&#34;&gt;Tags with Custom Faces&lt;/h2&gt;
&lt;p&gt;One thing I love about Ef themes and their sibling &lt;a href=&#34;https://protesilaos.com/emacs/modus-themes&#34;&gt;Modus Themes&lt;/a&gt; is that
Protesilaos (&lt;span&gt;Also Known As&lt;/span&gt; (&lt;abbr title=&#34;Also Known As&#34;&gt;aka&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Also Known As”&#34; title=&#34;Other site-wide references of “Also Known As”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-AKA&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 Prot) has mapped colors to semantic concepts.  I have found
this helpful as I can map additional concepts to those semantics.&lt;/p&gt;
&lt;p&gt;In the case of &lt;abbr title=&#34;Hypertext Markup Language&#34;&gt;HTML&lt;/abbr&gt;
 elements, its somewhat imprecise, but it does create a
conceptual consistency.&lt;/p&gt;
&lt;p&gt;For the &lt;code&gt;blockquote&lt;/code&gt; tag, I wanted a gentle indicator.  I mapped this semantically
to the &lt;code&gt;docstring&lt;/code&gt; foreground color defined in Ef Themes.&lt;/p&gt;
&lt;p&gt;For the &lt;code&gt;aside&lt;/code&gt;, it is very much like a &lt;code&gt;comment&lt;/code&gt;.  For the moment, I’m also adding
a background color to it.  I’m not set on that color, but include it as an
example.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;cite&lt;/code&gt; and &lt;code&gt;dfn&lt;/code&gt; tags are often italicized in the default stylesheet; I wanted
to carry that forward but also gently differentiate.  The &lt;code&gt;cite&lt;/code&gt; uses the
&lt;code&gt;mail-cite-0&lt;/code&gt; color.  And the &lt;code&gt;dfn&lt;/code&gt; applies the &lt;code&gt;keyword&lt;/code&gt; color.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; I’m mixing the semantic categories, but it works out alright.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;p&gt;Related to &lt;code&gt;dfn&lt;/code&gt; is the &lt;code&gt;dt&lt;/code&gt;, both being a definition.  Hence I use the &lt;code&gt;keyword&lt;/code&gt;
color.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I’m loving using &lt;abbr title=&#34;Emacs Web Wowser&#34;&gt;EWW&lt;/abbr&gt;
 as my primary browser.  And as a bonus, changes I make to
&lt;abbr title=&#34;Emacs Web Wowser&#34;&gt;EWW&lt;/abbr&gt;
 rendering also ripple into my &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/RSS&#34;&gt;Rich Site Summary&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Rich Site Summary&#34;&gt;RSS&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Rich Site Summary”&#34; title=&#34;Other site-wide references of “Rich Site Summary”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-RSS&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 reading via the &lt;span&gt;&lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;elfeed package&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “elfeed package”&#34; title=&#34;Other site-wide references of “elfeed package”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ELFEED&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
.  This
little adjustments help convey the semantic intention of the author(s).&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Adding HTML5 Display Block Elements to Emacs’ SHR (and EWW) Tag Rendering</title>
      <link>https://takeonrules.com/2024/12/18/adding-html5-display-block-elements-to-emacs-shr-and-eww-tag-rendering/</link>
      <pubDate>Wed, 18 Dec 2024 09:28:38 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2024/12/18/adding-html5-display-block-elements-to-emacs-shr-and-eww-tag-rendering/</guid>
        <category>emacs</category>
        <category>programming</category>
      <description>
        &lt;p&gt;&lt;time datetime=&#34;2024-12-18&#34; title=&#34;2024-12-18&#34;&gt;This morning&lt;/time&gt; I made two quality of life adjustments to my &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Eww_(web_browser)&#34;&gt;Emacs Web Wowser&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Emacs Web Wowser&#34;&gt;EWW&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs Web Wowser”&#34; title=&#34;Other site-wide references of “Emacs Web Wowser”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EMACS-WEB-WOWSER&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)

viewing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add handling for HTML5 &lt;code&gt;display:block&lt;/code&gt; elements: &lt;code&gt;article&lt;/code&gt;, &lt;code&gt;aside&lt;/code&gt;, &lt;code&gt;footer&lt;/code&gt;, &lt;code&gt;header&lt;/code&gt;,
&lt;code&gt;nav&lt;/code&gt;, &lt;code&gt;section&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;rel=home&lt;/code&gt; and &lt;code&gt;rel=up&lt;/code&gt; navigation key bindings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Without the handling adjustment, the aforementioned HTML5 elements render
inline; meaning there’s no surrounding line break and the text rendering can
look a bit off.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;rel=home&lt;/code&gt; and &lt;code&gt;rel=up&lt;/code&gt; are analogous to the &lt;code&gt;next&lt;/code&gt; and &lt;code&gt;prev&lt;/code&gt; rel
attributes.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel#next&#34;&gt;See next rel attribute on MDN Web Docs&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
 &lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel#prev&#34;&gt;See prev rel attribute on MDN Web Docs&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
 The &lt;code&gt;up&lt;/code&gt; and &lt;code&gt;home&lt;/code&gt; are not documented in &lt;span&gt;&lt;a href=&#34;https://developer.mozilla.org/&#34;&gt;Mozilla Developer Network Web Docs&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Mozilla Developer Network Web Docs&#34;&gt;MDN Web Docs&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Mozilla Developer Network Web Docs”&#34; title=&#34;Other site-wide references of “Mozilla Developer Network Web Docs”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-MDN&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 but &lt;code&gt;up&lt;/code&gt; is
documented on &lt;a href=&#34;https://www.w3.org&#34;&gt;w3.org&lt;/a&gt;.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; &lt;a href=&#34;https://www.w3.org/TR/2011/WD-html5-20110113/links.html#link-type-up&#34;&gt;See up rel attribute docs on W3.org&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
 And &lt;code&gt;rel=home&lt;/code&gt; is regarded as good &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Search_engine_optimization&#34;&gt;Search Engine Optimization&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Search Engine Optimization&#34;&gt;SEO&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Search Engine Optimization”&#34; title=&#34;Other site-wide references of “Search Engine Optimization”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-SEO&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 (and helpful for
accessibility).&lt;/p&gt;
&lt;p&gt;When viewing a page in &lt;abbr title=&#34;Emacs Web Wowser&#34;&gt;EWW&lt;/abbr&gt;
, I can type the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;h&lt;/kbd&gt; to visit &lt;code&gt;rel=home&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;u&lt;/kbd&gt; to visit &lt;code&gt;rel=up&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;p&lt;/kbd&gt; to visit &lt;code&gt;rel=prev&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;n&lt;/kbd&gt; to visit &lt;code&gt;rel=next&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Which I find to be some super convenient hot keys.  Now for some code…!&lt;/p&gt;
&lt;h2 id=&#34;emacs-lisp-code&#34;&gt;Emacs Lisp Code&lt;/h2&gt;

&lt;aside  role=&#34;note&#34; class=&#34;margin&#34;&gt;

&lt;p&gt;&lt;small&gt;The code is refined to convey local context.  See the unrefined &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/c525d68140f2773aa94e03699965ca8e3628da66/emacs.d/init.el#L7800-L7831&#34;&gt;SHR/EWW
adjustments on Github&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;
&lt;/aside&gt;

&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(use-package eww
  :straight (:type built-in)
  (defmacro shr-display-block (tag)
    &amp;quot;Register TAG a paragraph (in CSS parlance \&amp;quot;display:block;\&amp;quot;).

See https://developer.mozilla.org/en-US/docs/Glossary/Block-level_content&amp;quot;
    (let ((fname
           (intern (format &amp;quot;shr-tag-%s&amp;quot; tag)))
          (docstring
           (format &amp;quot;Render \&amp;quot;%s\&amp;quot; tag as paragraph.&amp;quot; tag)))
      `(defun ,fname (dom)
         ,docstring
         (shr-ensure-paragraph)
         (shr-generic dom)
         (shr-ensure-paragraph))))

  (shr-display-block &amp;quot;article&amp;quot;)
  (shr-display-block &amp;quot;aside&amp;quot;)
  (shr-display-block &amp;quot;footer&amp;quot;)
  (shr-display-block &amp;quot;header&amp;quot;)
  (shr-display-block &amp;quot;nav&amp;quot;)
  (shr-display-block &amp;quot;section&amp;quot;)

  ;; The `shr-map&#39; is being applied after `eww-mode-map&#39;; which means that
  ;; attempts to register \&amp;quot;u\&amp;quot; for `eww-up-url&#39; don&#39;t work.
  (unbind-key &amp;quot;u&amp;quot; shr-map)
  :bind (:map eww-mode-map
              (&amp;quot;u&amp;quot; . eww-up-url)
              (&amp;quot;h&amp;quot; . eww-home-url)))
&lt;/code&gt;&lt;/pre&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Extending Built-In Emacs Bookmark Package</title>
      <link>https://takeonrules.com/2024/12/17/extending-built-in-emacs-bookmark-package/</link>
      <pubDate>Tue, 17 Dec 2024 08:04:39 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2024/12/17/extending-built-in-emacs-bookmark-package/</guid>
        <category>emacs</category>
        <category>programming</category>
      <description>
        &lt;p&gt;&lt;time datetime=&#34;2024-12-03&#34; title=&#34;2024-12-03&#34;&gt;Earlier in December&lt;/time&gt; I wrote 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2024/12/03/monkey-patch-fix-for-bookmark-for-emacs-30/&#34;&gt;Monkey Patch Fix for Bookmark&amp;#43; for Emacs 30&lt;/a&gt;&lt;/cite&gt;.  Since
then, I’ve encountered problems with corrupted bookmarks.  And if I undo the
patch, I encounter similar problems.&lt;/p&gt;
&lt;p&gt;As I’m using Emacs 30, which is not yet released, I can expect bugs.  However, I
want to stop encountering corrupted bookmarks.  So I disabled the Bookmarks+
package.  But that left me without some key functionality: creating an Emacs
bookmark of the foreground tab of a browser such as Firefox, Safari, or Chrome.&lt;/p&gt;
&lt;p&gt;I did some digging in &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Eww_(web_browser)&#34;&gt;Emacs Web Wowser&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Emacs Web Wowser&#34;&gt;EWW&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs Web Wowser”&#34; title=&#34;Other site-wide references of “Emacs Web Wowser”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EMACS-WEB-WOWSER&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
, as that package can create Bookmarks and indicate the
type as EWW.&lt;/p&gt;
&lt;h2 id=&#34;emacs-functions-for-extending-eww&#34;&gt;Emacs Functions for Extending EWW&lt;/h2&gt;
&lt;p&gt;There are three functions, one for each of the browsers I might use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;jf/menu--bookmark-chrome&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jf/menu--bookmark-firefox&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jf/menu--bookmark-safari&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of those functions use the &lt;a href=&#34;https://github.com/xuchunyang/grab-mac-link.el/tree/5fdb03bf57bc4a530374b896e0f8b5139dc794e3&#34;&gt;Grab Mac Link package&lt;/a&gt; to interact with the
browsers.  Each then calls &lt;code&gt;jf/bookmark-url&lt;/code&gt; which sets some variables,
importantly the &lt;code&gt;bookmark-make-record-function&lt;/code&gt;; which needs to return a list with
the &lt;code&gt;car&lt;/code&gt; as the title and &lt;code&gt;cdr&lt;/code&gt; is a property list with the keys &lt;code&gt;location&lt;/code&gt; and
&lt;code&gt;handler&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Below is my “good enough” solution to my desired functionality, with &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/898db7fbae93c7bf34646c043ce3a85d3009158a/emacs.d/init.el#L7232-L7304&#34;&gt;source code
available on Github&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(use-package bookmark
  :straight (:type built-in)
  :config
  ;; On each machine I use, I have different bookmarks, yet they all
  ;; point to the same location.
  (setq bookmark-default-file &amp;quot;~/emacs-bookmarks.el&amp;quot;)

  ;; Save the `bookmark-file&#39; each time I modify a bookmark.
  (setq bookmark-save-flag 1)

  (defvar jf/bookmark-make-record-function/browse-url/title &amp;quot;&amp;quot;
    &amp;quot;Used for capturing the title from the browser current tab.&amp;quot;)

  (defvar jf/bookmark-make-record-function/browse-url/url &amp;quot;&amp;quot;
    &amp;quot;Used for capturing the url from the browser current tab.&amp;quot;)

  (defun jf/bookmark-url (url title)
    &amp;quot;Create a `browse-url&#39; bookmark for URL and TITLE.&amp;quot;
    (let* ((jf/bookmark-make-record-function/browse-url/title
            title)
           (jf/bookmark-make-record-function/browse-url/url
            url)
           (bookmark-make-record-function
            #&#39;jf/bookmark-make-record-function/browse-url))
      (bookmark-set-internal nil title nil)))

  (defun jf/bookmark-make-record-function/browse-url()
    &amp;quot;Function to build the bookmark structure.&amp;quot;
    `(,jf/bookmark-make-record-function/browse-url/title
      (location . ,jf/bookmark-make-record-function/browse-url/url)
      (handler . jf/browse-url-bookmark-jump)))

  (defun jf/browse-url-bookmark-jump (bookmark)
    &amp;quot;Default bookmark handler for browser.&amp;quot;
    (browse-url (bookmark-prop-get bookmark &#39;location)))

  ;; In the bookmark list page, identify the type as BROWSE for those
  ;; captured by `jf/bookmark-url&#39;.
  (put &#39;jf/browse-url-bookmark-jump &#39;bookmark-handler-type &amp;quot;BROWSE&amp;quot;)

  (defun jf/menu--bookmark-safari ()
    &amp;quot;Create `bookmark+&#39; for current Safari page.&amp;quot;
    (interactive)
    (require &#39;grab-mac-link)
    (let* ((url-and-title
            (grab-mac-link-safari-1))
           (title
            (read-string
             (concat &amp;quot;URL: &amp;quot; (car url-and-title) &amp;quot;\nTitle: &amp;quot;)
             (cadr url-and-title))))
      (jf/bookmark-url (car url-and-title) title)))

  (defun jf/menu--bookmark-firefox ()
    &amp;quot;Create `bookmark+&#39; for current Firefox page.&amp;quot;
    (interactive)
    (require &#39;grab-mac-link)
    (let* ((url-and-title
            (grab-mac-link-firefox-1))
           (title
            (read-string
             (concat &amp;quot;URL: &amp;quot; (car url-and-title) &amp;quot;\nTitle: &amp;quot;)
             (cadr url-and-title))))
      (jf/bookmark-url (car url-and-title) title)))

  (defun jf/menu--bookmark-chrome ()
    &amp;quot;Create `bookmark+&#39; for current Chrome page.&amp;quot;
    (interactive)
    (require &#39;grab-mac-link)
    (let* ((url-and-title
            (grab-mac-link-chrome-1))
           (title
            (read-string
             (concat &amp;quot;URL: &amp;quot; (car url-and-title) &amp;quot;\nTitle: &amp;quot;)
             (cadr url-and-title))))
      (jf/bookmark-url (car url-and-title) title))))
&lt;/code&gt;&lt;/pre&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Add Work Link Type to Org-Mode</title>
      <link>https://takeonrules.com/2024/12/07/add-work-link-type-to-org-mode/</link>
      <pubDate>Sat, 07 Dec 2024 15:10:02 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2024/12/07/add-work-link-type-to-org-mode/</guid>
        <category>emacs</category>
        <category>org-mode</category>
        <category>programming</category>
      <description>
        &lt;p&gt;&lt;time datetime=&#34;2024-12-06&#34; title=&#34;2024-12-06&#34;&gt;Yesterday&lt;/time&gt;, I added a &lt;code&gt;work&lt;/code&gt; link type to &lt;span&gt;&lt;a href=&#34;https://orgmode.org/&#34;&gt;Org-Mode&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Mode”&#34; title=&#34;Other site-wide references of “Org-Mode”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-MODE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; For those Samverans reading along, I thought about naming this link type “wortem”, in honor of the placeholder name used during &lt;span&gt;&lt;a href=&#34;https://github.com/duraspace/pcdm/wiki&#34;&gt;Portland Common Data Model&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Portland Common Data Model&#34;&gt;PCDM&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Portland Common Data Model”&#34; title=&#34;Other site-wide references of “Portland Common Data Model”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-PORTLAND-COMMON-DATA-MODEL&#34;&gt;📖&lt;/a&gt;&lt;/small&gt;)
discussions.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
 My original name for the
link type was &lt;code&gt;cite&lt;/code&gt;; however that is a link type in &lt;a href=&#34;https://blog.tecosaur.com/tmio/2021-07-31-citations.html#fn.3&#34;&gt;Org Citation ecosystem&lt;/a&gt;. I
did not want to collide with another named link type; in case that I start
writing academic papers and use that citation process.&lt;/p&gt;
&lt;h2 id=&#34;background&#34;&gt;Background&lt;/h2&gt;
&lt;p&gt;As I’ve written about lately: 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2024/12/04/refining-my-quotation-capture-process/&#34;&gt;Refining My Quotation Capture Process&lt;/a&gt;&lt;/cite&gt; and

&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2024/12/01/re-wiring-my-epigraphs-functionality-to-leverage-my-bibliography-file/&#34;&gt;Re-Wiring My Epigraphs Functionality to Leverage My Bibliography File&lt;/a&gt;&lt;/cite&gt;.&lt;/p&gt;
&lt;p&gt;In summary, I have a single document that contains quotes and their associated
person or work.  I’ve written several capture templates for creating people,
works, and attributed quotes.&lt;/p&gt;
&lt;p&gt;Let’s look again at a quote that &lt;em&gt;belongs to&lt;/em&gt; a &lt;code&gt;work&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;** The Annals of Imperial Rome :books:
,:PROPERTIES:
,:AUTHOR: Tacitus
,:CUSTOM_ID: 73A11F00-F727-4FDF-9FF1-27EBB59CF139
,:END:

,#+NAME: 20230121T093858
,#+begin_quote
The more corrupt the state, the more numerous the laws.
,#+end_quote
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With my prior functionality, I could link to the named quote.  What I wanted was
to link to the work.  I could link via &lt;span&gt;&lt;a href=&#34;https://protesilaos.com/emacs/denote&#34;&gt;Denote&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Denote”&#34; title=&#34;Other site-wide references of “Denote”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-DENOTE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 or to the Headline.  However,
before I chose to re-use another link type I thought about what I wanted.&lt;/p&gt;
&lt;h3 id=&#34;rudimentary-requirements-gathering&#34;&gt;Rudimentary Requirements Gathering&lt;/h3&gt;
&lt;p&gt;First, I make extensive use of the &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/cite&#34;&gt;CITE-tag&lt;/a&gt; in my blog.  Such that I have an
&lt;span&gt;Org-Mode&lt;/span&gt;
 macro for &lt;code&gt;cite&lt;/code&gt;.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/3e196bb76abd7d182c1837d2b4c2e3ee0889774c/emacs.d/init.el#L2371-L2372&#34;&gt;my cite macro on Github&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
 And the target for most of my &lt;span&gt;Org-Mode&lt;/span&gt;
 is
“publishing” is my blog.&lt;/p&gt;
&lt;p&gt;This defined a functional need:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-gherkin&#34;&gt;Given that I am linking to a work,
When I export that work to HTML,
Then that work&#39;s title should be in a =CITE= tag.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also wanted a means of quickly selecting works that I might cite.  There were
a couple of options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Write a custom function to insert a Denote or Headline link.&lt;/li&gt;
&lt;li&gt;Create a custom link type.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Were I to write a custom function, I would then want to extend/modify the
associated link export function.  If I created a new link type, I wouldn’t be
hacking an existing function but could instead write a new one.&lt;/p&gt;
&lt;p&gt;Re-using Denote would allow me to see backlinks.  However, a simple &lt;span&gt;&lt;a href=&#34;https://github.com/BurntSushi/ripgrep&#34;&gt;Ripgrep&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Ripgrep”&#34; title=&#34;Other site-wide references of “Ripgrep”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-RIPGREP&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;

would do something similar for a custom link.&lt;/p&gt;
&lt;p&gt;Another “nice to have” functionality is rendering, in &lt;span&gt;Org-Mode&lt;/span&gt;
, the link with
similar font style as that of browsers (&lt;span&gt;example given&lt;/span&gt; (&lt;abbr title=&#34;example given&#34;&gt;e.g.&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “example given”&#34; title=&#34;Other site-wide references of “example given”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EG&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
, italicized).  That is very simple
with custom link types.&lt;/p&gt;
&lt;h2 id=&#34;emacs-code&#34;&gt;Emacs Code&lt;/h2&gt;
&lt;p&gt;Here’s my configuration for the a &lt;code&gt;work&lt;/code&gt; link.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/3e196bb76abd7d182c1837d2b4c2e3ee0889774c/emacs.d/init.el#L5243-L5248&#34;&gt;my configuration on Github&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(org-link-set-parameters &amp;quot;work&amp;quot;
    ;; TODO: Allow link to specify to include author.
    :follow #&#39;jf/org-link-ol-follow/work
    :complete #&#39;jf/org-link-ol-complete/work
    :export #&#39;jf/org-link-ol-export/work
    :face #&#39;jf/org-faces-work)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ve defined four of the properties:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;:follow&lt;/dt&gt;
&lt;dd&gt;when I click on the link, jump to the work.&lt;/dd&gt;
&lt;dt&gt;:complete&lt;/dt&gt;
&lt;dd&gt;when I &lt;code&gt;M-x org-insert-link&lt;/code&gt; this function fires to find the work.&lt;/dd&gt;
&lt;dt&gt;:export&lt;/dt&gt;
&lt;dd&gt;when I export the document to another format, this function
determines what happens.&lt;/dd&gt;
&lt;dt&gt;:face&lt;/dt&gt;
&lt;dd&gt;italicized and colored to look visually different.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;But have chosen to not implement the &lt;code&gt;:store&lt;/code&gt; option.  Why?  When I’m citing
something, I’m unlikely to be on the Work node but instead in some other
document.&lt;/p&gt;
&lt;h3 id=&#34;the-follow-function&#34;&gt;The &lt;code&gt;:follow&lt;/code&gt; Function&lt;/h3&gt;
&lt;p&gt;Here’s the quick and dirty function to find the Work in my bibliography.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/3e196bb76abd7d182c1837d2b4c2e3ee0889774c/emacs.d/init.el#L5250-L5262&#34;&gt;jf/org-link-ol-follow/work on Github&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
 I’m
using a regular expression to quickly find the work, then positioning point to
the start of the headline.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/org-link-ol-follow/work (name)
    &amp;quot;Follow the NAME to the work.&amp;quot;
    (let* ((file
             jf/filename/bibliography)
            (case-fold-search
              t))
      (find-file file)
      (goto-char (point-min))
      (let ((case-fold-search t))
        (search-forward-regexp
          (format &amp;quot;^:custom_id:[[:space:]]+%s$&amp;quot; name))
        (call-interactively #&#39;org-previous-visible-heading))
      (pulsar--pulse)))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;the-complete-function&#34;&gt;The &lt;code&gt;:complete&lt;/code&gt; Function&lt;/h3&gt;
&lt;p&gt;Here’s the function that reads my bibliography and assembles a list of works.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/3e196bb76abd7d182c1837d2b4c2e3ee0889774c/emacs.d/init.el#L5264-L5296&#34;&gt;jf/org-link-ol-complete/work on Github&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;

From that list I choose a work and insert the link.  I add the title to the kill
ring so I can easily add that title as the description for the link.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/org-link-ol-complete/work ()
    &amp;quot;Prompt for a work from my bibliography&amp;quot;
    (interactive)
    (let* ((buffer
             (find-file-noselect jf/filename/bibliography))
            (works
              (save-excursion
                (with-current-buffer buffer
                  ;; With the given tag, find all associated headlines
                  ;; that match that tag.
                  (org-map-entries
                    (lambda ()
                      (let* ((headline
                               (org-element-at-point))
                              (title
                                (org-element-property :title headline))
                              (subtitle
                                (org-entry-get headline &amp;quot;SUBTITLE&amp;quot;)))
                        (cons
                          (format &amp;quot;%s&amp;quot;
                            (if subtitle
                              (concat title &amp;quot;: &amp;quot; subtitle)
                              title))
                          (org-entry-get headline &amp;quot;CUSTOM_ID&amp;quot;))))
                    &amp;quot;+LEVEL=2+!people&amp;quot; &#39;file))))
            (work
              (completing-read &amp;quot;Citable: &amp;quot; works nil t)))
      (when-let ((id
                   (alist-get work works nil nil #&#39;string=)))
        (progn
          (message &amp;quot;Added %S to the kill ring&amp;quot; work)
          (kill-new work)
          (format &amp;quot;work:%s&amp;quot; id)))))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;the-export-function&#34;&gt;The &lt;code&gt;:export&lt;/code&gt; Function&lt;/h3&gt;
&lt;p&gt;Here’s the function for exporting the link.  I handle &lt;code&gt;html&lt;/code&gt;, &lt;code&gt;md&lt;/code&gt;, &lt;code&gt;latex&lt;/code&gt;, and a
general fallback.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/3e196bb76abd7d182c1837d2b4c2e3ee0889774c/emacs.d/init.el#L5298-L5344&#34;&gt;jf/org-link-ol-export/work on Github&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/org-link-ol-export/work (link description format protocol)
    &amp;quot;Export the text of the LINK work in the corresponding FORMAT.

We ignore the DESCRIPTION and probably the PROTOCOL.&amp;quot;
    (let ((buffer
            (find-file-noselect jf/filename/bibliography)))
      (save-excursion
        (with-current-buffer buffer
          ;; First we find the corresponding work and possible URL.
          (when-let* ((work
                        (car
                          (org-element-map
                            (org-element-parse-buffer)
                            &#39;(headline)
                            (lambda (el)
                              ;; Skip un-named blocks as we can’t link to
                              ;; them.
                              (when (string=
                                      (org-entry-get el &amp;quot;CUSTOM_ID&amp;quot;)
                                      link)
                                (let ((title
                                        (car
                                        (org-element-property :title el))))
                                  (list
                                    :title
                                    (if-let ((subtitle
                                               (org-entry-get el &amp;quot;SUBTITLE&amp;quot;)))
                                      (format &amp;quot;%s: %s&amp;quot; title subtitle)
                                      title)
                                    :url
                                    (org-entry-get el &amp;quot;ROAM_REFS&amp;quot;)))))))))
            ;; Then we create the corresponding format.
            (cond
              ((or (eq format &#39;html) (eq format &#39;md))
                (format &amp;quot;&amp;lt;cite data-id=\&amp;quot;%s\&amp;quot;&amp;gt;%s&amp;lt;/cite&amp;gt;&amp;quot;
                  link
                  (if-let ((url
                             (plist-get work :url)))
                    (format &amp;quot;&amp;lt;a href=\&amp;quot;%s\&amp;quot;&amp;gt;%s&amp;lt;/a&amp;gt;&amp;quot;
                      url (plist-get work :title))
                  (plist-get work :title))))
              ((eq format &#39;latex)
                (format &amp;quot;\\textit{%s}&amp;quot;
                  (plist-get work :title)))
              (t
                (format &amp;quot;“%s”&amp;quot;
                  (plist-get work :title)))))))))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;the-face-setting&#34;&gt;The &lt;code&gt;:face&lt;/code&gt; Setting&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;work&lt;/code&gt; face inherits from link.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defface jf/org-faces-work &#39;((default :inherit link))
    &amp;quot;Face used to style `org-mode&#39; work links in the buffer.&amp;quot;
    :group &#39;denote-faces
    :package-version &#39;(denote . &amp;quot;0.5.0&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I use &lt;code&gt;ef-themes-with-colors&lt;/code&gt; to further customize the colors, helping create
visual differentiation between other links:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;`(jf/org-faces-work
  ((,c :underline nil :slant italic :bold t :foreground ,mail-cite-0)))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;continued-hacking-on-links&#34;&gt;Continued Hacking on Links&lt;/h2&gt;
&lt;p&gt;A deeper read of this work, begins to highlight how I’m using the &lt;span&gt;Org-Mode&lt;/span&gt;

ecosystem to introduce &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/HTML&#34;&gt;Hypertext Markup Language&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Hypertext Markup Language&#34;&gt;HTML&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Hypertext Markup Language”&#34; title=&#34;Other site-wide references of “Hypertext Markup Language”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-HTML&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 5 elements.  The &lt;code&gt;abbr&lt;/code&gt; and &lt;code&gt;abbr-plural&lt;/code&gt; map directly
to the &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/abbr&#34;&gt;ABBR-tag&lt;/a&gt;.  The &lt;code&gt;date&lt;/code&gt; link maps (although incompletely) to the &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time&#34;&gt;TIME-tag&lt;/a&gt;. My
&lt;code&gt;epigraph&lt;/code&gt; link is a narrow usage of the &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote&#34;&gt;BLOCKQUOTE-tag&lt;/a&gt;.  And my new &lt;code&gt;work&lt;/code&gt; link is
an approximation of the &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/cite&#34;&gt;CITE-tag&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This also helps keep me out of mucking around with existing export functions.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Auto-Exporting My Book &#34;Shopping List&#34; as Part of Org Capture</title>
      <link>https://takeonrules.com/2024/12/04/auto-exporting-my-book-shopping-list-as-part-of-org-capture/</link>
      <pubDate>Wed, 04 Dec 2024 17:50:09 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2024/12/04/auto-exporting-my-book-shopping-list-as-part-of-org-capture/</guid>
        <category>emacs</category>
        <category>org-mode</category>
        <category>programming</category>
        <category>reading</category>
      <description>
        
&lt;aside  role=&#34;note&#34; class=&#34;margin&#34;&gt;

&lt;p&gt;&lt;small&gt;I feel like I should create a Series for these posts related to my Bibliography
and Epigraphs.  That would help me find these posts later on.&lt;/small&gt;&lt;/p&gt;
&lt;/aside&gt;

&lt;p&gt;&lt;time datetime=&#34;2024-12-04&#34; title=&#34;2024-12-04&#34;&gt;Today&lt;/time&gt; I extracted a function that will write to my book “shopping list”.  I
wrote about the original function in 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2024/11/27/extending-my-bibliography-for-an-on-the-go-shopping-list/&#34;&gt;Extending My Bibliography for an On The Go “Shopping List”&lt;/a&gt;&lt;/cite&gt;.&lt;/p&gt;
&lt;h2 id=&#34;some-emacs-lisp&#34;&gt;Some Emacs Lisp&lt;/h2&gt;
&lt;p&gt;I now call the &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/df2717f77ff1df89b28814b3f3f111e217c7ef6f/emacs.d/init.el#L4907-L4963&#34;&gt;new function&lt;/a&gt; as part of the finalization of my &lt;span&gt;&lt;a href=&#34;https://orgmode.org/&#34;&gt;Org-Mode&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Mode”&#34; title=&#34;Other site-wide references of “Org-Mode”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-MODE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 template
capture.  I’ve defined &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/df2717f77ff1df89b28814b3f3f111e217c7ef6f/emacs.d/init.el#L3204-L3209&#34;&gt;the “work” capture template&lt;/a&gt; as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(&amp;quot;w&amp;quot; &amp;quot;Work&amp;quot;
 entry
 (file+headline jf/filename/bibliography &amp;quot;Works&amp;quot;)
 &amp;quot;%^{Title} %^g\n:PROPERTIES:\n:CUSTOM_ID: %(org-id-new)\n:AUTHOR: %^{AUTHOR}\n:END:\n%?&amp;quot;
 :jump-to-captured t
 :after-finalize jf/bibliography/export-shopping-list)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The change I made was adding the &lt;code&gt;:after-finalize&lt;/code&gt; property.  This helps keep my
“shopping list” up to date based on what I’m considering.&lt;/p&gt;
&lt;h2 id=&#34;serendipity-and-previous-lifetime--s&#34;&gt;Serendipity and Previous Lifetime(s)&lt;/h2&gt;
&lt;p&gt;As part of my previous work, I would travel to various college towns.
Invariably there would be a wonderful used bookstore.  I miss perusing those
shelves, looking for the esoteric books.&lt;/p&gt;
&lt;p&gt;Jenny and I also used to take day trips to mid-sized cities, but that happens
less and less.  And we always prioritized visiting independent bookstores.&lt;/p&gt;
&lt;p&gt;When we were helping to start &lt;a href=&#34;https://fablesbooks.com/&#34;&gt;Fables Books&lt;/a&gt;, Jenny and I visited numerous
bookstores; looking for inspiration and to see how others were merchandising
their shop.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2019/04/26/im-helping-to-open-fables-bookshop-in-downtown-goshen-indiana/&#34;&gt;I&#39;m Helping to Open Fables Bookshop in Downtown Goshen Indiana&lt;/a&gt;&lt;/cite&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;p&gt;I could order these books online (from great bookshops such as &lt;a href=&#34;https://www.brainlairbooks.com/&#34;&gt;Brain Lair Books&lt;/a&gt;,
&lt;a href=&#34;https://www.lowrysbooks.com/&#34;&gt;Lowry Books&lt;/a&gt;, &lt;a href=&#34;https://www.marcusbooks.com/&#34;&gt;Marcus Books&lt;/a&gt;, and &lt;a href=&#34;https://fablesbooks.com/&#34;&gt;Fables Books&lt;/a&gt;).  Or borrow them from a local
library.&lt;/p&gt;
&lt;p&gt;But I’m holding off on getting these books.  First, I have a large backlog of
books.  But I’m also keen on creating moments of serendipity.&lt;/p&gt;
&lt;p&gt;A few weeks ago I had read a post on The Marginalian that referenced out Albert
Camus’s &lt;cite&gt;Lyrical and Critical Essays&lt;/cite&gt;.  A few days later, at a local
bookstore, I saw “front-facing” a copy of this very book.&lt;/p&gt;
&lt;p&gt;Serendipity!  And I purchased it immediately.&lt;/p&gt;
&lt;p&gt;What I’m feeling, with this “shopping list”, is priming myself for delayed
gratification.  Namely, when I find myself at a book shop, I’ll have a list of
books to investigate.  And in sifting through those shelves, I’m certain I’ll
find other books of interest.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Refining My Quotation Capture Process</title>
      <link>https://takeonrules.com/2024/12/04/refining-my-quotation-capture-process/</link>
      <pubDate>Wed, 04 Dec 2024 13:17:30 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2024/12/04/refining-my-quotation-capture-process/</guid>
        <category>emacs</category>
        <category>org-mode</category>
        <category>programming</category>
      <description>
        &lt;p&gt;In 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2024/11/27/refining-my-personal-bibliography-and-epigraph-process/&#34;&gt;Refining My Personal Bibliography and Epigraph Process&lt;/a&gt;&lt;/cite&gt; I wrote about my
capture template for Quotes.&lt;/p&gt;
&lt;p&gt;Prior to &lt;time datetime=&#34;2024-12-04&#34; title=&#34;2024-12-04&#34;&gt;today&lt;/time&gt; the positioning logic was to go to the &lt;code&gt;:contents-end&lt;/code&gt; of the
chosen headline.  The problem I encountered was that I had additional
sub-headings with writing and reflection…and the capture process dumped the
quote at the end of that sub-heading.  In other words, not where I wanted it.&lt;/p&gt;
&lt;p&gt;I thought for a bit and my options were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Always create a sub-node for quotations within a headline.&lt;/li&gt;
&lt;li&gt;Put the content at the beginning of the headline node.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I chose to pursue the beginning of the headline node.  In part because not all
books will have quotations.  But also because where I’d want to add the headline
was in the same spot as the beginning of the headline node.&lt;/p&gt;
&lt;p&gt;Meaning, I needed to “solve” the beginning of the headline problem.  I
experimented with using &lt;code&gt;:contents-begin&lt;/code&gt; property.  That is always the beginning
of the first line following the headline.&lt;/p&gt;
&lt;p&gt;Which was right at the point where I was storing metadata around the work.
Let’s look at an example.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;** DONE Power of the Powerless, The :books:
#+CLOSED: [2024-12-04 Wed 08:36]
,:PROPERTIES:
,:CUSTOM_ID: 26A608F1-70C2-4E23-9DA0-B2C978D5BB52
,:AUTHOR: Václav Havel
,:ID:       045E3F33-5D5A-49E6-A534-2EDAE3F74062
,:END:
,:LOGBOOK:
- State &amp;quot;DONE&amp;quot;       from &amp;quot;STARTED&amp;quot;    [2024-12-04 Wed 08:36]
#+CLOCK: [2024-11-28 Thu 08:45]--[2024-11-28 Thu 09:00] =&amp;gt;  0:15
- State &amp;quot;STARTED&amp;quot;    from              [2024-11-27 Wed 10:42]
,:END:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;:contents-begin&lt;/code&gt; would be the line starting with &lt;code&gt;#+CLOSED&lt;/code&gt;.  And that is not
where I wanted to put the quote.  I wanted it just after the last &lt;code&gt;:END:&lt;/code&gt; in the
example block.&lt;/p&gt;
&lt;p&gt;Which lead me to the following bit of &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Emacs&#34;&gt;Emacs&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs”&#34; title=&#34;Other site-wide references of “Emacs”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EMACS&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(while (org-element-type-p
        (org-element-at-point)
        &#39;(drawer property-drawer keyword planning))
  (goto-char
   (org-element-property :end (org-element-at-point))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I call this just after moving &lt;em&gt;point&lt;/em&gt; to the &lt;code&gt;:contents-begin&lt;/code&gt; of the headline.&lt;/p&gt;
&lt;p&gt;There are four elements I’m looking for:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;drawer&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;That is the lines starting with &lt;code&gt;:LOGBOOK:&lt;/code&gt; and it’s related &lt;code&gt;:END:&lt;/code&gt;.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;property-drawer&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;That is the lines starting with &lt;code&gt;:PROPERTIES:&lt;/code&gt; and it’s
related &lt;code&gt;:END:&lt;/code&gt;.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;planning&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;That is the line starting &lt;code&gt;#+CLOSED:&lt;/code&gt;.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;keyword&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;That is a “just in case” I have other keywords defined on this
node.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Those four element types are automatically added and positioned by &lt;span&gt;&lt;a href=&#34;https://orgmode.org/&#34;&gt;Org-Mode&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Mode”&#34; title=&#34;Other site-wide references of “Org-Mode”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-MODE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 as
part of its baseline functionality and as part of my initial “work” capture
template.&lt;/p&gt;
&lt;p&gt;To understand the nodes, I used the interactive &lt;code&gt;eval-expression&lt;/code&gt;.  Moving point
to the beginning of the line then executing &lt;code&gt;(org-element-at-point)&lt;/code&gt; to see the
type.  And using &lt;code&gt;(goto-char (org-element-property :end (org-element-at-point)))&lt;/code&gt;
to move point to see it’s effect.&lt;/p&gt;
&lt;p&gt;You can &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/df2717f77ff1df89b28814b3f3f111e217c7ef6f/emacs.d/init.el#L3153-L3193&#34;&gt;read my updated function on Github&lt;/a&gt;.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Monkey Patch Fix for Bookmark&#43; for Emacs 30</title>
      <link>https://takeonrules.com/2024/12/03/monkey-patch-fix-for-bookmark-for-emacs-30/</link>
      <pubDate>Tue, 03 Dec 2024 10:42:36 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2024/12/03/monkey-patch-fix-for-bookmark-for-emacs-30/</guid>
        <category>emacs</category>
        <category>programming</category>
      <description>
        &lt;p&gt;Earlier this year, I started using the &lt;a href=&#34;https://github.com/emacsmirror/bookmark-plus&#34;&gt;Bookmarks+ emacs package&lt;/a&gt;.  And in
&lt;time datetime=&#34;2024-11&#34; title=&#34;2024-11&#34;&gt;November&lt;/time&gt; I upgraded to Emacs 30, at &lt;time datetime=&#34;2024-12-03&#34; title=&#34;2024-12-03&#34;&gt;present&lt;/time&gt; an Alpha/Beta release of the next
version.&lt;/p&gt;
&lt;h2 id=&#34;the-problem&#34;&gt;The Problem&lt;/h2&gt;
&lt;p&gt;I’ve encountered a few hiccups, the most insidious being how Bookmark+ was
losing/clobbering bookmarks.&lt;/p&gt;
&lt;p&gt;With some sleuthing, what I found was that the &lt;em&gt;read&lt;/em&gt; expectations for the
bookmark file were out of sync with how we &lt;em&gt;write&lt;/em&gt; the bookmark file (in Emacs
30).&lt;/p&gt;
&lt;p&gt;I didn’t dive too deep, but hopefully this triage can provide some clues.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; I also have not yet explored how to submit an issue for this observed
problem.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;p&gt;The expectations on &lt;em&gt;read&lt;/em&gt; is that there will be a line that starts with &lt;code&gt;)&lt;/code&gt; (&lt;span&gt;example given&lt;/span&gt; (&lt;abbr title=&#34;example given&#34;&gt;e.g.&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “example given”&#34; title=&#34;Other site-wide references of “example given”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EG&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
,
a closing parenthesis, implying the closing of a list).  The &lt;em&gt;write&lt;/em&gt; process
however was adding that closing parenthesis to the prior line.&lt;/p&gt;
&lt;p&gt;The result, the &lt;em&gt;read&lt;/em&gt; would fail.  And my bookmarks would start getting
clobbered.&lt;/p&gt;
&lt;h2 id=&#34;the-hack&#34;&gt;The Hack&lt;/h2&gt;
&lt;p&gt;After some experimentation, I think the following hack remediates most of the
problems I was encountering:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;  (add-hook &#39;bmkp-write-bookmark-file-hook
    #&#39;jf/bookmark+/remediate-bookmark-file)

  (defun jf/bookmark+/remediate-bookmark-file (&amp;amp;optional file)
    &amp;quot;Fix FILE format to conform to `bookmark+&#39;.

In updating to Emacs 30.x, I encountered problems with saving the
bookmark file.  What was happening is that the read format is assumed to
have a line that is only \&amp;quot;)\&amp;quot;.  However the writing was not doing that.

This function remediates the observed written format to conform to the
expected read format.&amp;quot;
    (with-current-buffer
      (find-file-noselect (or file bookmark-default-file))
      (save-excursion
        (goto-char (point-max))
        (if (re-search-backward &amp;quot;^)&amp;quot; nil t)
          (message &amp;quot;%s already well formatted&amp;quot; bookmark-default-file)
          (progn
            (goto-char (point-max))
            (re-search-backward &amp;quot;)&amp;quot;)
            (insert &amp;quot;\n&amp;quot;)
            (save-buffer))))))
&lt;/code&gt;&lt;/pre&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Re-Wiring My Epigraphs Functionality to Leverage My Bibliography File</title>
      <link>https://takeonrules.com/2024/12/01/re-wiring-my-epigraphs-functionality-to-leverage-my-bibliography-file/</link>
      <pubDate>Sun, 01 Dec 2024 09:09:03 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2024/12/01/re-wiring-my-epigraphs-functionality-to-leverage-my-bibliography-file/</guid>
        <category>blogging</category>
        <category>emacs</category>
        <category>org-mode</category>
        <category>programming</category>
      <description>
        &lt;p&gt;I’ve been working on adjusting my epigraphs.  Prior to &lt;time datetime=&#34;2024-11-29&#34; title=&#34;2024-11-29&#34;&gt;Friday&lt;/time&gt; my blog used one
file per epigraph.  These lonely files held metadata around the quote, the text
of the quote and any additional commentary I might have privately written.&lt;/p&gt;
&lt;h2 id=&#34;previous-epigraph&#34;&gt;Previous Epigraph&lt;/h2&gt;
&lt;p&gt;Here’s an example of that file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;#+title:      Trees are an invitation to think about time
#+date:       [2023-01-21 Sat 17:36]
#+filetags:
#+identifier: 20230121T173626

#+AUTHOR_NAME: Rebecca Solnit
#+WORK_TITLE: Orwell’s Roses

Trees are an invitation to think about time and to travel in it the
way they do, by standing still and reaching out and down.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;#+identifier&lt;/code&gt; of &lt;code&gt;20230121T173626&lt;/code&gt; is used for creating the link to this quote.&lt;/p&gt;
&lt;p&gt;The “Trees are an invitation to think…” is the quoted text.  &lt;cite&gt;Orwell’s Roses&lt;/cite&gt;is the work, and Rebecca Solnit the author.  The rest is for metadata,
discoverability, and back-linking.&lt;/p&gt;
&lt;h2 id=&#34;updated-epigraph&#34;&gt;Updated Epigraph&lt;/h2&gt;
&lt;p&gt;The updated epigraph, which is a &lt;em&gt;named&lt;/em&gt; quote or verse block contained within a
level two headline.  Here’s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;** STARTED Orwell’s Roses :books:
,:PROPERTIES:
,:AUTHOR: Rebecca Solnit
,:END:

#+NAME: 20230121T173626
#+begin_quote
Trees are an invitation to think about time and to travel in it the
way they do, by standing still and reaching out and down.
#+end_quote
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The new &lt;code&gt;NAME&lt;/code&gt; property is the prior &lt;code&gt;IDENTIFIER&lt;/code&gt;.  And the type of epigraph (e.g.,
a quote instead of verse) is indicated by the content block.&lt;/p&gt;
&lt;h2 id=&#34;benefits&#34;&gt;Benefits&lt;/h2&gt;
&lt;p&gt;This allows for multiple quotes from the same work.  And as previously mentioned
in 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2024/11/27/refining-my-personal-bibliography-and-epigraph-process/&#34;&gt;Refining My Personal Bibliography and Epigraph Process&lt;/a&gt;&lt;/cite&gt;, this allows for me to
generate both &lt;a href=&#34;https://takeonrules.com/site-map/bibliography/&#34;&gt;my Bibliography&lt;/a&gt; and &lt;a href=&#34;https://takeonrules.com/site-map/epigraphs/&#34;&gt;my Epigraphs&lt;/a&gt; from the same source file (as
they are related).&lt;/p&gt;
&lt;h2 id=&#34;exploring-org-insert-link&#34;&gt;Exploring &lt;code&gt;org-insert-link&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;While typing in &lt;span&gt;&lt;a href=&#34;https://orgmode.org/&#34;&gt;Org-Mode&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Mode”&#34; title=&#34;Other site-wide references of “Org-Mode”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-MODE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
, I use &lt;code&gt;M-x org-insert-link&lt;/code&gt; to select the type of link and the type then dictates the prompt/completion.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See &lt;a href=&#34;https://orgmode.org/manual/Handling-Links.html#index-C_002dc-C_002dl&#34;&gt;Handling Links (The Org Manual)&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;p&gt;I added epigraphs to my link options as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(org-link-set-parameters &amp;quot;epigraph&amp;quot;
    :complete #&#39;jf/org-link-ol-complete/epigraph
    :export #&#39;jf/org-link-ol-export/epigraph
    :face #&#39;jf/org-faces-epigraph
    :follow #&#39;jf/org-link-ol-follow/epigraph)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ve set 4 options for epigraphs:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;:complete&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;prompt for which epigraph to link to.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;:export&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;when I export the file, this function determines the exported
content.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;:face&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;I don’t want my epigraphs to look like regular links, so I’ve set the
face for this link to provide a visual clue.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;:follow&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;When I “click” on the epigraph link, this function finds the
epigraph and takes me to that location.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;See &lt;a href=&#34;https://orgmode.org/manual/Adding-Hyperlink-Types.html&#34;&gt;Adding Hyperlink Types (The Org Manual)&lt;/a&gt; for the documented options.&lt;/p&gt;
&lt;h2 id=&#34;emacs-lisp-code&#34;&gt;Emacs Lisp Code&lt;/h2&gt;
&lt;p&gt;The code I’m referencing can be found in &lt;a href=&#34;https://github.com/jeremyf/dotemacs/blob/37dd022a3393073c73ac77a3bcd8a011e39aa0a7/emacs.d/init.el#L4900-L5067&#34;&gt;my Dotemacs init.el file&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;the-complete-function&#34;&gt;The &lt;code&gt;:complete&lt;/code&gt; function&lt;/h3&gt;
&lt;p&gt;The following function reads the bibliography file, mapping the named
&lt;code&gt;quote-block&lt;/code&gt; and &lt;code&gt;verse-block&lt;/code&gt; into a list.  The list is a &lt;code&gt;cons&lt;/code&gt; cell with the &lt;code&gt;car&lt;/code&gt;
as the first 72 characters of the block and the &lt;code&gt;cdr&lt;/code&gt; as the name/identifier of
the block.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/org-link-ol-complete/epigraph ()
    &amp;quot;Find and insert an epigraph for export.

Wires into `org-insert-link&#39;.&amp;quot;
    (let* ((buffer
             (find-file-noselect jf/bibliography-filename))
            (candidates
              (save-excursion
                (with-current-buffer buffer
                  (org-element-map
                    (org-element-parse-buffer)
                    &#39;(quote-block verse-block)
                    (lambda (el)
                      ;; Skip un-named blocks as we can’t link to them.
                      (when-let* ((id
                                    (org-element-property :name el))
                                   (left
                                     (org-element-property
                                       :contents-begin el))
                                   (right
                                     (org-element-property
                                       :contents-end el))
                                   (text
                                     (s-trim
                                       (s-replace &amp;quot;\n&amp;quot; &amp;quot; &amp;quot;
                                         (buffer-substring-no-properties
                                           left
                                           (if (&amp;lt; (- right left) 72)
                                             right
                                             (+ left 72)))))))
                        (cons text id)))))))
            (candidate
              (completing-read &amp;quot;Epigraph: &amp;quot; candidates nil t))
            (id
              (alist-get candidate candidates nil nil #&#39;string=)))
      (when id
        (progn
          (message &amp;quot;Added %S to the kill ring&amp;quot; candidate)
          (kill-new candidate)
      (format &amp;quot;epigraph:%s&amp;quot; id)))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When I use &lt;code&gt;M-x org-insert-link&lt;/code&gt; and select epigraph, my completion shows the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;1/208  Epigraph: &amp;lt;PROMPT&amp;gt;
0  Your hands are empty The streets are empty You can&#39;t control us You can&#39;
1  Without contraries there is no progression.
2  The times are urgent let us slow down.
3  The use of truth is its communication.
4  Life is a brief encampment.
5  The map is not the territory.
6  Uncertainty is the refuge of hope.
7  Books are a uniquely portable magic.
8  Desire is movement rather than place.
9  Men have become the tools of their tools.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can then start typing to narrow the options.  Once I’ve selected the epigraph,
I’m then prompted to insert the description (&lt;span&gt;example given&lt;/span&gt; (&lt;abbr title=&#34;example given&#34;&gt;e.g.&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “example given”&#34; title=&#34;Other site-wide references of “example given”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EG&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
, the visible text for the
link).  As a quality of life improvement, the selection process adds the
selected block’s first 72 characters to the &lt;code&gt;kill-ring&lt;/code&gt;; allowing for quick
pasting.&lt;/p&gt;
&lt;p&gt;Later, when I export the epigraph, I discard the description favoring the
original text.&lt;/p&gt;
&lt;h3 id=&#34;the-follow-function&#34;&gt;The &lt;code&gt;:follow&lt;/code&gt; function&lt;/h3&gt;
&lt;p&gt;When I “click” on the link, I jump to the named block.  The following function
facilitates that behavior:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/org-link-ol-follow/epigraph (name)
    &amp;quot;Follow the NAME to the epigraph.&amp;quot;
    (let* ((file
             jf/bibliography-filename)
            (case-fold-search
              t))
      (find-file file)
      (goto-char (point-min))
      (search-forward-regexp (format &amp;quot;^#\\+name: +%s$&amp;quot; name))
      (pulsar--pulse)))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;the-export-function&#34;&gt;The &lt;code&gt;:export&lt;/code&gt; function&lt;/h3&gt;
&lt;p&gt;I often export &lt;span&gt;Org-Mode&lt;/span&gt;
 documents to Markdown, LaTeX, and HTML.  I want to
ensure that my epigraphs export in a meaningful format.  Below is the function
that facilitates that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/org-link-ol-export/epigraph (link description format protocol)
    &amp;quot;Export the text of the LINK epigraph in the corresponding FORMAT.

We ignore the DESCRIPTION and probably the PROTOCOL.&amp;quot;
    (let ((buffer
            (find-file-noselect jf/bibliography-filename)))
      (save-excursion
        (with-current-buffer buffer
          (let* ((epigraph
                   (car
                     (org-element-map
                       (org-element-parse-buffer)
                       &#39;(quote-block verse-block)
                       (lambda (el)
                         ;; Skip un-named blocks as we can’t link to
                         ;; them.
                         (when (string=
                                 (org-element-property :name el)
                                 link)
                           el)))))
                  (class
                    (if (eq &#39;verse-block (org-element-type epigraph))
                      &amp;quot;verse&amp;quot;
                      &amp;quot;quote&amp;quot;))
                  (lineage
                    (org-element-lineage epigraph))
                  (context
                    (car
                      (seq-filter
                        (lambda (el)
                          (and
                            (eq (org-element-type el) &#39;headline)
                            (= (org-element-property :level el) 2)))
                        lineage)))
                  (people?
                    (member &amp;quot;people&amp;quot;
                      (org-element-property :tags context)))
                  (work
                    (if people?
                      &amp;quot;&amp;quot;
                      (car (org-element-property :title context))))
                  (author
                    (if people?
                      (car (org-element-property :title context))
                      (org-entry-get context &amp;quot;AUTHOR&amp;quot;)))
                  (text
                    (buffer-substring-no-properties
                      (org-element-property
                        :contents-begin epigraph)
                      (org-element-property
                        :contents-end epigraph))))
            (cond
              ((and
                 ;; This represents the logic in Take on Rules before
                 ;; &amp;lt;2024-11-30 Sat&amp;gt;.
                 ;;
                 ;; QUESTION: Am I concerned with the backlinks?  They
                 ;; are cute, but are they worth it?  Assume I persist
                 ;; the ID, I can rebuild that logic.
                 jf/exporting-org-to-tor
                 (or (eq format &#39;html) (eq format &#39;md)))
                (format &amp;quot;{{&amp;lt; epigraph key=\&amp;quot;%s\&amp;quot; &amp;gt;}}&amp;quot; link))
              ((or (eq format &#39;html) (eq format &#39;md))
                (format &amp;quot;&amp;lt;blockquote class=\&amp;quot;%s\&amp;quot;&amp;gt;\n%s%s&amp;lt;/blockquote&amp;gt;\n&amp;quot;
                  class
                  (if (string= class &amp;quot;verse&amp;quot;)
                    (s-replace &amp;quot;\n&amp;quot; &amp;quot;&amp;lt;br /&amp;gt;\n&amp;quot; text)
                    text)
                  (cond
                    ((and (s-present? work) (s-present? author))
                      (format &amp;quot;\n&amp;lt;footer&amp;gt;&amp;amp;mdash;%s, &amp;lt;cite&amp;gt;%s&amp;lt;/cite&amp;gt;&amp;lt;/footer&amp;gt;&amp;quot;
                        author work))
                    ((s-present? work)
                      (format &amp;quot;\n&amp;lt;footer&amp;gt;&amp;amp;mdash; &amp;lt;cite&amp;gt;%s&amp;lt;/cite&amp;gt;&amp;lt;/footer&amp;gt;&amp;quot;
                        work))
                    ((s-present? author)
                      (format &amp;quot;\n&amp;lt;footer&amp;gt;&amp;amp;mdash; %s&amp;lt;/footer&amp;gt;&amp;quot;
                        author))
                    (t &amp;quot;&amp;quot;))))
              ((eq format &#39;latex)
                (format &amp;quot;\\begin{%s}\n%s%s\n\\end{%s}\n&amp;quot;
                  class
                  (if (string= &amp;quot;verse&amp;quot; class)
                    (s-replace &amp;quot;\n&amp;quot; &amp;quot;\\\\\n&amp;quot; text)
                    text)
                  (cond
                    ((and (s-present? work) (s-present? author))
                      (format &amp;quot;---%s, \\textit{%s}&amp;quot; author work))
                    ((s-present? work)
                      (format &amp;quot;---\\textit{%s}&amp;quot; work))
                    ((s-present? author)
                      (format &amp;quot;---%s&amp;quot; author))
                    (t &amp;quot;&amp;quot;))
                  class))
              ((eq format &#39;ascii)
                (let ((use-hard-newlines t))
                  (s-replace
                    &amp;quot;\n&amp;quot; hard-newline
                    (format &amp;quot;%s%s&amp;quot;
                      text
                      (cond
                        ((and (s-present? work) (s-present? author))
                          (format &amp;quot;\n\n—%s, “%s”&amp;quot; author work))
                        ((s-present? work)
                          (format &amp;quot;\n\n—“%s”&amp;quot; work))
                        ((s-present? author)
                          (format &amp;quot;\n\n—%s&amp;quot; author))
                        (t &amp;quot;&amp;quot;))))))
              (t nil)))))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There’s some refactoring I could do, but what I have reads easily enough for me.&lt;/p&gt;
&lt;h2 id=&#34;contrast&#34;&gt;Contrast&lt;/h2&gt;
&lt;p&gt;My previous approach (&lt;abbr title=&#34;example given&#34;&gt;e.g.&lt;/abbr&gt;
, one epigraph per file) felt a bit disjointed; namely
quotes from the same work were scattered amongst different files.  My previous
&lt;code&gt;:complete&lt;/code&gt; function read the file names; and by convention the file name encoded
the first few words of the quote.&lt;/p&gt;
&lt;p&gt;With the new approach, the &lt;code&gt;:complete&lt;/code&gt; function creates a more immediately legible
list of options.  And my quotes are contained within the larger context.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I wanted to share this functionality to further demonstrate using the &lt;span&gt;Org-Mode&lt;/span&gt;

&lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/API&#34;&gt;Application Programming Interface&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Application Programming Interface&#34;&gt;API&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Application Programming Interface”&#34; title=&#34;Other site-wide references of “Application Programming Interface”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-API&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
; in particular the &lt;code&gt;org-element-lineage&lt;/code&gt;, as that was something that took a
bit of searching and experimenting to utilize.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Extending My Bibliography for an On The Go “Shopping List”</title>
      <link>https://takeonrules.com/2024/11/27/extending-my-bibliography-for-an-on-the-go-shopping-list/</link>
      <pubDate>Wed, 27 Nov 2024 21:44:49 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2024/11/27/extending-my-bibliography-for-an-on-the-go-shopping-list/</guid>
        <category>emacs</category>
        <category>programming</category>
      <description>
        &lt;p&gt;Earlier &lt;time datetime=&#34;2024-11-27&#34; title=&#34;2024-11-27&#34;&gt;today&lt;/time&gt; I wrote 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2024/11/27/refining-my-personal-bibliography-and-epigraph-process/&#34;&gt;Refining My Personal Bibliography and Epigraph Process&lt;/a&gt;&lt;/cite&gt;.
And &lt;time datetime=&#34;2024-11-27&#34; title=&#34;2024-11-27&#34;&gt;this evening&lt;/time&gt; I added some additional functionality.  Namely writing my
“shopping list” to a file in the cloud.  One that I can access on my phone.
Useful for used bookstores and libraries.&lt;/p&gt;
&lt;p&gt;Here’s that code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;#+begin_src emacs-lisp :exports results :results value file :file ~/Library/CloudStorage/path-to-bibliography.txt
;; Export my “shopping list” to my Proton Drive.
(concat
  (s-join &amp;quot;\n&amp;quot;
    (org-map-entries
      (lambda ()
        &amp;quot;&amp;quot;
        (concat
          &amp;quot;- “&amp;quot;
          (org-element-property :title (org-element-at-point))
          (when-let ((subtitle
                       (org-entry-get
                         (org-element-at-point) &amp;quot;SUBTITLE&amp;quot;)))
            (format &amp;quot;: %s&amp;quot; subtitle))
          &amp;quot;”&amp;quot;
          (when-let ((authors
                       (org-entry-get
                         (org-element-at-point) &amp;quot;AUTHOR&amp;quot;)))
            (concat &amp;quot; by &amp;quot; authors))
          (when-let ((editors
                       (org-entry-get
                         (org-element-at-point) &amp;quot;EDITOR&amp;quot;)))
            (concat &amp;quot; Editors: &amp;quot; editors))))
      &amp;quot;+LEVEL=2+books+shoppingLists&amp;quot; &#39;file)))
#+end_src
&lt;/code&gt;&lt;/pre&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Refining My Personal Bibliography and Epigraph Process</title>
      <link>https://takeonrules.com/2024/11/27/refining-my-personal-bibliography-and-epigraph-process/</link>
      <pubDate>Wed, 27 Nov 2024 16:45:44 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2024/11/27/refining-my-personal-bibliography-and-epigraph-process/</guid>
        <category>emacs</category>
        <category>org-mode</category>
        <category>programming</category>
      <description>
        &lt;p&gt;Those that have explored my &lt;a href=&#34;https://takeonrules.com/site-map/&#34;&gt;Take on Rules’ Site Map&lt;/a&gt; may have noticed my
Epigraphs and Bibliography section.  In 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2024/11/25/exploring-the-reworking-of-a-blog-page/&#34;&gt;Exploring the Reworking of a Blog Page&lt;/a&gt;&lt;/cite&gt;,
I wrote about the Bibliography and some rework I was exploring.&lt;/p&gt;
&lt;h2 id=&#34;anatomy-of-a-document&#34;&gt;Anatomy of a Document&lt;/h2&gt;
&lt;p&gt;&lt;time datetime=&#34;2024-11-25&#34; title=&#34;2024-11-25&#34;&gt;Since publishing that post&lt;/time&gt;, I have folded my Epigraphs into the same file as the
Bibliography.&lt;/p&gt;
&lt;p&gt;I have two main sections in that document:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;Works&lt;/dt&gt;
&lt;dd&gt;The “published” material that may contain a quote.  I have Books,
Essays, Presentations, Verses, Blog Posts, and a few other oddities.&lt;/dd&gt;
&lt;dt&gt;People&lt;/dt&gt;
&lt;dd&gt;These are the people whom I’ve seen/heard quotes, but to which I’m
not attributing the associated work.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Below is an example of how I am organizing the information:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;** A Commentary on “The Stranger” :essays:
:PROPERTIES:
:AUTHOR: Jean-Paul Sartre
:END:

#+NAME: 20230701T143902
#+begin_quote
We tumble from sentence to sentence, from nothingness to nothingness.
#+end_quote
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Jean-Paul Sartre authored the essay &lt;cite&gt;A Commentary on “The Stranger”&lt;/cite&gt;.
And a quote from that essay is “We tumble from sentence to sentence, from
nothingness to nothingness.”&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;#+NAME: 20230701T143902&lt;/code&gt; is a unique identifier for that quote.  My eventual
goal will be to use that name to extend the org link functionality to search for
Epigraphs and link to them.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; See
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/2024/08/11/exporting-org-mode-elfeed-links/&#34;&gt;Exporting Org Mode Elfeed Links&lt;/a&gt;&lt;/cite&gt; for a reference implementation of
linking and exporting &lt;span&gt;&lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;elfeed package&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “elfeed package”&#34; title=&#34;Other site-wide references of “elfeed package”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ELFEED&#34;&gt;📖&lt;/a&gt;&lt;/small&gt;
links.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;p&gt;The Bibliography that I publish only includes the books I’ve read.  In this new
org file, &lt;dfn&gt;a read Book&lt;/dfn&gt; is: a second level headline tagged with &lt;code&gt;books&lt;/code&gt;
and marked as &lt;code&gt;DONE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The Epigraphs that I publish grabs all of the quote (and verse) blocks, and
assembles their attribution properties (e.g. Title, Subtitle, and Author).&lt;/p&gt;
&lt;h2 id=&#34;capture-templates&#34;&gt;Capture Templates&lt;/h2&gt;
&lt;p&gt;&lt;time datetime=&#34;2024-11-27&#34; title=&#34;2024-11-27&#34;&gt;Today&lt;/time&gt; I wrote three &lt;span&gt;&lt;a href=&#34;https://orgmode.org/&#34;&gt;Org-Mode&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Mode”&#34; title=&#34;Other site-wide references of “Org-Mode”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-MODE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 capture templates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Work&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Quote&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Person to Quote&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below is what I’ve added to my &lt;code&gt;org-capture-templates&lt;/code&gt; variable:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(&amp;quot;w&amp;quot; &amp;quot;Work&amp;quot;
 entry
 (file+headline
  &amp;quot;~/git/org/denote/private/20241124T080648--bibliography__personal.org&amp;quot;
  &amp;quot;Works&amp;quot;)
 &amp;quot;%^{Title} %^g\n:PROPERTIES:\n:ID: %(org-id-new)\n:AUTHOR: %^{AUTHOR}\n:END:\n%?&amp;quot;
 :jump-to-captured t)
(&amp;quot;q&amp;quot; &amp;quot;Quote&amp;quot;
 plain
 (file+function
  &amp;quot;~/git/org/denote/private/20241124T080648--bibliography__personal.org&amp;quot;
  jf/org/capture/quote-location)
 &amp;quot;#+begin_%^{Type|quote|quote|verse}\n%^{Text}\n#+end_%\\1&amp;quot;
 :prepare-finalize jf/org/capture/quote/name-that-block
 :jump-to-capture t)
(&amp;quot;p&amp;quot; &amp;quot;Person to Quote&amp;quot;
 entry
 (file+headline
  &amp;quot;~/git/org/denote/private/20241124T080648--bibliography__personal.org&amp;quot;)
 &amp;quot;%^{Name} :people:\n:PROPERTIES:\n:ID: %(org-id-new)\n:END:\n%?&amp;quot;
 :jump-to-capture t)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;Work&lt;/em&gt; and &lt;em&gt;Person to Quote&lt;/em&gt; are very basic.  The &lt;em&gt;Quote&lt;/em&gt; is more complicated,
relying on two functions.&lt;/p&gt;
&lt;h3 id=&#34;breaking-down-the-quote-capture&#34;&gt;Breaking Down the Quote Capture&lt;/h3&gt;
&lt;p&gt;When I capture a quote, I associate that quote with one of the headlines in my
bibliography; namely a person or a work.  I use &lt;code&gt;jf/org/capture/quote-location&lt;/code&gt; to
find the position in my Bibliography to insert the quote.&lt;/p&gt;
&lt;p&gt;That function:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prompts to select a tag from the Bibliography.&lt;/li&gt;
&lt;li&gt;Prompts me to select an item from a list of entries that include that tag.&lt;/li&gt;
&lt;li&gt;Positions the document at the end of the chosen entry.&lt;/li&gt;
&lt;/ul&gt;
&lt;!--listend--&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/org/capture/quote-location ()
  &amp;quot;Position to a selected “quotable” element base on prompts.

Narrow focus to a tag, then a named element.&amp;quot;
  (let* (
         ;; Prompt to select a tag from the current org file.
         (tag
          (completing-read &amp;quot;Tag: &amp;quot; (org-get-buffer-tags) nil t))
         ;; With the given tag, find all associated headlines that match
         ;; that tag.
         (headline-alist
          (org-element-map
              (org-element-parse-buffer &#39;headline)
              &#39;headline
            (lambda (headline)
              (when
                  (and
                   (eq (org-element-property :level headline) 2)
                   (member tag (org-element-property :tags headline)))
                (let ((title
                       (org-element-property :title headline))
                      (subtitle
                       (org-entry-get headline &amp;quot;SUBTITLE&amp;quot;))
                      (author
                       (org-entry-get headline &amp;quot;AUTHOR&amp;quot;)))
                  (cons
                   (format &amp;quot;«%s»%s&amp;quot;
                           (if subtitle
                               (concat title &amp;quot;: &amp;quot; subtitle)
                             title)
                           (if author
                               (concat &amp;quot; by &amp;quot; author)
                             &amp;quot;&amp;quot;))
                   (org-element-property :contents-end headline)))))))
         ;; Prompt me to pick one of those headlines.
         (headline
          (completing-read
           (concat &amp;quot;Choose from &amp;quot; tag &amp;quot;: &amp;quot;) headline-alist nil t)))
    (goto-char (alist-get headline headline-alist nil nil #&#39;string=))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once I’ve selected the work or person I’m quoting, I need to choose if it is
verse or quote.  A verse is exported such that white space matters (&lt;span&gt;example given&lt;/span&gt; (&lt;abbr title=&#34;example given&#34;&gt;e.g.&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “example given”&#34; title=&#34;Other site-wide references of “example given”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-EG&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
, a
poem).  A quote is non-verse (&lt;abbr title=&#34;example given&#34;&gt;e.g.&lt;/abbr&gt;
, prose, dialogue, what have you).&lt;/p&gt;
&lt;p&gt;Last, once I’ve written the quote, I name it.  My old mechanism for quotes was
that each quote would be a single &lt;span&gt;&lt;a href=&#34;https://protesilaos.com/emacs/denote&#34;&gt;Denote&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Denote”&#34; title=&#34;Other site-wide references of “Denote”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-DENOTE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 file.  And &lt;span&gt;Denote&lt;/span&gt;
 would assign an
identifier.  However, I’m moving away from that and am naming the quote based on
the 8 words of the first line.  I do that via the &lt;code&gt;:prepare-finalize&lt;/code&gt; function
&lt;code&gt;jf/org/capture/quote/name-that-block&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;(defun jf/org/capture/quote/name-that-block ()
  &amp;quot;Name a quote/verse block from capture block.

Use `denote-sluggify&#39; as the naming function for the quote&amp;quot;
  (let* (
          ;; The evaluated text thus far.  With prompts completed.
          (template
            (plist-get org-capture-current-plist :template))
          ;; By convention the second line of the template is the
          ;; first line of the content block
          (first-line-of-block-content
            (nth 1 (s-split &amp;quot;\n&amp;quot; template)))
          ;; Derive the name of the block by leveraging
          ;; `denote-sluggify&#39;.
          (name
            (s-join &amp;quot;-&amp;quot;
              (seq-take
                (s-split
                  &amp;quot;-&amp;quot;
                  (denote-sluggify &#39;title
                    first-line-of-block-content))
                8))))
    (save-excursion
      (save-restriction
        ;; Place the name of the quote just above the start of the
        ;; block.
        (goto-char (point-min))
        (insert (format &amp;quot;#+NAME: %s\n&amp;quot; name))))))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;exporting-the-epigraphs&#34;&gt;Exporting the Epigraphs&lt;/h2&gt;
&lt;p&gt;&lt;time datetime=&#34;2024-11-24&#34; title=&#34;2024-11-24&#34;&gt;This weekend&lt;/time&gt;, I wrote code to loop through all of the quote and verse blocks in
my Bibliography.  That code then randomizes the order of the epigraphs and
assembles an HTML version of that export; in part by using the quote’s lineage
to get its parent headline (&lt;abbr title=&#34;example given&#34;&gt;e.g.&lt;/abbr&gt;
, a &lt;em&gt;Work&lt;/em&gt; or a &lt;em&gt;Person&lt;/em&gt;) and the associated
metadata (&lt;abbr title=&#34;example given&#34;&gt;e.g.&lt;/abbr&gt;
, &lt;em&gt;Title&lt;/em&gt; and &lt;em&gt;Author&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;When I don’t name the quote, I don’t export that quote.&lt;/p&gt;
&lt;p&gt;The following is the &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Emacs_Lisp&#34;&gt;Emacs Lisp&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs Lisp”&#34; title=&#34;Other site-wide references of “Emacs Lisp”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ELISP&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 that implements the previously described
process.  It is the inner part of a block that exports its results to a file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-emacs-lisp&#34;&gt;;; https://lists.gnu.org/archive/html/emacs-devel/2024-09/msg00363.html
(defun seq-shuffle (sequence)
  &amp;quot;Shuffle the given SEQUENCE.&amp;quot;
  (cl-assert (sequencep sequence))

  (let* ((vec (seq-into sequence &#39;vector))
         (length (length vec))
         (n 0)
         (seq-type (type-of sequence)))
    (while (&amp;lt; n length)
      (let ((i (+ n (random (- length n))))
            (tmp (aref vec n)))
        (setf (aref vec n) (aref vec i)
              (aref vec i) tmp))
      (cl-incf n))

    (seq-into vec (if (eq &#39;cons seq-type) &#39;list seq-type))))
;; TODO: Create an Epigraph’s document, it pulls from bibliography but has
;; additional text.
;;
;; Find all of the named verse and quote blocks then export accordingly.
;;
;; By convention, the second level headlines are the nodes of interest;
;; that is the person that said something or the book in which it was
;; said.
(s-join
 &amp;quot;\n&amp;quot;
 (let ((epigraphs
  (org-element-map
      (org-element-parse-buffer)
      &#39;(quote-block verse-block)
    (lambda (el)
      ;; Skip un-named blocks as we can’t link to them.
      (when-let* ((id
       (org-element-property :name el)))
        (cons id el))))))
   (cl-mapcar
    (lambda (epigraph)
     (let* ((id
      (car epigraph))
     (el
      (cdr epigraph))
     (type
      (org-element-type el))
     (class
      (if (eq type &#39;verse-block) &amp;quot;verse&amp;quot; &amp;quot;&amp;quot;))
     (left
            (org-element-property
             :contents-begin el))
           (right
            (org-element-property
             :contents-end el))
     (text
      (buffer-substring-no-properties
       left
       right))
     (lineage
      (org-element-lineage el)))
       (let* ((h-node
         (car
      (seq-filter
       (lambda (el)
         (and
          (eq (org-element-type el) &#39;headline)
          (= (org-element-property :level el) 2)))
       lineage)))
        (people?
         (member &amp;quot;people&amp;quot; (org-element-property :tags h-node)))
        (title
         (if people?
       &amp;quot;&amp;quot;
     (car (org-element-property :title h-node))))
        (author
         (if people?
       (car (org-element-property :title h-node))
     (org-entry-get h-node &amp;quot;AUTHOR&amp;quot;))))
   (format &amp;quot;&amp;lt;blockquote class=\&amp;quot;%s\&amp;quot; id=\&amp;quot;%s\&amp;quot;&amp;gt;%s%s&amp;lt;/blockquote&amp;gt;&amp;quot;
     class
     id
     (let ((html
      (s-trim text)))
       ;; (org-export-string-as text &#39;html t))))
       (if (eq type &#39;verse-block)
           (s-replace &amp;quot;\n&amp;quot; &amp;quot;&amp;lt;br /&amp;gt;&amp;quot; html)
         html))
     (cond
      ((and (s-present? title) (s-present? author))
       (format &amp;quot;\n&amp;lt;footer&amp;gt;&amp;amp;mdash;%s, &amp;lt;cite&amp;gt;%s&amp;lt;/cite&amp;gt;&amp;lt;/footer&amp;gt;&amp;quot;
         author title))
      ((s-present? title)
       (format &amp;quot;\n&amp;lt;footer&amp;gt;&amp;amp;mdash; &amp;lt;cite&amp;gt;%s&amp;lt;/cite&amp;gt;&amp;lt;/footer&amp;gt;&amp;quot;
         title))
      ((s-present? author)
       (format &amp;quot;\n&amp;lt;footer&amp;gt;&amp;amp;mdash; %s&amp;lt;/footer&amp;gt;&amp;quot;
         author))
      (t &amp;quot;&amp;quot;))))))
    (seq-shuffle epigraphs))))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Consolidating the books I’ve read and the quotes I’ve gathered has helped me
think about additional functionality.  Namely the entire ecosystem of &lt;span&gt;Org-Mode&lt;/span&gt;
:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Agenda&lt;/li&gt;
&lt;li&gt;Clocking&lt;/li&gt;
&lt;li&gt;Column Views&lt;/li&gt;
&lt;li&gt;Sparse Tree&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I can also think of my bibliography as a reading list and a list of what I own,
owned, am borrowing and so forth.&lt;/p&gt;
&lt;p&gt;And as an added bonus, I can call &lt;code&gt;C-u M-x org-capture&lt;/code&gt;; which means I walk
through the file positioning process (&lt;abbr title=&#34;example given&#34;&gt;e.g.&lt;/abbr&gt;
, pick a tag, pick a tagged concept)
and jump to that location.&lt;/p&gt;
&lt;p&gt;Put another way, keep leveraging &lt;span&gt;Org-Mode&lt;/span&gt;
 and its nuances.  Up next, at least
sometime in the future, is to export the content to my blog.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Exploring the Reworking of a Blog Page</title>
      <link>https://takeonrules.com/2024/11/25/exploring-the-reworking-of-a-blog-page/</link>
      <pubDate>Mon, 25 Nov 2024 08:40:40 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2024/11/25/exploring-the-reworking-of-a-blog-page/</guid>
        <category>blogging</category>
        <category>emacs</category>
        <category>org-mode</category>
        <category>programming</category>
      <description>
        &lt;p&gt;I’m exploring the option of removing &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Hugo_(software)&#34;&gt;Hugo&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Hugo”&#34; title=&#34;Other site-wide references of “Hugo”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-HUGO&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 from my build process.  I have a todo
list of things to consider and explore.  One of those is my 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/site-map/bibliography/&#34;&gt;Bibliography&lt;/a&gt;&lt;/cite&gt;.&lt;/p&gt;
&lt;p&gt;Prior to &lt;time datetime=&#34;2024-11-24&#34; title=&#34;2024-11-24&#34;&gt;yesterday&lt;/time&gt; that page only existed in my &lt;span&gt;Hugo&lt;/span&gt;
 site repository.  Most
every other page’s canonical version exists in my &lt;span&gt;&lt;a href=&#34;https://protesilaos.com/emacs/denote&#34;&gt;Denote&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Denote”&#34; title=&#34;Other site-wide references of “Denote”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-DENOTE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 directories.  And when
I publish the post, I export that page to the &lt;span&gt;Hugo&lt;/span&gt;
 site repository.&lt;/p&gt;
&lt;p&gt;&lt;time datetime=&#34;2024-11-24&#34; title=&#34;2024-11-24&#34;&gt;Yesterday&lt;/time&gt;, I spent a bit of time transforming that page into an &lt;span&gt;&lt;a href=&#34;https://orgmode.org/&#34;&gt;Org-Mode&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Mode”&#34; title=&#34;Other site-wide references of “Org-Mode”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-MODE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 file.
Instead of representing the entries in an &lt;span&gt;Org-Mode&lt;/span&gt;
 table, I opted for sub-tree
entries and a code-block to reproduce the table.&lt;/p&gt;
&lt;h2 id=&#34;show-me-the-examples&#34;&gt;Show Me the Examples&lt;/h2&gt;
&lt;p&gt;The is as as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;
#+ROAM_REFS: https://takeonrules.com/site-map/bibliography/

In [[table:249][Most of the Books that I&#39;ve Read]], I list most of the books
that I&#39;ve read.  I have chosen to exclude most [[abbr:20221009T115226][RPG]]
books; in part because there are so many.  I plan to create a Ludography; a list
of games that I&#39;ve played, both [[abbr:20221009T115226][RPG]] and otherwise.

#+begin_src emacs-lisp :exports results :results value html
  (concat
   &amp;quot;&amp;lt;div class=\&amp;quot;table-wrapper\&amp;quot;&amp;gt;\n&amp;quot;
   &amp;quot;&amp;lt;table id=\&amp;quot;table-249\&amp;quot; aria-labelledby=\&amp;quot;caption-249\&amp;quot;&amp;gt;\n&amp;quot;
   &amp;quot;&amp;lt;caption id=\&amp;quot;caption-249\&amp;quot;&amp;gt;\n&amp;quot;
   &amp;quot;Table 249: Most of the Books that I&amp;amp;rsquo;ve Read\n&amp;quot;
   &amp;quot;&amp;lt;/caption&amp;gt;\n&amp;quot;
   &amp;quot;&amp;lt;thead&amp;gt;\n&amp;quot;
   &amp;quot;&amp;lt;tr&amp;gt;&amp;lt;th scope=\&amp;quot;col\&amp;quot;&amp;gt;Title&amp;lt;/th&amp;gt;&amp;lt;th scope=\&amp;quot;col\&amp;quot;&amp;gt;Author&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;\n&amp;quot;
   &amp;quot;&amp;lt;/thead&amp;gt;\n&amp;quot;
   &amp;quot;&amp;lt;tbody&amp;gt;\n&amp;quot;
   (s-join &amp;quot;\n&amp;quot;
  	 (org-map-entries
  	  (lambda ()
  	    &amp;quot;&amp;quot;
  	    (concat
  	     &amp;quot;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;cite&amp;gt;&amp;quot;
  	     (org-element-property :title (org-element-at-point))
  	     (when-let ((subtitle
  			 (org-entry-get (org-element-at-point) &amp;quot;SUBTITLE&amp;quot;)))
  	       (format &amp;quot;: %s&amp;quot; subtitle))
  	     &amp;quot;&amp;lt;/cite&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;quot;
  	     (org-entry-get (org-element-at-point) &amp;quot;AUTHOR&amp;quot;)
  	     &amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;quot;))
  	  &amp;quot;+LEVEL=2+books+TODO=\&amp;quot;DONE\&amp;quot;&amp;quot; &#39;file))
   &amp;quot;\n&amp;lt;tbody&amp;gt;\n&amp;lt;/table&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;quot;)
#+end_src

* Books :books:noexport:
:PROPERTIES:
:COLUMNS:  %ITEM(NAME) %AUTHOR %TODO
:END:

** DONE 1984
:PROPERTIES:
:TYPE: Book
:AUTHOR: George Orwell
:ID:       D8C4A544-993C-4C20-AB42-237267FAE4B4
:END:
** DONE Acts of King Arthur and His Noble Knights, The
:PROPERTIES:
:TYPE: Book
:AUTHOR: John Steinbeck
:ID:       C3461E8A-266B-4E6E-9627-2343CF7F72DA
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are four primary sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Line starting with &lt;code&gt;#+ROAM_REFS:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The paragraph starting &lt;code&gt;In [[table&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Emacs_Lisp&#34;&gt;Emacs Lisp&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Emacs Lisp”&#34; title=&#34;Other site-wide references of “Emacs Lisp”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ELISP&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 code block.&lt;/li&gt;
&lt;li&gt;And the Books tree with sub-nodes for each book read and it’s current state
(e.g. started, done).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While I don’t use &lt;span&gt;&lt;a href=&#34;https://www.orgroam.com/&#34;&gt;Org-Roam&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Roam”&#34; title=&#34;Other site-wide references of “Org-Roam”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-ROAM&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 anymore, I have kept the idea of &lt;code&gt;ROAM_REFS&lt;/code&gt;.  When a
document has a &lt;code&gt;ROAM_REFS&lt;/code&gt; entry that means there’s world-wide web representation
of that document.&lt;/p&gt;
&lt;p&gt;Whenever I publish a blog post, based on configuration &lt;span&gt;Hugo&lt;/span&gt;
 determines that
page’s &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/URL&#34;&gt;Uniform Resource Locator&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Uniform Resource Locator&#34;&gt;URL&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Uniform Resource Locator”&#34; title=&#34;Other site-wide references of “Uniform Resource Locator”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-URL&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
.  Then I update the underlying &lt;span&gt;Denote&lt;/span&gt;
 document with the &lt;abbr title=&#34;Uniform Resource Locator&#34;&gt;URL&lt;/abbr&gt;
 of that
blog post.  In my ongoing refactoring, I’m looking to use &lt;code&gt;ROAM_REFS&lt;/code&gt; as the
target where I’ll publish the page.&lt;/p&gt;
&lt;p&gt;I copied the paragraph from my current 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/site-map/bibliography/&#34;&gt;Bibliography&lt;/a&gt;&lt;/cite&gt;.  It’s part of the text that
I export.&lt;/p&gt;
&lt;p&gt;Next is the &lt;span&gt;Emacs Lisp&lt;/span&gt;
 code block.  That block queries the Books section of the
document for book’s I’m done reading.  It then creates an &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/HTML&#34;&gt;Hypertext Markup Language&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Hypertext Markup Language&#34;&gt;HTML&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Hypertext Markup Language”&#34; title=&#34;Other site-wide references of “Hypertext Markup Language”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-HTML&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 table and writes
that to the exported document.&lt;/p&gt;
&lt;p&gt;At present that &lt;span&gt;Emacs Lisp&lt;/span&gt;
 creates a direct representation of the &lt;abbr title=&#34;Hypertext Markup Language&#34;&gt;HTML&lt;/abbr&gt;
; in the
future I want to shift away from that direct representation.  But what I have is
an adequate proof of concept.&lt;/p&gt;
&lt;p&gt;Reviewing the &lt;code&gt;begin_src emacs-lisp :exports results :results value html&lt;/code&gt; line,
there are two keywords:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:exports&lt;/code&gt;, indicating export the &lt;code&gt;results&lt;/code&gt; of evaluating the code but not the
code itself.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:results&lt;/code&gt;, treat the results as &lt;abbr title=&#34;Hypertext Markup Language&#34;&gt;HTML&lt;/abbr&gt;
; meaning we don’t escape the exported
value, and instead treat it as raw &lt;abbr title=&#34;Hypertext Markup Language&#34;&gt;HTML&lt;/abbr&gt;
.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Last is the Books tree.  I have set this as &lt;code&gt;:noexport:&lt;/code&gt;, meaning the contents are
not exported as part of the process.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; Instead, as mentioned earlier, the tree is queried by the &lt;span&gt;Emacs Lisp&lt;/span&gt;
code.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;h2 id=&#34;emerging-functionality&#34;&gt;Emerging Functionality&lt;/h2&gt;
&lt;p&gt;By shifting from a row in a table to a node entry, I then expose greater
functionality.&lt;/p&gt;
&lt;p&gt;I can use &lt;span&gt;Org-Mode&lt;/span&gt;
’s todo functionality to track the state of my reading; even
when I started reading it.  The properties drawer allows for capturing
additional metadata (such as subtitle).  I have a columns view configured so I
can switch to reading the entries in tabular form.&lt;/p&gt;
&lt;p&gt;In other words, I get the full functionality of &lt;span&gt;Org-Mode&lt;/span&gt;
.  Clocking time, which
helps in content capture.  I’m also exploring how I would move my 
&lt;cite&gt;&lt;a href=&#34;https://takeonrules.com/site-map/epigraphs/&#34;&gt;Epigraphs&lt;/a&gt;&lt;/cite&gt; into
this document as well.  Doing that, however, I would be concerned with the size
of the file, as it is currently 3700 lines.&lt;/p&gt;
&lt;p&gt;I’m doing this slowly as a matter of reflection and self-care; looking to remove
&lt;span&gt;Hugo&lt;/span&gt;
 and related scripts from my build process.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>I Consider Myself a Writer Who Codes</title>
      <link>https://takeonrules.com/2024/11/08/i-consider-myself-a-writer-who-codes/</link>
      <pubDate>Fri, 08 Nov 2024 18:43:43 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2024/11/08/i-consider-myself-a-writer-who-codes/</guid>
        <category>personal</category>
        <category>poetry</category>
        <category>programming</category>
      <description>
        &lt;h2 id=&#34;first-a-haiku&#34;&gt;First a Haiku&lt;/h2&gt;
&lt;div class=&#34;verse&#34;&gt;
&lt;p&gt;Swish swish slide my sole&lt;br /&gt;
Through autumn’s collapse my heart&lt;br /&gt;
Knows winter then spring&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&#34;words-sprout-forth&#34;&gt;Words Sprout Forth&lt;/h2&gt;
&lt;p&gt;From seemingly nowhere the title &lt;cite&gt;I Consider Myself a Writer Who Codes&lt;/cite&gt; spilled over my keyboard.  In stress I feel urges to write; I assume a
form of catharsis.&lt;/p&gt;
&lt;p&gt;I haven’t written any novels nor white papers.  Nor have I published to any
journals.  Yet, those words “I consider myself a writer who codes” demanded my
attention.&lt;/p&gt;
&lt;h2 id=&#34;identity-job&#34;&gt;Identity ≠ Job&lt;/h2&gt;
&lt;p&gt;For 26 years I’ve been a professional software developer.  And for almost 14
years, I’ve been an active blogger.  As of &lt;time datetime=&#34;2024-11-08&#34; title=&#34;2024-11-08&#34;&gt;today&lt;/time&gt;, this will be my 1,050th post.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; Interested in some writing stats?  Take a look at &lt;a href=&#34;https://takeonrules.com/about/stats/&#34;&gt;my Post Statistics&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;p&gt;In years past I didn’t want my profession to be my identity, yet I slipped into
that mindset.  In part driven to “provide” for my family; but also because its a path of no resistance.&lt;/p&gt;
&lt;p&gt;American’s love to ask “what do you do?” with the quiet part—”…for work”—often left unspoken.  A few years ago, I deliberately kicked that question aside.  And ask other questions, like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“What’s sparking your interest these days?”&lt;/li&gt;
&lt;li&gt;“How are you finding joy?”&lt;/li&gt;
&lt;li&gt;“What’s been an interesting victory you’ve recently had?”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The goal of the question is to disrupt the easy path.  And when I am asked “What do I do?” I don’t answer with my career.&lt;/p&gt;
&lt;h2 id=&#34;a-shift&#34;&gt;A Shift&lt;/h2&gt;
&lt;p&gt;A recent habit I’ve developed is sharing features I’ve developed at work.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; Thank you &lt;a href=&#34;https://www.allisonmcmillan.com&#34;&gt;Allison&lt;/a&gt; for prompting me to do more of this.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
  I do this in differing ways each week, but the end results are similar:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A screencast where I’m walking through something&lt;/li&gt;
&lt;li&gt;An internal blog post that supplements the screencast&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My personal goal: help create an inviting space for people joining my team.  And provide the information in two modes so team members have a choice of how to engage with the content.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; Note, I have no plans to do videos as part of my personal writing.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;p&gt;I still code, but I’m taking more time writing documentation both on my approach but also on what I’ve delivered.  Creating a bit of a “chain of custody” regarding the development process.&lt;/p&gt;
&lt;p&gt;Fundamentally, writing to be understood.&lt;/p&gt;
&lt;h2 id=&#34;why-don-the-mantle-of-writer&#34;&gt;Why Don the Mantle of Writer?&lt;/h2&gt;
&lt;p&gt;I see a contradiction in saying I am not my profession but I am a writer.  Yet writing is my thinking.  So I suppose I’m fundamentally &lt;del&gt;saying&lt;/del&gt; writing “I’m a thinker who codes.”&lt;/p&gt;
&lt;p&gt;And again, there’s this aspect of writing to be understood.  By the compiler
and/or interpreter.&lt;/p&gt;
&lt;p&gt;I also chose to keep the kicker “writer who codes.”  Programming is very much a writing exercise.  And there’s an art to it.&lt;/p&gt;
&lt;h2 id=&#34;art-and-drudgery&#34;&gt;Art and Drudgery&lt;/h2&gt;
&lt;p&gt;&lt;time datetime=&#34;2024-11-07&#34; title=&#34;2024-11-07&#34;&gt;Yesterday&lt;/time&gt; at a local pub a friend and I started talking software languages.  For her job she’s possibly going to be learning &lt;span&gt;&lt;a href=&#34;https://takeonrules.com/tags/golang/&#34;&gt;Go Lang&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Go Lang”&#34; title=&#34;Other site-wide references of “Go Lang”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-GO&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
.&lt;/p&gt;
&lt;p&gt;The gist of my perspective is as follows:&lt;/p&gt;
&lt;p&gt;I dislike reading &lt;span&gt;Go Lang&lt;/span&gt;
 it’s neither beautiful nor poetic.  It reminds me of reading one run-on-sentence after another.&lt;/p&gt;
&lt;p&gt;Yet I love &lt;em&gt;working&lt;/em&gt; in &lt;span&gt;Go Lang&lt;/span&gt;
 because the tooling is amazing.&lt;/p&gt;
&lt;p&gt;But I hate writing it, in that it isn’t as “expressive” instead favoring a dry verbosity paired with mental gymnastics to conform to its type system.&lt;/p&gt;
&lt;p&gt;And stuff I’ve written is discoverable yet a bit more rigid.  Refactoring requires a different approach.&lt;/p&gt;
&lt;p&gt;Ultimately, what I’ve settled on is: &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Ruby_(programming_language)&#34;&gt;Ruby&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Ruby”&#34; title=&#34;Other site-wide references of “Ruby”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-RUBY&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 is to &lt;a href=&#34;https://en.wikipedia.org/wiki/Kenning&#34;&gt;kennings&lt;/a&gt; as &lt;span&gt;Go Lang&lt;/span&gt;
 is to sentences/phrases stitched together by a heavy dose of “…and then…”.&lt;/p&gt;
&lt;h2 id=&#34;despite-all-my-rage&#34;&gt;Despite All My Rage&lt;/h2&gt;
&lt;p&gt;Yet in all of my vocalizations and damnation of &lt;span&gt;Go Lang&lt;/span&gt;
, it’s simply a tool.  A means of shaping a solution to a problem.  And there’s not much use in cursing at your tools.  They don’t care.&lt;/p&gt;
&lt;p&gt;But there’s also a matter of discerning both the right tool for the job and keeping your tools well maintained.&lt;/p&gt;
&lt;p&gt;I write to help in all of that.  To explore my understanding and push against it.  But also recognize that the tools, like the jobs that deploy them, can create cages.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I want and need my life filled with art and mystery.  I have previously taken an easier path in which I conflated aspects of identity with my profession; though now I’m striving to eschew those sirens’ calls of efficiency and homogeneity.&lt;/p&gt;
&lt;p&gt;Yet, due to my current situation I’m more isolated than at other times in my life.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; It will pass.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
  And I recognize this as a potentially precarious state.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; Authoritarianism works towards isolation.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;p&gt;So I’m taking a writer’s route: engaging with conversations that are happening across space and time.  I’m reading essays, poetry, fiction, and forewards.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; I cannot express how much I love reading forewards of most any book.  Show me, tell me, how this thing was made.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
  I’m cultivating my public and private &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/RSS&#34;&gt;Rich Site Summary&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Rich Site Summary&#34;&gt;RSS&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Rich Site Summary”&#34; title=&#34;Other site-wide references of “Rich Site Summary”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-RSS&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 feed, helping to broaden my inputs.&lt;/p&gt;
&lt;p&gt;I’m trying to ask questions that aren’t the ones spewed forth by auto-pilot.  And I’m remember Le Guin, Camus, Butler, and many more are here with me.  I, &lt;strong&gt;and you&lt;/strong&gt;, are not alone.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Guarding Against Hugo&#39;s Breakage</title>
      <link>https://takeonrules.com/2024/11/05/guarding-against-hugos-breakage/</link>
      <pubDate>Tue, 05 Nov 2024 17:21:28 -0500</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2024/11/05/guarding-against-hugos-breakage/</guid>
        <category>blogging</category>
        <category>personal</category>
        <category>programming</category>
      <description>
        &lt;p&gt;&lt;time datetime=&#34;20241105&#34; title=&#34;20241105&#34;&gt;Today&lt;/time&gt;, as I was working/exploring removing &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Hugo_(software)&#34;&gt;Hugo&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Hugo”&#34; title=&#34;Other site-wide references of “Hugo”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-HUGO&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 from my site build chain, I
stumbled upon the following:&lt;/p&gt;

&lt;blockquote  class=&#34;h-cite&#34; cite=&#34;https://www.baldurbjarnason.com/notes/redesign/&#34;&gt;

&lt;p&gt;The primary reason why I redesigned the site was simple:&lt;/p&gt;
&lt;p&gt;I hate Hugo.&lt;/p&gt;
&lt;p&gt;It is a pain in the ass. It’s fast but keeps breaking to such an extent
that just the thought of updating the hugo binary is anxiety-inducing.&lt;/p&gt;


&lt;footer&gt;&amp;mdash;&lt;cite&gt;&lt;a href=&#34;https://www.baldurbjarnason.com/notes/redesign/&#34; class=&#34;u-url p-name&#34; rel=&#34;cite&#34;&gt;A bit of a redesign&lt;/a&gt;&lt;/cite&gt;
&lt;/footer&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have a series of &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Rake_(software)&#34;&gt;Rake&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Rake”&#34; title=&#34;Other site-wide references of “Rake”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-RAKE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 tasks that audit my site’s built files.  Why?  Because
&lt;span&gt;Hugo&lt;/span&gt;
 kept breaking things.  So I feel Baldur’s pain, and have worked to guard
against it.&lt;/p&gt;
&lt;p&gt;I pair this auditing, with something someone told me a few years ago; namely
that I’d eventually move towards publishing directly from &lt;span&gt;&lt;a href=&#34;https://orgmode.org/&#34;&gt;Org-Mode&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Org-Mode”&#34; title=&#34;Other site-wide references of “Org-Mode”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ORG-MODE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
.&lt;/p&gt;
&lt;p&gt;On &lt;time datetime=&#34;2024-11-03&#34; title=&#34;2024-11-03&#34;&gt;Sunday&lt;/time&gt; I started thinking about what this might mean.&lt;/p&gt;
&lt;p&gt;Why?&lt;/p&gt;
&lt;p&gt;Because my build was breaking…and my audits weren’t adequate.  So I added more
audits, and so long as I use &lt;span&gt;Hugo&lt;/span&gt;
, I’ll keep doing that.&lt;/p&gt;
&lt;p&gt;However, the broken build and the mind-worm of yesteryear started me thinking.
First I started thinking about porting more of my build from &lt;span&gt;Rake&lt;/span&gt;
 to &lt;span&gt;&lt;a href=&#34;https://takeonrules.com/tags/golang/&#34;&gt;Go Lang&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Go Lang”&#34; title=&#34;Other site-wide references of “Go Lang”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-GO&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;

commands.&lt;/p&gt;
&lt;p&gt;But that mind worm took root, could I remove &lt;span&gt;Hugo&lt;/span&gt;
 from my build?  Yes…but I had
work to do.  I spent time thinking and writing about what that might look like.&lt;/p&gt;
&lt;p&gt;It’s not something I’m moving towards quickly, but am instead writing to think
through what I need and am willing to set aside.&lt;/p&gt;
&lt;p&gt;Regardless, I definitely feel Baldur’s “I hate Hugo.”  But for the moment, it
does the job.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
    <item>
      <title>Adopting  Gomponents for Work Project</title>
      <link>https://takeonrules.com/2024/11/01/adopting-gomponents-for-work-project/</link>
      <pubDate>Fri, 01 Nov 2024 18:19:20 -0400</pubDate>
      <author>jeremy@takeonrules.com (Jeremy Friesen)</author>
      <guid isPermaLink="true">https://takeonrules.com/2024/11/01/adopting-gomponents-for-work-project/</guid>
        <category>emacs</category>
        <category>programming</category>
      <description>
        &lt;p&gt;At work, I’ve been writing a web application powered by &lt;span&gt;&lt;a href=&#34;https://takeonrules.com/tags/golang/&#34;&gt;Go Lang&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Go Lang&#34;&gt;Go&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Go Lang”&#34; title=&#34;Other site-wide references of “Go Lang”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-GO&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
.  This week I
switched from the &lt;a href=&#34;https://pkg.go.dev/github.com/teocci/go-simple-tpl/src/ginview&#34;&gt;ginview package found in go-simple-tpl&lt;/a&gt; to &lt;span&gt;&lt;a href=&#34;https://www.gomponents.com/&#34;&gt;Gomponents&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Gomponents”&#34; title=&#34;Other site-wide references of “Gomponents”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-GOMPONENTS&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
.&lt;/p&gt;
&lt;h2 id=&#34;switching&#34;&gt;Switching…&lt;/h2&gt;
&lt;p&gt;Why? Because I began working on the &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/User_interface&#34;&gt;User Interface&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;User Interface&#34;&gt;UI&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “User Interface”&#34; title=&#34;Other site-wide references of “User Interface”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-UI&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
, and thinking about these aspects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Breadcrumbs&lt;/li&gt;
&lt;li&gt;Navigation header&lt;/li&gt;
&lt;li&gt;Side bar&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Internationalization&lt;/span&gt; (&lt;abbr title=&#34;Internationalization&#34;&gt;i18n&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Internationalization”&#34; title=&#34;Other site-wide references of “Internationalization”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-INTERNATIONALIZATION&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
&lt;/li&gt;
&lt;li&gt;Conditional logic&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The simple templating system was going to creak and moan.  I know, because it’s
in the same lineage of my blog’s templating system.&lt;/p&gt;
&lt;h2 id=&#34;documenting-the-decision&#34;&gt;Documenting the Decision&lt;/h2&gt;
&lt;p&gt;I wrote the following in my decision:&lt;/p&gt;

&lt;blockquote  class=&#34;h-cite&#34;&gt;

&lt;p&gt;Let’s look at the inadequacies of the templating:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It’s clumsy to compose a page from different conceptual components; in part
because you must bring a consistent albeit non-enforced mindset to those
templates.&lt;/li&gt;
&lt;li&gt;When a template is broken, there’s a logged error, but the rending engine is
still quite happy to kick up to the requesting browser all of the &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/HTML&#34;&gt;Hypertext Markup Language&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Hypertext Markup Language&#34;&gt;HTML&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Hypertext Markup Language”&#34; title=&#34;Other site-wide references of “Hypertext Markup Language”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-HTML&#34;&gt;📖&lt;/a&gt;&lt;/small&gt;)
up to
the breaking point; while also keeping the initial rendering status.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Pair those two things, and we had two potent ingredients for broken pages and
functionality; with a bit of silence of what was broken.&lt;/p&gt;


&lt;/blockquote&gt;

&lt;h2 id=&#34;pivoting-to-gomponents&#34;&gt;Pivoting to Gomponents&lt;/h2&gt;
&lt;p&gt;The pivot involved swapping out one template with one page.  And getting that to
work “as is.”  It was quick work mapping the rendered &lt;abbr title=&#34;Hypertext Markup Language&#34;&gt;HTML&lt;/abbr&gt;
 to the function calls
to generate an identical &lt;abbr title=&#34;Hypertext Markup Language&#34;&gt;HTML&lt;/abbr&gt;
 document.&lt;/p&gt;
&lt;p&gt;With the alternate in place, I started developing the aforementioned &lt;abbr title=&#34;User Interface&#34;&gt;UI&lt;/abbr&gt;
 components
(e.g., navigation header, breadcrumbs and side bar).  As this was in &lt;abbr title=&#34;Go Lang&#34;&gt;Go&lt;/abbr&gt;
, instead
of the simple template language, I could create structs and initializer logic
that would make things easier.&lt;/p&gt;
&lt;p&gt;Turns out the breadcrumbs and side bar used the same structure with a different
initializer.&lt;/p&gt;
&lt;h2 id=&#34;leaning-on-the-compiler&#34;&gt;Leaning on the Compiler&lt;/h2&gt;
&lt;p&gt;I’ve worked in applications that mixed templates and conditional rendering for
authorization and authentication; that crap can get obnoxious to track down.&lt;/p&gt;
&lt;p&gt;Using the same tooling for generating pages as the functions meant I could rely
on &lt;abbr title=&#34;Go Lang&#34;&gt;Go&lt;/abbr&gt;
 and the surrounding ecosystem.  For example, with the &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Language_Server_Protocol&#34;&gt;Language Server Protocol&lt;/a&gt;&lt;/span&gt; (&lt;abbr title=&#34;Language Server Protocol&#34;&gt;LSP&lt;/abbr&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Language Server Protocol”&#34; title=&#34;Other site-wide references of “Language Server Protocol”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-LSP&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;)
 tracking called
functions in a page gets much easier.&lt;/p&gt;
&lt;p&gt;Contrast with a template, in which the editor can’t tell me what got me to that
point as well as what’s available.&lt;/p&gt;
&lt;p&gt;Put another way, my experience (both immediate and from years of this stuff)
tells me that the templating approach will be more brittle.&lt;/p&gt;
&lt;h2 id=&#34;bonus-emacs-content&#34;&gt;Bonus Emacs Content&lt;/h2&gt;
&lt;p&gt;Below is a sample of what could be the inner logic of a function to generate a
page’s body.&lt;/p&gt;

&lt;aside  role=&#34;note&#34; class=&#34;margin&#34;&gt;

&lt;p&gt;&lt;small&gt;Fun fact, while typing the &lt;abbr title=&#34;Go Lang&#34;&gt;Go&lt;/abbr&gt;
code out, I wanted to type &lt;code&gt;(Body(Header…&lt;/code&gt; instead
of &lt;code&gt;Body(Header(&lt;/code&gt;.  Definitely has a Lisp like feel to it.&lt;/small&gt;&lt;/p&gt;
&lt;/aside&gt;

&lt;pre&gt;&lt;code class=&#34;language-go-ts&#34;&gt;Body(
        Header(
                Nav(
                        A(Aria(&amp;quot;current-page&amp;quot;, &amp;quot;true&amp;quot;),
                                Href(&amp;quot;/&amp;quot;), Text(&amp;quot;Home&amp;quot;),
                        )),
        ),
        Article(
                H1(Text(&amp;quot;Welcome Home&amp;quot;)),
                P(Text(&amp;quot;It&#39;s where we put our feet up&amp;quot;)),
        )
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Given that I have these possibly long running nested nodes, I configured my use
of the &lt;span&gt;&lt;a href=&#34;https://github.com/meain/scopeline.el/&#34;&gt;scopeline package&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “scopeline package”&#34; title=&#34;Other site-wide references of “scopeline package”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-SCOPELINE-PACKAGE&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
 to add &lt;code&gt;call_expression&lt;/code&gt; to the &lt;code&gt;scopeline-target&lt;/code&gt; variable
for &lt;abbr title=&#34;Go Lang&#34;&gt;Go&lt;/abbr&gt;
 mode.&lt;/p&gt;
&lt;p&gt;Now for those chonky nodes, I can see what is the “opening” tag.  A constant
need of anyone working in &lt;abbr title=&#34;Hypertext Markup Language&#34;&gt;HTML&lt;/abbr&gt;
.&lt;/p&gt;
&lt;h2 id=&#34;what-about-huge-tracks-of-html&#34;&gt;What About Huge Tracks of Html?&lt;/h2&gt;
&lt;p&gt;Turns out as I was building out more pages, I wanted the ability to have chunks
of trusted HTML that I could load into the document.  Very simple:
&lt;code&gt;Raw(varWithRawHtml)&lt;/code&gt; did the trick.&lt;/p&gt;
&lt;p&gt;Now, where to get that &lt;abbr title=&#34;Hypertext Markup Language&#34;&gt;HTML&lt;/abbr&gt;
?  Templates!?!  Raw files?  I thought for a moment,
and decided to go the route of &lt;abbr title=&#34;Internationalization&#34;&gt;i18n&lt;/abbr&gt;
.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; Via the &lt;a href=&#34;https://github.com/nicksnyder/go-i18n&#34;&gt;go-i18n package&lt;/a&gt;.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
 It could address my immediate need while
also preparing me for a possible future need.&lt;/p&gt;
&lt;p&gt;I did some research, and my assessment on implementation time was about the
same.&lt;small class=&#34;side-container&#34;&gt;
  &lt;span class=&#34;side-label&#34;&gt;&lt;span class=&#34;hidden&#34;&gt;(&lt;/span&gt;Sidenote&lt;span class=&#34;hidden&#34;&gt;:&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&#34;side&#34; role=&#34;note&#34;&gt; And in doing so, I uncovered another crease in the application that helped
in the conceptual refactor.&lt;span class=&#34;hidden&#34;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/small&gt;
&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;For decades, I’ve used &lt;span&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Ruby_on_Rails&#34;&gt;Ruby on Rails&lt;/a&gt;&lt;/span&gt; &lt;small&gt;&lt;a class=&#34;ref&#34; rel=&#34;tag opener&#34; aria-label=&#34;Other site-wide references of “Ruby on Rails”&#34; title=&#34;Other site-wide references of “Ruby on Rails”&#34; href=&#34;https://takeonrules.com/site-map/glossary/#abbr-dfn-GLOSSARY-ROR&#34;&gt;&amp;#128214;&lt;/a&gt;&lt;/small&gt;
’ view templates; they are great and quick to use.
Until you have a lot of them, and then it starts to hurt.  You can introduce
helper methods and objects to assist, which is yet another effective strategy.&lt;/p&gt;
&lt;p&gt;There’s definitely a tension between the simplicity of a template and the
utility of page “objects.”&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Ruby on Rails&lt;/span&gt;
 has a very mature and well thought out template-orienting rendering
approach.  What I found with &lt;abbr title=&#34;Go Lang&#34;&gt;Go&lt;/abbr&gt;
 is frustratingly naive and fragile and not all
that opinionated; meaning you better be prepared to bring your opinions and
implement them.&lt;/p&gt;
&lt;p&gt;So I swung towards page objects, appreciating that my compiler can provide
guardrails to my UI development.  It feels like the alternative would have been
to introduce a test that checked every route (and some non existent ones) to see
if the page fully rendered.&lt;/p&gt;
&lt;p&gt;And there’s probably something I could do in &lt;abbr title=&#34;Go Lang&#34;&gt;Go&lt;/abbr&gt;
 to attempt a render then send
along the successful document.  But for a language that loves its error
handling, this silent error was particularly vexing.&lt;/p&gt;

      </description>
      <source url="https://takeonrules.com/index.xml">Take on Rules</source>
    </item>
    
  </channel>
</rss>
