Let’s try to do just that (or an example of that at least)! The
question is: what notes attract my attention most? Let me quantify
this question by saying: which notes have the most Org Roam backlinks?
This makes sense to me because adding a backlink is an effort.
Backlinks show how much I care about a note. So the plan is to take (a
portion of — I got too many notes–) my notes, get how many backlinks
they have, and plot this to see which note wins. Also I want to click
the plot to open the note in Emacs (and show its backlinks). It sounds
complex, but here it is!
Time to explain! First of all the tools I needed for this workflow.
- Emacs (for everything really),
- Org Roam (for the notes),
- Vega-Lite (for the plot),
- Moldable Emacs (for playground and data conversion),
- Emacs-with-Nyxt (for interaction between Nyxt and Emacs),
- Nyxt (for hooking Emacs to the plot).
We start from a moldable-emacs Playground that takes the first 100
notes and transforms them into a plist. The list contains the number
of backlinks, the size of the file and a
:command which tells what
to do when you click on a Vega-Lite node.
(--> (org-roam-node-list) (-take 100 it) (--filter (> (length (org-roam-backlinks-get it)) 0) it) (--map (list :file (org-roam-node-file it) :backlinks (length (org-roam-backlinks-get it)) :size (file-attribute-size (file-attributes (org-roam-node-file it))) :command (concat "file:///" (base64-encode-string (concat "(progn (find-file "" (org-roam-node-file it) "") (org-roam-buffer-toggle))")) ".ag91")) it) )
Vega-Lite does take data in JSON format. So we translate that plist
into JSON with another moldable-emacs mold. The Vega-Lite schema is a
hack of the scatterplot with href example. The dimensions I consider
are backlinks and size of file (I was curious if there was correlation
between size and backlinks).
Anyway, we now get into the pretty cool stuff. Vega-Lite supports
hyperlinks to allow you click a node of the plot and navigate the web.
I want to run an Emacs action instead (i.e., open the note and open
the Org Roam buffer with backlinks)! What to do? Hack the hyperlink!
Nyxt comes with a super-cool feature: it lets you define how to handle
links. Recently I modified my Nyxt configuration to open mails with
Emacs. You can also tell how to handle file extensions of an hyperlnk.
So I made my own file extension and an handler.
(define-configuration buffer ((request-resource-hook (reduce #'hooks:add-hook (list (url-dispatching-handler 'emacs-mail (match-scheme "mailto") "/usr/bin/emacsclient --eval '(browse-url-mail "~a")'" ) (url-dispatching-handler 'decode-elisp-with-emacs (match-file-extension "ag91") "/usr/bin/emacsclient --eval '(emacs-with-nyxt-decode-command "~a")'" )) :initial-value %slot-default%))))
Note that when I find that extension, I make Emacs call
emacs-with-nyxt-decode-command. The reason is into the Playground we saw before.
:command (concat "file:///" (base64-encode-string (concat "(progn (find-file "" (org-roam-node-file it) "") (org-roam-buffer-toggle))")) ".ag91")
I put Elisp into my file name!!! I encode my Elisp program in base64
and then add an
That is why I need a decode function.
(defun emacs-with-nyxt-decode-command (a) (--> a (s-split "/" it t) reverse car (s-split "\." it t) car base64-decode-string read eval))
This is probably crazy, but it opens humongous possibilities! You can
run Elisp from the browser. And you can embed actions as hyperlinks!! I
need to design a less hacky way to use this, after which I will add it
to moldable-emacs and emacs-with-nyxt.
And with this, I feel closer to have a moldable interface to
understand better the world around me.
(Note, this integration is a bit complex because Emacs does not have a
good UX story. Otherwise, we could probably have an Emacs Vega-Lite
and a simple way to hook actions to nodes. Nyxt embraces HTML and
makes that first class. I think GlamorousToolkit has a much better
story because the UX is a first class citizen of the IDE: this means I
would not need to jump from Emacs to Nyxt and back. In GT you can just
program the components of the UX (which are Pharo objects) from within
your tool. I hope Emacs will get inspired by that at some point!)