Linking to and exporting function definitions in Org Mode
| emacs, org
2023-09-05: fixed the completion to include defun:
I'd like to write more blog posts about little Emacs hacks, and I'd like to do it with less effort. Including source code is handy even when it's missing some context from other functions defined in the same file, since sometimes people pick up ideas and having the source code right there means less flipping between links. When I'm working inside my config file or other literate programming documents, I can just write my blog post around the function definitions. When I'm talking about Emacs Lisp functions defined elsewhere, though, it's a little more annoying to copy the function definition and put it in a source block, especially if there are updates.
The following code creates a defun
link type that exports the function
definition. It works for functions that can be located with
find-function, so only functions loaded from .el files, but that does
what I need for now. Probably once I post this, someone will mention a
much more elegant way to do things. Anyway, it makes it easier to use
org-store-link
to capture a link to the function, insert it into a
blog post, navigate back to the function, and export HTML.
(defun my-org-defun-complete () "Return function definitions." (concat "defun:" (completing-read "Function: " #'help--symbol-completion-table #'fboundp 'confirm nil nil))) ; (and fn (symbol-name fn)) ? (defun my-org-defun-link-description (link description) "Add documentation string as part of the description" (unless description (when (string-match "defun:\\(.+\\)" link) (let ((symbol (intern (match-string 1 link)))) (when (documentation symbol) (concat (symbol-name symbol) ": " (car (split-string (documentation symbol) "\n")))))))) (defun my-org-defun-export (symbol description format _) "Export the function." (save-window-excursion (find-function (intern symbol)) (let ((function-body (buffer-substring (point) (progn (forward-sexp) (point))))) (pcase format ((or '11ty 'html) (format " <details><summary>%s</summary><div class=\"org-src-container\"><pre class=\"src src-emacs-lisp\">%s</pre></div></details>" (or description (and (documentation (intern symbol)) (concat symbol ": " (car (split-string (documentation (intern symbol)) "\n")))) symbol) (org-html-do-format-code function-body "emacs-lisp" nil nil nil nil))) (`ascii function-body) (_ function-body))))) (defun my-org-defun-store () "Store a link to the function." (when (derived-mode-p 'emacs-lisp-mode) (org-link-store-props :type "defun" :link (concat "defun:" (lisp-current-defun-name))))) (defun my-org-defun-open (symbol _) "Jump to the function definition." (find-function (intern symbol))) (org-link-set-parameters "defun" :follow #'my-org-defun-open :export #'my-org-defun-export :complete #'my-org-defun-complete :insert-description #'my-org-defun-link-description :store #'my-org-defun-store)