Run source blocks in an Org Mode subtree by custom ID
| emacs, org
I like the way Org Mode lets me logically group
functions into headings. If I give the heading a
CUSTOM_ID
property (which is also handy for
exporting to HTML, as it turns into an link
anchor), I can use that property to find the
subtree. Then I can use
org-babel-execute-subtree
to execute all source
blocks in that subtree, which means I can mix
scripting languages if I want to.
Here's the code:
(defun my-org-execute-subtree-by-custom-id (id &optional filename)
"Prompt for a CUSTOM_ID value and execute the subtree with that ID.
If called with \\[universal-argument], prompt for a file, and then prompt for the ID."
(interactive (if current-prefix-arg
(let ((file (read-file-name "Filename: ")))
(list
(with-current-buffer (find-file-noselect file)
(completing-read
"Custom ID: "
(org-property-values "CUSTOM_ID")))
file))
(list
(completing-read "Custom ID: " (org-property-values "CUSTOM_ID")))))
(with-current-buffer (if filename (find-file-noselect filename) (current-buffer))
(let ((pos (org-find-property "CUSTOM_ID" id)))
(if pos
(org-babel-execute-subtree)
(if filename(error "Could not find %s in %s" id filename)
(error "Could not find %s" id))))))
For example, in Using Org Mode, Emacs Lisp, and TRAMP to parse meetup calendar entries and generate a crontab, I have a Emacs Lisp source block that generates a crontab on a different computer, and a shell source block that installs it on that computer.
Technical notes: org-babel-execute-subtree
narrows to the current subtree, so if I want
anything from the rest of the buffer, I need to
widen the focus again. Also, it's wrapped in a
save-restriction
and a save-excursion
, so
someday I might want to figure out how to handle
the cases where I want to change what I'm looking
at.
elisp:
links in Org Mode let me call functions
by clicking on them or following them with C-c
C-o
(org-open-at-point
). This means I can make
links that execute subtrees that might even be in
a different file. For example, I can define links
like these:
[[elisp:(my-org-execute-subtree-by-custom-id "update" "~/sync/emacs-calendar/README.org")][Update Emacs calendar]]
[[elisp:(my-org-execute-subtree-by-custom-id "crontab" "~/sync/emacs-calendar/README.org")][Update Emacs meetup crontab]]
That could be a good starting point for a dashboard.
Related: Execute a single named Org Babel source block