mirror of
https://github.com/org-roam/org-roam
synced 2025-09-18 16:06:49 -05:00
(feat): clean-ups for org-roam-capture system (#315)
This introduces 2 user-facing changes: 1. If a capture process is aborted, the file is not created if it doesn't yet exist 2. If a capture process is aborted, org-roam-insert will not insert a link
This commit is contained in:
122
org-roam.el
122
org-roam.el
@@ -735,6 +735,9 @@ applies.
|
|||||||
inserted on initial creation (added only once). This is where
|
inserted on initial creation (added only once). This is where
|
||||||
insertion of any note metadata should go.")
|
insertion of any note metadata should go.")
|
||||||
|
|
||||||
|
(defvar org-roam--capture-insert-link-plist nil
|
||||||
|
"Dynamically scoped variable used to insert the org link after org-capture.")
|
||||||
|
|
||||||
(defun org-roam--fill-template (str &optional info)
|
(defun org-roam--fill-template (str &optional info)
|
||||||
"Expands the template STR, returning the string.
|
"Expands the template STR, returning the string.
|
||||||
This is an extension of org-capture's template expansion.
|
This is an extension of org-capture's template expansion.
|
||||||
@@ -751,6 +754,16 @@ Next, it expands the remaining template string using
|
|||||||
(completing-read (format "%s: " key ) nil))) nil)
|
(completing-read (format "%s: " key ) nil))) nil)
|
||||||
(org-capture-fill-template)))
|
(org-capture-fill-template)))
|
||||||
|
|
||||||
|
(defun org-roam--capture-save-file-maybe-h ()
|
||||||
|
"This function is saves the file if the original value of
|
||||||
|
:no-save is not t and `org-note-abort' is not t. It is added to
|
||||||
|
`org-capture-after-finalize-hook'."
|
||||||
|
(when (and (not (org-capture-get :orig-no-save))
|
||||||
|
(not org-note-abort))
|
||||||
|
(with-current-buffer (org-capture-get :buffer)
|
||||||
|
(save-buffer)))
|
||||||
|
(remove-hook 'org-capture-after-finalize-hook #'org-roam--capture-save-file-maybe-h))
|
||||||
|
|
||||||
(defun org-roam--capture-new-file ()
|
(defun org-roam--capture-new-file ()
|
||||||
"Return the path to the new file during an Org-roam capture.
|
"Return the path to the new file during an Org-roam capture.
|
||||||
|
|
||||||
@@ -761,7 +774,18 @@ If the file path already exists, it throw an error.
|
|||||||
|
|
||||||
Else, to insert the header content in the file, org-capture
|
Else, to insert the header content in the file, org-capture
|
||||||
template is prepended with the `:head' portion of the Org-roam
|
template is prepended with the `:head' portion of the Org-roam
|
||||||
capture template."
|
capture template.
|
||||||
|
|
||||||
|
To prevent the creation of a new file if the capture process is
|
||||||
|
aborted, we do the following:
|
||||||
|
|
||||||
|
1. Save the original value of the capture template's :no-save.
|
||||||
|
|
||||||
|
2. Set the capture template's :no-save to t.
|
||||||
|
|
||||||
|
3. Add a function on `org-capture-after-finalize-hook' that saves
|
||||||
|
the file if the original value of :no-save is not t and
|
||||||
|
`org-note-abort' is not t."
|
||||||
(let* ((name-templ (or (org-capture-get :file-name)
|
(let* ((name-templ (or (org-capture-get :file-name)
|
||||||
org-roam--capture-file-name-default))
|
org-roam--capture-file-name-default))
|
||||||
(new-id (s-trim (org-roam--fill-template
|
(new-id (s-trim (org-roam--fill-template
|
||||||
@@ -770,12 +794,14 @@ capture template."
|
|||||||
(file-path (org-roam--file-path-from-id new-id)))
|
(file-path (org-roam--file-path-from-id new-id)))
|
||||||
(when (file-exists-p file-path)
|
(when (file-exists-p file-path)
|
||||||
(error (format "File exists at %s, aborting" file-path)))
|
(error (format "File exists at %s, aborting" file-path)))
|
||||||
|
(org-capture-put :orig-no-save (org-capture-get :no-save))
|
||||||
(org-capture-put :template
|
(org-capture-put :template
|
||||||
(concat
|
(concat
|
||||||
(or (org-capture-get :head)
|
(or (org-capture-get :head)
|
||||||
org-roam--capture-header-default)
|
org-roam--capture-header-default)
|
||||||
(org-capture-get :template))
|
(org-capture-get :template))
|
||||||
:type 'plain)
|
:type 'plain
|
||||||
|
:no-save t)
|
||||||
file-path))
|
file-path))
|
||||||
|
|
||||||
(defun org-roam--expand-capture-template ()
|
(defun org-roam--expand-capture-template ()
|
||||||
@@ -801,7 +827,7 @@ This function is used solely in Org-roam's capture templates: see
|
|||||||
('title
|
('title
|
||||||
(let ((file-path (org-roam--capture-new-file)))
|
(let ((file-path (org-roam--capture-new-file)))
|
||||||
(org-roam--expand-capture-template)
|
(org-roam--expand-capture-template)
|
||||||
(setq org-roam--capture-file-path file-path)
|
(org-capture-put :roam-file-path file-path)
|
||||||
(set-buffer (org-capture-target-buffer file-path))
|
(set-buffer (org-capture-target-buffer file-path))
|
||||||
(widen)
|
(widen)
|
||||||
(goto-char (point-max))))
|
(goto-char (point-max))))
|
||||||
@@ -811,7 +837,7 @@ This function is used solely in Org-roam's capture templates: see
|
|||||||
(file-path (or (cdr (assoc ref completions))
|
(file-path (or (cdr (assoc ref completions))
|
||||||
(org-roam--capture-new-file))))
|
(org-roam--capture-new-file))))
|
||||||
(org-roam--expand-capture-template)
|
(org-roam--expand-capture-template)
|
||||||
(setq org-roam--capture-file-path file-path)
|
(org-capture-put :roam-file-path file-path)
|
||||||
(set-buffer (org-capture-target-buffer file-path))
|
(set-buffer (org-capture-target-buffer file-path))
|
||||||
(widen)
|
(widen)
|
||||||
(goto-char (point-max))))
|
(goto-char (point-max))))
|
||||||
@@ -822,23 +848,31 @@ This function is used solely in Org-roam's capture templates: see
|
|||||||
The templates are defined at `org-roam-capture-templates'. The
|
The templates are defined at `org-roam-capture-templates'. The
|
||||||
GOTO and KEYS argument have the same functionality as
|
GOTO and KEYS argument have the same functionality as
|
||||||
`org-capture'."
|
`org-capture'."
|
||||||
(let ((org-capture-templates org-roam-capture-templates)
|
(let ((org-capture-templates org-roam-capture-templates))
|
||||||
file-path)
|
|
||||||
(when (= (length org-capture-templates) 1)
|
(when (= (length org-capture-templates) 1)
|
||||||
(setq keys (caar org-capture-templates)))
|
(setq keys (caar org-capture-templates)))
|
||||||
(org-capture goto keys)))
|
(org-capture goto keys)))
|
||||||
|
|
||||||
;;; Interactive Commands
|
;;; Interactive Commands
|
||||||
;;;; org-roam-insert
|
;;;; org-roam-insert
|
||||||
(defvar org-roam--capture-insert-point nil
|
|
||||||
"The point to jump to after the call to `org-roam-insert'.")
|
|
||||||
|
|
||||||
(defun org-roam--format-link-title (title)
|
(defun org-roam--format-link-title (title)
|
||||||
"Retur the link title, given the file TITLE."
|
"Retur the link title, given the file TITLE."
|
||||||
(if (functionp org-roam-link-title-format)
|
(if (functionp org-roam-link-title-format)
|
||||||
(funcall org-roam-link-title-format title)
|
(funcall org-roam-link-title-format title)
|
||||||
(format org-roam-link-title-format title)))
|
(format org-roam-link-title-format title)))
|
||||||
|
|
||||||
|
(defun org-roam--format-link (target description)
|
||||||
|
"Formats an org link for a given file TARGET and link DESCRIPTION."
|
||||||
|
(let* ((here (-> (or (buffer-base-buffer)
|
||||||
|
(current-buffer))
|
||||||
|
(buffer-file-name)
|
||||||
|
(file-truename)
|
||||||
|
(file-name-directory))))
|
||||||
|
(format "[[%s][%s]]"
|
||||||
|
(concat "file:"
|
||||||
|
(file-relative-name target here))
|
||||||
|
description)))
|
||||||
|
|
||||||
(defun org-roam-insert (prefix)
|
(defun org-roam-insert (prefix)
|
||||||
"Find an Org-roam file, and insert a relative org link to it at point.
|
"Find an Org-roam file, and insert a relative org link to it at point.
|
||||||
If PREFIX, downcase the title before insertion."
|
If PREFIX, downcase the title before insertion."
|
||||||
@@ -856,49 +890,40 @@ If PREFIX, downcase the title before insertion."
|
|||||||
(title (org-roam--completing-read "File: " completions
|
(title (org-roam--completing-read "File: " completions
|
||||||
:initial-input region-text))
|
:initial-input region-text))
|
||||||
(region-or-title (or region-text title))
|
(region-or-title (or region-text title))
|
||||||
(target-file-path (cdr (assoc title completions)))
|
|
||||||
(current-file-path (-> (or (buffer-base-buffer)
|
(current-file-path (-> (or (buffer-base-buffer)
|
||||||
(current-buffer))
|
(current-buffer))
|
||||||
(buffer-file-name)
|
(buffer-file-name)
|
||||||
(file-truename)
|
(file-truename)
|
||||||
(file-name-directory)))
|
(file-name-directory)))
|
||||||
(buf (current-buffer))
|
(target-file-path (cdr (assoc title completions)))
|
||||||
(p (point-marker)))
|
(link-description (org-roam--format-link-title (if prefix
|
||||||
(unless (and target-file-path
|
(downcase region-or-title)
|
||||||
|
region-or-title))))
|
||||||
|
(if (and target-file-path
|
||||||
(file-exists-p target-file-path))
|
(file-exists-p target-file-path))
|
||||||
|
(progn
|
||||||
|
(when region ;; Remove previously selected text.
|
||||||
|
(delete-region (car region) (cdr region)))
|
||||||
|
(insert (org-roam--format-link target-file-path link-description)))
|
||||||
(let* ((org-roam--capture-info (list (cons 'title title)
|
(let* ((org-roam--capture-info (list (cons 'title title)
|
||||||
(cons 'slug (org-roam--title-to-slug title))))
|
(cons 'slug (org-roam--title-to-slug title))))
|
||||||
(org-roam--capture-context 'title))
|
(org-roam--capture-context 'title))
|
||||||
(org-roam-capture)
|
(add-hook 'org-capture-after-finalize-hook #'org-roam--capture-insert-link-h)
|
||||||
(setq target-file-path org-roam--capture-file-path)
|
(setq org-roam--capture-insert-link-plist (list :region region
|
||||||
(setq org-roam--capture-file-path nil)))
|
:link-description link-description))
|
||||||
(with-current-buffer buf
|
(org-roam-capture)))))
|
||||||
(when region ;; Remove previously selected text.
|
|
||||||
|
(defun org-roam--capture-insert-link-h ()
|
||||||
|
"Inserts the link into the original buffer, after the capture process is done.
|
||||||
|
This is added as a hook to `org-capture-after-finalize-hook'."
|
||||||
|
(when (and (not org-note-abort)
|
||||||
|
org-roam--capture-insert-link-plist)
|
||||||
|
(when-let ((region (plist-get org-roam--capture-insert-link-plist :region))) ;; Remove previously selected text.
|
||||||
(delete-region (car region) (cdr region)))
|
(delete-region (car region) (cdr region)))
|
||||||
(let ((link-location (concat "file:"
|
(insert (org-roam--format-link (org-capture-get :roam-file-path)
|
||||||
(file-relative-name target-file-path
|
(plist-get org-roam--capture-insert-link-plist :link-description)))
|
||||||
current-file-path)))
|
(setq org-roam--capture-insert-link-plist nil))
|
||||||
(description (org-roam--format-link-title (if prefix
|
(remove-hook 'org-capture-after-finalize-hook #'org-roam--capture-insert-link-h))
|
||||||
(downcase region-or-title)
|
|
||||||
region-or-title))))
|
|
||||||
(goto-char p)
|
|
||||||
(insert (format "[[%s][%s]]"
|
|
||||||
link-location
|
|
||||||
description))
|
|
||||||
(setq org-roam--capture-insert-point (point))))
|
|
||||||
(add-hook 'org-capture-after-finalize-hook #'org-roam--capture-advance-point)))
|
|
||||||
|
|
||||||
(defun org-roam--capture-advance-point ()
|
|
||||||
"Advances the point if it is updated.
|
|
||||||
|
|
||||||
We need this function because typically `org-capture' prevents the
|
|
||||||
point from being advanced, whereas when a link is inserted, the
|
|
||||||
point moves some characters forward. This is added as a hook to
|
|
||||||
`org-capture-after-finalize-hook'."
|
|
||||||
(when org-roam--capture-insert-point
|
|
||||||
(goto-char org-roam--capture-insert-point)
|
|
||||||
(setq org-roam--capture-insert-point nil))
|
|
||||||
(remove-hook 'org-capture-after-finalize-hook #'org-roam--capture-advance-point))
|
|
||||||
|
|
||||||
;;;; org-roam-find-file
|
;;;; org-roam-find-file
|
||||||
(defun org-roam--get-title-path-completions ()
|
(defun org-roam--get-title-path-completions ()
|
||||||
@@ -915,13 +940,12 @@ point moves some characters forward. This is added as a hook to
|
|||||||
file-path) res))))
|
file-path) res))))
|
||||||
res))
|
res))
|
||||||
|
|
||||||
(defun org-roam--capture-find-file ()
|
(defun org-roam--capture-find-file-h ()
|
||||||
"Opens the newly created template file.
|
"Opens the newly created template file.
|
||||||
This is added as a hook to `org-capture-after-finalize-hook'."
|
This is added as a hook to `org-capture-after-finalize-hook'."
|
||||||
(when org-roam--capture-file-path
|
(when-let ((file-path (org-capture-get :roam-file-path)))
|
||||||
(find-file org-roam--capture-file-path)
|
(find-file file-path))
|
||||||
(setq org-roam--capture-file-path nil))
|
(remove-hook 'org-capture-after-finalize-hook #'org-roam--capture-find-file-h))
|
||||||
(remove-hook 'org-capture-after-finalize-hook #'org-roam--capture-find-file))
|
|
||||||
|
|
||||||
(defun org-roam-find-file (&optional initial-prompt)
|
(defun org-roam-find-file (&optional initial-prompt)
|
||||||
"Find and open an Org-roam file.
|
"Find and open an Org-roam file.
|
||||||
@@ -936,8 +960,8 @@ INITIAL-PROMPT is the initial title prompt."
|
|||||||
(let* ((org-roam--capture-info (list (cons 'title title)
|
(let* ((org-roam--capture-info (list (cons 'title title)
|
||||||
(cons 'slug (org-roam--title-to-slug title))))
|
(cons 'slug (org-roam--title-to-slug title))))
|
||||||
(org-roam--capture-context 'title))
|
(org-roam--capture-context 'title))
|
||||||
(org-roam-capture)
|
(add-hook 'org-capture-after-finalize-hook #'org-roam--capture-find-file-h)
|
||||||
(add-hook 'org-capture-after-finalize-hook #'org-roam--capture-find-file)))))
|
(org-roam-capture)))))
|
||||||
|
|
||||||
;;;; org-roam-find-ref
|
;;;; org-roam-find-ref
|
||||||
(defun org-roam--get-ref-path-completions ()
|
(defun org-roam--get-ref-path-completions ()
|
||||||
|
Reference in New Issue
Block a user