diff --git a/CHANGELOG.md b/CHANGELOG.md index 4465110..8a5b9d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,12 @@ # Changelog +## 1.2.4 (TBD) + +### Added +- [#1270](https://github.com/org-roam/org-roam/pull/1270) capture: create OLP if it does not exist. Removes need for OLP setup in `:head`. + +### Changed + +### Fixed ## 1.2.3 (13-11-2020) diff --git a/doc/org-roam.org b/doc/org-roam.org index 5ad7c19..51d61c1 100644 --- a/doc/org-roam.org +++ b/doc/org-roam.org @@ -1123,20 +1123,19 @@ specifying the outline-path to a heading: #'org-roam-capture--get-point "* %?" :file-name "daily/%<%Y-%m-%d>" - :head "#+title: %<%Y-%m-%d>\n\n* Lab notes\n* Journal" + :head "#+title: %<%Y-%m-%d>\n" :olp ("Journal")) ("j" "journal" entry #'org-roam-capture--get-point "* %?" :file-name "daily/%<%Y-%m-%d>" - :head "#+title: %<%Y-%m-%d>\n\n* Lab notes\n* Journal" + :head "#+title: %<%Y-%m-%d>\n" :olp ("Lab notes")))) #+end_src The template ~l~ will put its notes under the heading ‘Lab notes’, and the -template ~j~ will put its notes under the heading ‘Journal’. When you use -~:olp~, make sure that the headings are present in ~:head~. +template ~j~ will put its notes under the heading ‘Journal’. ** Capturing and finding daily-notes diff --git a/doc/org-roam.texi b/doc/org-roam.texi index e4230a7..1fe2848 100644 --- a/doc/org-roam.texi +++ b/doc/org-roam.texi @@ -1525,20 +1525,19 @@ specifying the outline-path to a heading: #'org-roam-capture--get-point "* %?" :file-name "daily/%<%Y-%m-%d>" - :head "#+title: %<%Y-%m-%d>\n\n* Lab notes\n* Journal" + :head "#+title: %<%Y-%m-%d>\n" :olp ("Journal")) ("j" "journal" entry #'org-roam-capture--get-point "* %?" :file-name "daily/%<%Y-%m-%d>" - :head "#+title: %<%Y-%m-%d>\n\n* Lab notes\n* Journal" + :head "#+title: %<%Y-%m-%d>\n" :olp ("Lab notes")))) @end lisp The template @code{l} will put its notes under the heading ‘Lab notes’, and the -template @code{j} will put its notes under the heading ‘Journal’. When you use -@code{:olp}, make sure that the headings are present in @code{:head}. +template @code{j} will put its notes under the heading ‘Journal’. @node Capturing and finding daily-notes @section Capturing and finding daily-notes diff --git a/org-roam-capture.el b/org-roam-capture.el index 2028e93..68e8a23 100644 --- a/org-roam-capture.el +++ b/org-roam-capture.el @@ -442,6 +442,50 @@ the file if the original value of :no-save is not t and (org-capture-put :no-save t)) file-path)) +(defun org-roam-capture-find-or-create-olp (olp) + "Return a marker pointing to the entry at OLP in the current buffer. +If OLP does not exist, create it. If anything goes wrong, throw +an error, and if you need to do something based on this error, +you can catch it with `condition-case'." + (let* ((level 1) + (lmin 1) + (lmax 1) + (start (point-min)) + (end (point-max)) + found flevel) + (unless (derived-mode-p 'org-mode) + (error "Buffer %s needs to be in Org mode" (current-buffer))) + (org-with-wide-buffer + (goto-char start) + (dolist (heading olp) + (let ((re (format org-complex-heading-regexp-format + (regexp-quote heading))) + (cnt 0)) + (while (re-search-forward re end t) + (setq level (- (match-end 1) (match-beginning 1))) + (when (and (>= level lmin) (<= level lmax)) + (setq found (match-beginning 0) flevel level cnt (1+ cnt)))) + (when (> cnt 1) + (error "Heading not unique on level %d: %s" lmax heading)) + (when (= cnt 0) + ;; Create heading if it doesn't exist + (goto-char end) + (unless (bolp) (newline)) + (org-insert-heading nil nil t) + (unless (= lmax 1) (org-do-demote)) + (insert heading) + (setq end (point)) + (goto-char start) + (while (re-search-forward re end t) + (setq level (- (match-end 1) (match-beginning 1))) + (when (and (>= level lmin) (<= level lmax)) + (setq found (match-beginning 0) flevel level cnt (1+ cnt)))))) + (goto-char found) + (setq lmin (1+ flevel) lmax (+ lmin (if org-odd-levels-only 1 0))) + (setq start found + end (save-excursion (org-end-of-subtree t t)))) + (point-marker)))) + (defun org-roam-capture--get-point () "Return exact point to file for org-capture-template. The file to use is dependent on the context: @@ -485,26 +529,23 @@ This function is used solely in Org-roam's capture templates: see (org-roam-capture--put prop val))) (set-buffer (org-capture-target-buffer file-path)) (widen) - (if-let* ((olp (when (eq org-roam-capture--context 'dailies) - (--> (org-roam-capture--get :olp) - (pcase it - ((pred stringp) - (list it)) - ((pred listp) - it) - (wrong-type - (signal 'wrong-type-argument - `((stringp listp) - ,wrong-type)))))))) + (if-let* ((olp (--> (org-roam-capture--get :olp) + (pcase it + ((pred listp) + it) + (wrong-type + (signal 'wrong-type-argument + `((stringp listp) + ,wrong-type))))))) (condition-case err - (when-let ((marker (org-find-olp `(,file-path ,@olp)))) + (when-let ((marker (org-roam-capture-find-or-create-olp olp))) (goto-char marker) (set-marker marker nil)) (error (when (org-roam-capture--get :new-file) (kill-buffer)) (signal (car err) (cdr err)))) - (goto-char (point-min))))) + (goto-char (point-max))))) (defun org-roam-capture--convert-template (template) "Convert TEMPLATE from Org-roam syntax to `org-capture-templates' syntax."