I submitted the following issue for org-roam: Allow for `org-roam-buffer`’s Backlinks section to be unique per source. On I submitted a patch to address the issue: Adding unique option fro org-roam-backlinks-section.
While chatting with Jethro
Org Roam’s maintainer
he suggested using a pcase
construct. I have read the pcase
documentation and struggled to sift through it. It’s right on the boundary of my comprehension. So I proceeded with my pull request.
Later, I submitted a proposal for a customization, and Jethro explained that the pcase
construct would likely be cleaner and more generalizable. He then wrote up that change and pinged me. Thank you Jethro, now I have a pcase
use case that I understand what we’re doing, which will help me move pcase
further into my area of comprehension.
To learn, I’m going to write about the change that Jethro put forward:
(dolist (section-fn org-roam-mode-section-functions)
(pcase section-fn
((pred functionp)
(funcall section-fn org-roam-buffer-current-node))
(`(,fn . ,args)
(apply fn (cons org-roam-buffer-current-node args)))
(_
(user-error "Invalid `org-roam-mode-section-functions specification.'")))))
Line 1: This iterates over the org-roam-mode-section-functions
list. Each element of the list is section-fn
. The element is “passed” to the “anonymous function” that is lines 2 through 8 (e.g. the “body” of the dolist
).
Line 2: The pcase
expression we’re evaluating is the section-fn
. Reading the docstring for pcase
, it doesn’t say mention it explicitly, but the verbose name for pcase
could be patterning-matching-case-statement
.
Line 3: This is the first pattern that we check. This line answers the question: Is the section-fn
a function?
Line 4: When section-fn
is a function, call that function passing the org-roam-buffer-current-node
as the only argument.
Line 5: This is the line that breaks me. What I do know is that when section-fn
is (org-roam-backlinks-section :unique t)
then this is a match. But
Line 6: Call the fn
(which is declared in line 5?) with the org-roam-buffer-current-node
and the args
. Okay, this is breaking my brain a bit.
Line 7 and 8: The fallback is to raise a user-error.
That Which Breaks Me
On a cursory read, line 5 and 6 confound me. My mind wonders what is fn
and args
? How do they become the “variables” of line 6?
While thrashing against this, I started building up some search terms: “pcase emacs backquote”. Which lead me to Backquote-Style Patterns. Jackpot!
Backquote-style patterns are a powerful set of
pcase
pattern extensions (created usingpcase-defmacro
) that make it easy to match expval against specifications of its structure.
Of course, it’s in the manual. And reading further, I see the following:
The first three clauses use backquote-style patterns.
`(add ,x ,y)
is a pattern that checks that form is a three-element list starting with the literal symbol add, then extracts the second and third elements and binds them to symbolsx
andy
, respectively.
The commas are used to “extract” elements of the section-fn
and allow them to be used later on. I’m trying to connect this to my extensive Ruby (Ruby 📖) experience, and I’m struggling to do so.
I’ve used case statements before, but I hadn’t considered how I might use comparison statement as the thing that also “declares” the variables for evaluation.
Thank You
So thank you Jethro for taking the time to refine the org-roam
code. This has helped me further develop my understanding of Emacs.