Skip to content

Configuring series

Martin Edström edited this page Aug 28, 2024 · 14 revisions

Here's a few premade series definitions.

They are examples only; the idea is that you override them completely, not use add-to-list or the like.

After evalling a new definition, remember to type M-x org-node-reset RET.

The default value

(setq org-node-series-defs
  (list
   '("d" :name "Daily-files"
     :version 2
     :classifier (lambda (node)
                   (let ((path (org-node-get-file-path node)))
                     (when (string-search (org-node--guess-daily-dir) path)
                       (let ((ymd (org-node-helper-filename->ymd path)))
                         (when ymd
                           (cons ymd path))))))
     :whereami (lambda ()
                 (org-node-helper-filename->ymd buffer-file-name))
     :prompter (lambda (key)
                 (let ((org-node-series-that-marks-calendar key))
                   (org-read-date)))
     :try-goto (lambda (item)
                 (org-node-helper-try-visit-file (cdr item)))
     :creator (lambda (sortstr key)
                (let ((org-node-datestamp-format "")
                      (org-node-ask-directory (org-node--guess-daily-dir)))
                  (org-node-create sortstr (org-id-new) key))))

   ;; Obviously, this series works best if you have `org-node-put-created' on
   ;; `org-node-creation-hook'.
   '("a" :name "All ID-nodes by property :CREATED:"
     :version 2
     :capture "n"
     :classifier (lambda (node)
                   (let ((time (cdr (assoc "CREATED" (org-node-get-props node)))))
                     (when (and time (not (string-blank-p time)))
                       (cons time (org-node-get-id node)))))
     :whereami (lambda ()
                 (let ((time (org-entry-get nil "CREATED" t)))
                   (and time (not (string-blank-p time)) time)))
     :prompter (lambda (key)
                 (let ((series (cdr (assoc key org-node--series))))
                   (completing-read "Go to: " (plist-get series :sorted-items))))
     :try-goto (lambda (item)
                 (when (org-node-helper-try-goto-id (cdr item))
                   t))
     :creator (lambda (sortstr key)
                (org-node-create sortstr (org-id-new) key))))

Custom-formatted date in the file title, while keeping filename as YYYY-MM-DD

For the "d" series above, change the :creator to:

:creator (lambda (sortstr key)
           (let ((org-node-datestamp-format "")
                 (org-node-slug-fn (lambda (&rest _) sortstr))
                 (org-node-ask-directory (org-node--guess-daily-dir)))
             (org-node-create (format-time-string
                               "%Y-%b-%d" ;; your custom format
                               (org-time-string-to-time sortstr))
                              (org-id-new)
                              key)))

More

'("f" :name "All files by file-name datestamp"
  :version 2
  :capture "n"
  :classifier (lambda (node)
                (let ((path (org-node-get-file-path node)))
                  (when (org-node-extract-file-name-datestamp path)
                    (cons (file-name-nondirectory path) path))))
  :whereami (lambda ()
              (when (org-node-extract-file-name-datestamp buffer-file-name)
                (cons (file-name-nondirectory buffer-file-name)
                      buffer-file-name)))
  :prompter (lambda (key)
              (let ((series (cdr (assoc key org-node--series))))
                (completing-read "Go to: " (plist-get series :sorted-items))))
  :try-goto (lambda (item)
              (org-node-helper-try-goto-id (cdr item)))
  :creator (lambda (sortstr key)
             (org-node-create sortstr (org-id-new) key)))

Dailies, using Roam internals

Quick start for simple cases

If you always had just one daily capture template, then this definition should work as a drop-in.

It is not perfect, e.g. the :capture key cannot be useful, but it will use your actual org-roam-dailies-capture-templates to create new nodes, giving you time to port your way of doing things.

   '("d" :name "Dailies, using Roam internals"
     :version 2
     :classifier (lambda (node)
                   (if (boundp 'org-roam-dailies-directory)
                       (let ((path (org-node-get-file-path node)))
                         (when (string-search org-roam-dailies-directory path)
                           (let ((ymd (org-node-helper-filename->ymd path)))
                             (when ymd
                               (cons ymd path)))))
                     (error "Not installed: org-roam")))
     :whereami (lambda ()
                 (org-node-helper-filename->ymd buffer-file-name))
     :prompter (lambda (key)
                 (let ((org-node-series-that-marks-calendar key))
                   (org-read-date)))
     :try-goto (lambda (item)
                 (org-node-helper-try-visit-file (cdr item)))
     :creator (lambda (sortstr key)
                (if (fboundp 'org-node-fakeroam-daily-create)
                    (org-node-fakeroam-daily-create sortstr key t)
                  (error "Not installed: org-node-fakeroam"))))

Rethinking

Interfacing with org-roam-dailies is possible, but it's a bit odd to do so and you have to ask why. Get some idea of what it will bring you.

Let's recap the architecture of org-roam-dailies:

  1. Everything under a "daily/" dir is potentially a daily. Nothing outside can be.
  2. A daily is both created or navigated-to using the corresponding capture template.
    • If you have just a single capture template, then several commands actually autoselect that one.
  3. You can have multiple files for the same day, so long as they are created using different capture templates, which place them in different sub-directories. Like, you could have a file "./daily/work/2024-04-15.org" as well as a file "./daily/self-reviews/2024-04-15.org".
  4. How the items are ordered in sequence is a matter of how the filenames sort. So there is no possibility of nesting them in a datetree file. (correct me on this)

If you like all of that, just stay with org-roam-dailies. If it's slow, see https://github.com/meedstrom/org-node#tip-on-very-slow-filesystems.

Extra commands

We do not ship built-in commands for the equivalents of "goto today", "goto next" or "goto previous". The series dispatch is the only command.

Here are some commands that hardcode a specific series keyed on "d".

(defun my-goto-date ()
  (interactive)
  (org-node--series-jump "d"))

(defun my-goto-today ()
  (interactive)
  (let* ((series (cdr (assoc "d" org-node--series)))
         (item (assoc (format-time-string "%F")
                      (plist-get series :sorted-items))))
    (when (or (null item)
              (not (funcall (plist-get series :try-goto) item)))
      (funcall (plist-get series :creator)
               (format-time-string "%F")
               (plist-get series :key)))))

(defun my-goto-next-day ()
  (interactive nil org-mode)
  (org-node--series-goto-next "d"))

(defun my-goto-prev-day ()
  (interactive nil org-mode)
  (org-node--series-goto-previous "d"))
Clone this wiki locally