What is the best way to use org-roam-node-read with an arbitrary list of nodes?

Let’s say I’m trying to write a function that will let me choose from all the backlinks to a particular node (and I don’t want to use the org-roam buffer, but rather the standard minibuffer completing-read function). I can’t just use org-roam-node-read with a filter function, because the list of nodes that org-roam-node-read is pulling from (which is given by org-roam-node-list) doesn’t have the relevant information. So I need to figure out the list of nodes that link to the node at point, and then somehow input them into org-roam-node-read, which lacks this functionality. Here is a fairly simple way I’ve figured out how to do this (the important work is done by the cl-letf in the first function, based on ideas I read about here and here):

(defun azr/org-roam-node-read (nodes)
  "Like org-roam-node-read but takes a list of NODES."
  (cl-letf (((symbol-function 'org-roam-node-list) (lambda () nodes)))
    (org-roam-node-read)))

(defun azr/org-roam-node-read-backlinks ()
  (interactive)
  "Like org-roam-node-read but only for backlinks of node at point."
  (let ((nodes (seq-uniq (mapcar #'org-roam-backlink-source-node
    		                     (org-roam-backlinks-get (org-roam-node-at-point))))))
    (azr/org-roam-node-read nodes)))

This works but it feels hacky. Is there a better way?

1 Like

Looks cool to me; especially the use of cl-letf.
Otherwise you would need to copy and paste relevant part from org-roam-node-read, and adjust.

Thanks. I just learned about cl-letf and am a big fan, especially for deeply nested function calls.

Ideally though the org-roam API would provide a better way to do this, so that I could, for example, also change the prompt text in the minibuffer completion.

until such an API gets done, you can always write your own function using org-roam-node-read as a reference. It’s not a big function and what it is doing is rather clear (it looks a bit complicated because of the API of built-in completion functions, I guess, but it’s almost fixed syntax).

Yeah, I haven’t figured out how the completion API works. But if, as you say, the details of that don’t matter and I can just copy and paste that bit of code, org-roam-node-read is quite simple. I just don’t like copy-pasting code I don’t understand :-).

You don’t need to take my word for it. In addition to the built-in documentation on completing-read, I use this part if Embark’s readme as a reference too. You will see it has the same form as org-roam-node-read when it uses completing-read (I vaguely remember this might be the way described in the built-in documentation, too) ;). It will soon go into C code if you try to read the source, which is for me a sign to turn around… (I don’t usually have C source as I don’t build Emacs on Windows).