complete-computing-environment/dynamic-org-captures.org

2.9 KiB

Dynamic Org Captures

An Emacs Lisp Macro for Org captures with dynamic file name:

(setq cce--journal-topic-id "journal"
      cce--standard-journal-topmatter
      '(insert ":PROPERTIES:\n"
               ":ID: " cce--journal-topic-id "-" (format-time-string "%Gw%V") "\n"
               ":END:\n"
               "#+TITLE: Journal " (format-time-string "%GW%V") "\n"
               "#+FILETAGS: :Journal:\n"
               "[[id:" cce--journal-topic-id "][Journal]]\n"))

(cl-defmacro cce-def-dynamic-org-capture (keys description 
                                               &key name 
                                               (top-matter cce--standard-journal-topmatter)
                                               capture-path-tmpl
                                               template-path
                                               extra-capture-args)
  `'(,keys ,description entry
           (file+olp+datetree cce--last-capture-location)
           (function
            (lambda ()
              (let ((filename (format-time-string ,capture-path-tmpl))
                    (template-filename ,template-path))
                (setq cce--last-capture-location filename)
                (unless (file-exists-p filename)
                  (message "Insert top-matter for %s" filename)
                  (find-file filename)
                  (goto-char (point-min))
                  ,top-matter)
                ;; lift from org-capture-get-template
                (let ((filename (expand-file-name template-filename org-directory)))
                  (if (file-exists-p filename) (org-file-contents filename)
                    (format "* Template file %S not found" file))))))
           ,@extra-capture-args
           ,@(unless (seq-contains extra-capture-args :tree-type)
               '(:tree-type week))))

(provide 'cce/dynamic-org-capture)

For a long time I used a system of my own invention to have dynamic file names in org-capture using defdaily and frankly it kind of stunk. Relying on timers was janky and often didn't behave how I wanted it to.

When I was reading the source code for Denote I made a realization in how they implemented support for "dynamic" file names in their capture templates.

  • the org-capture template can be a function and that is evaluated first
  • the capture can set a variable
  • file+olp+datetree and file capture targets can be variables.
  • the first function can set the variable used in the target and give dynamic capture file names.

Thanks denote.