(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:
Jethro Kuan
2020-03-17 17:06:49 +08:00
committed by GitHub
parent 81dd880357
commit 8f8ccf6797

View File

@@ -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 ()