(feat): Allow one file to have multiple roam_key statements (#1215)

This commit is contained in:
Kisaragi Hiu
2020-11-07 16:33:31 +09:00
committed by GitHub
parent 440461a90b
commit c6797cbd75
8 changed files with 120 additions and 62 deletions

View File

@ -5,6 +5,7 @@
### Features ### Features
- [#1183](https://github.com/org-roam/org-roam/pull/1183) add interactive functions for managing aliases and tags in Org-roam file, namely `org-roam-alias-add`, `org-roam-alias-delete`, `org-roam-tag-add`, and `org-roam-tag-delete`. - [#1183](https://github.com/org-roam/org-roam/pull/1183) add interactive functions for managing aliases and tags in Org-roam file, namely `org-roam-alias-add`, `org-roam-alias-delete`, `org-roam-tag-add`, and `org-roam-tag-delete`.
- [#1215](https://github.com/org-roam/org-roam/pull/1215) Multiple `ROAM_KEY` keywords can now be specified in one file. This allows bibliographical entries to share the same note file.
- [#1238](https://github.com/org-roam/org-roam/pull/1238) add `org-roam-prefer-id-links` variable to select linking method - [#1238](https://github.com/org-roam/org-roam/pull/1238) add `org-roam-prefer-id-links` variable to select linking method
### Bugfixes ### Bugfixes

View File

@ -47,7 +47,7 @@
(defvar org-roam--org-link-bracket-typed-re) (defvar org-roam--org-link-bracket-typed-re)
(declare-function org-roam-db--ensure-built "org-roam-db") (declare-function org-roam-db--ensure-built "org-roam-db")
(declare-function org-roam--extract-ref "org-roam") (declare-function org-roam--extract-refs "org-roam")
(declare-function org-roam--extract-titles "org-roam") (declare-function org-roam--extract-titles "org-roam")
(declare-function org-roam--get-title-or-slug "org-roam") (declare-function org-roam--get-title-or-slug "org-roam")
(declare-function org-roam--get-backlinks "org-roam") (declare-function org-roam--get-backlinks "org-roam")
@ -149,10 +149,11 @@ ORIG-PATH is the path where the CONTENT originated."
(defun org-roam-buffer--insert-ref-links () (defun org-roam-buffer--insert-ref-links ()
"Insert ref backlinks for the current buffer." "Insert ref backlinks for the current buffer."
(when-let ((path (cdr (with-temp-buffer (when-let* ((refs (with-temp-buffer
(insert-buffer-substring org-roam-buffer--current) (insert-buffer-substring org-roam-buffer--current)
(org-roam--extract-ref))))) (org-roam--extract-refs)))
(if-let* ((key-backlinks (org-roam--get-backlinks path)) (paths (mapcar #'cdr refs)))
(if-let* ((key-backlinks (mapcan #'org-roam--get-backlinks paths))
(grouped-backlinks (--group-by (nth 0 it) key-backlinks))) (grouped-backlinks (--group-by (nth 0 it) key-backlinks)))
(progn (progn
(insert (let ((l (length key-backlinks))) (insert (let ((l (length key-backlinks)))
@ -163,8 +164,8 @@ ORIG-PATH is the path where the CONTENT originated."
(bls (cdr group))) (bls (cdr group)))
(insert (format "** %s\n" (insert (format "** %s\n"
(org-roam-format-link file-from (org-roam-format-link file-from
(org-roam--get-title-or-slug file-from) (org-roam--get-title-or-slug file-from)
"file"))) "file")))
(dolist (backlink bls) (dolist (backlink bls)
(pcase-let ((`(,file-from _ ,props) backlink)) (pcase-let ((`(,file-from _ ,props) backlink))
(insert (if-let ((content (plist-get props :content))) (insert (if-let ((content (plist-get props :content)))

View File

@ -50,7 +50,7 @@
(declare-function org-roam--org-roam-file-p "org-roam") (declare-function org-roam--org-roam-file-p "org-roam")
(declare-function org-roam--extract-titles "org-roam") (declare-function org-roam--extract-titles "org-roam")
(declare-function org-roam--extract-ref "org-roam") (declare-function org-roam--extract-refs "org-roam")
(declare-function org-roam--extract-tags "org-roam") (declare-function org-roam--extract-tags "org-roam")
(declare-function org-roam--extract-ids "org-roam") (declare-function org-roam--extract-ids "org-roam")
(declare-function org-roam--extract-links "org-roam") (declare-function org-roam--extract-links "org-roam")
@ -274,34 +274,35 @@ Returns the number of rows inserted."
rows) rows)
(length rows))) (length rows)))
(defun org-roam-db--insert-ref (&optional update-p) (defun org-roam-db--insert-refs (&optional update-p)
"Update the ref of the current buffer into the cache. "Update the refs of the current buffer into the cache.
If UPDATE-P is non-nil, first remove the ref for the file in the database." If UPDATE-P is non-nil, first remove the ref for the file in the database."
(let ((file (or org-roam-file-name (buffer-file-name)))) (let ((file (or org-roam-file-name (buffer-file-name)))
(count 0))
(when update-p (when update-p
(org-roam-db-query [:delete :from refs (org-roam-db-query [:delete :from refs
:where (= file $s1)] :where (= file $s1)]
file)) file))
(if-let ((ref (org-roam--extract-ref))) (when-let ((refs (org-roam--extract-refs)))
(let ((key (cdr ref)) (dolist (ref refs)
(type (car ref))) (let ((key (cdr ref))
(condition-case nil (type (car ref)))
(progn (condition-case nil
(org-roam-db-query (progn
[:insert :into refs :values $v1] (org-roam-db-query
(list (vector key file type))) [:insert :into refs :values $v1]
1) (list (vector key file type)))
(error (cl-incf count))
(lwarn '(org-roam) :error (error
(format "Duplicate ref %s in:\n\nA: %s\nB: %s\n\nskipping..." (lwarn '(org-roam) :error
key (format "Duplicate ref %s in:\n\nA: %s\nB: %s\n\nskipping..."
file key
(caar (org-roam-db-query file
[:select file :from refs (caar (org-roam-db-query
:where (= ref $v1)] [:select file :from refs
(vector key))))) :where (= ref $v1)]
0))) (vector key))))))))))
0))) count))
(defun org-roam-db--insert-links (&optional update-p) (defun org-roam-db--insert-links (&optional update-p)
"Update the file links of the current buffer in the cache. "Update the file links of the current buffer in the cache.
@ -473,7 +474,7 @@ If the file exists, update the cache with information."
(org-roam-db--insert-meta 'update) (org-roam-db--insert-meta 'update)
(org-roam-db--insert-tags 'update) (org-roam-db--insert-tags 'update)
(org-roam-db--insert-titles 'update) (org-roam-db--insert-titles 'update)
(org-roam-db--insert-ref 'update) (org-roam-db--insert-refs 'update)
(when org-roam-enable-headline-linking (when org-roam-enable-headline-linking
(org-roam-db--insert-ids 'update)) (org-roam-db--insert-ids 'update))
(org-roam-db--insert-links 'update))))) (org-roam-db--insert-links 'update)))))
@ -538,7 +539,7 @@ If FORCE, force a rebuild of the cache from scratch."
(setq link-count (+ link-count (org-roam-db--insert-links))) (setq link-count (+ link-count (org-roam-db--insert-links)))
(setq tag-count (+ tag-count (org-roam-db--insert-tags))) (setq tag-count (+ tag-count (org-roam-db--insert-tags)))
(setq title-count (+ title-count (org-roam-db--insert-titles))) (setq title-count (+ title-count (org-roam-db--insert-titles)))
(setq ref-count (+ ref-count (org-roam-db--insert-ref)))) (setq ref-count (+ ref-count (org-roam-db--insert-refs))))
(file-error (file-error
(setq org-roam-files (remove file org-roam-files)) (setq org-roam-files (remove file org-roam-files))
(org-roam-db--clear-file file) (org-roam-db--clear-file file)

View File

@ -512,22 +512,30 @@ Use external shell commands if defined in `org-roam-list-files-commands'."
;;;; Org extraction functions ;;;; Org extraction functions
(defun org-roam--extract-global-props (props) (defun org-roam--extract-global-props (props)
"Extract PROPS from the current org buffer. "Extract PROPS from the current org buffer."
The search terminates when the first property is encountered." (let ((collected
(if (functionp 'org-collect-keywords) ;; Collect the raw props first
(->> (org-collect-keywords props) ;; It'll be returned in the form of
;; convert (("TITLE" "my title")) to (("TITLE" . "my title")) ;; (("PROP" "value" ...) ("PROP2" "value" ...))
(mapcar (pcase-lambda (`(,k ,v)) (cons k v)))) (if (functionp 'org-collect-keywords)
(let ((buf (org-element-parse-buffer)) (org-collect-keywords props)
res) (let ((buf (org-element-parse-buffer))
(dolist (prop props) res)
(let ((p (org-element-map buf 'keyword (dolist (prop props)
(lambda (kw) (let ((p (org-element-map buf 'keyword
(when (string-equal (org-element-property :key kw) prop) (lambda (kw)
(org-element-property :value kw))) (when (string-equal (org-element-property :key kw) prop)
:first-match t))) (org-element-property :value kw)))
(push (cons prop p) res))) :first-match nil)))
res))) (push (cons prop p) res)))
res))))
;; convert (("TITLE" "a" "b") ("Another" "c"))
;; to (("TITLE" . "a") ("TITLE" . "b") ("Another" . "c"))
(let (ret)
(pcase-dolist (`(,key . ,values) collected)
(dolist (value values)
(push (cons key value) ret)))
ret)))
(defun org-roam--get-outline-path () (defun org-roam--get-outline-path ()
"Return the outline path to the current entry. "Return the outline path to the current entry.
@ -763,20 +771,30 @@ backlinks."
"website") "website")
(t type))) (t type)))
(defun org-roam--extract-refs ()
"Extract all refs (ROAM_KEY statements) from the current buffer.
Each ref is returned as a cons of its type and its key."
(let (refs)
(pcase-dolist
(`(,_ . ,roam-key)
(org-roam--extract-global-props '("ROAM_KEY")))
(let (type path)
(pcase roam-key
('nil nil)
((pred string-empty-p)
(user-error "Org property #+roam_key cannot be empty"))
(ref
(when (string-match org-link-plain-re ref)
(setq type (org-roam--collate-types (match-string 1 ref))
path (match-string 2 ref)))))
(when (and type path)
(push (cons type path) refs))))
refs))
(defun org-roam--extract-ref () (defun org-roam--extract-ref ()
"Extract the ref from current buffer and return the type and the key of the ref." "Extract the ref from current buffer and return the type and the key of the ref."
(let (type path) (car (org-roam--extract-refs)))
(pcase (cdr (assoc "ROAM_KEY"
(org-roam--extract-global-props '("ROAM_KEY"))))
('nil nil)
((pred string-empty-p)
(user-error "Org property #+roam_key cannot be empty"))
(ref
(when (string-match org-link-plain-re ref)
(setq type (org-roam--collate-types (match-string 1 ref))
path (match-string 2 ref)))))
(when (and type path)
(cons type path))))
;;;; Title/Path/Slug conversion ;;;; Title/Path/Slug conversion
(defun org-roam--path-to-slug (path) (defun org-roam--path-to-slug (path)

View File

@ -0,0 +1 @@
#+roam_key: cite:mitsuha2007

View File

@ -0,0 +1,2 @@
#+roam_key: https://www.orgroam.com/
#+roam_key: cite:orgroam2020

View File

@ -45,7 +45,7 @@
(pcase (benchmark-run 1 (org-roam-db-build-cache t)) (pcase (benchmark-run 1 (org-roam-db-build-cache t))
(`(,time ,gcs ,time-in-gc) (`(,time ,gcs ,time-in-gc)
(message "Elapsed time: %fs (%fs in %d GCs)" time time-in-gc gcs) (message "Elapsed time: %fs (%fs in %d GCs)" time time-in-gc gcs)
(expect time :to-be-less-than 100)))) (expect time :to-be-less-than 110))))
(it "builds quickly without change" (it "builds quickly without change"
(pcase (benchmark-run 1 (org-roam-db-build-cache)) (pcase (benchmark-run 1 (org-roam-db-build-cache))
(`(,time ,gcs ,time-in-gc) (`(,time ,gcs ,time-in-gc)

View File

@ -71,6 +71,40 @@
(expect (org-roam--str-to-list "\"hello") (expect (org-roam--str-to-list "\"hello")
:to-throw))) :to-throw)))
(describe "Ref extraction"
(before-all
(test-org-roam--init))
(after-all
(test-org-roam--teardown))
(cl-flet
((test (fn file)
(let* ((fname (test-org-roam--abs-path file))
(buf (find-file-noselect fname)))
(with-current-buffer buf
;; Unlike tag extraction, it doesn't make sense to
;; pass a filename.
(funcall fn)))))
;; Enable "cite:" link parsing
(org-link-set-parameters "cite")
(it "extracts web keys"
(expect (test #'org-roam--extract-ref
"web_ref.org")
:to-equal
'("website" . "//google.com/")))
(it "extracts cite keys"
(expect (test #'org-roam--extract-ref
"cite_ref.org")
:to-equal
'("cite" . "mitsuha2007")))
(it "extracts all keys"
(expect (test #'org-roam--extract-refs
"multiple-refs.org")
:to-have-same-items-as
'(("cite" . "orgroam2020")
("website" . "//www.orgroam.com/"))))))
(describe "Title extraction" (describe "Title extraction"
:var (org-roam-title-sources) :var (org-roam-title-sources)
(before-all (before-all