(feat): add org-roam-unlinked-references (#787)

`org-roam-unlinked-references` uses rg to search for unlinked references. Regex courtesy of @angelsl.

Co-authored-by: Leo Vivier <leo.vivier+dev@gmail.com>
This commit is contained in:
Jethro Kuan
2020-06-12 23:21:01 +08:00
committed by GitHub
parent 278e3df95d
commit 48158e67d4
2 changed files with 88 additions and 0 deletions

View File

@ -6,6 +6,8 @@ In this release, we improved the linking process by achieving feature parity bet
This is a major step forward. Supporting the in-file structure of Org-mode files means that we can interface with many of its core-features like TODOs, properties, priorities, etc. UX will have to be figured out, but this release ushers in a new age in terms of functionalities.
We also add `org-roam-unlinked-references`, which naively finds text that could be references to the current Org-roam file.
### Breaking Changes
- [#701](https://github.com/org-roam/org-roam/pull/701) Use `emacsql-sqlite3` instead of `emacsql-sqlite` for better Windows compatibility. This requires the presence of the standard `sqlite3` binary on your machine.
@ -13,6 +15,7 @@ This is a major step forward. Supporting the in-file structure of Org-mode files
### Features
- [#787](https://github.com/org-roam/org-roam/pull/787) Add `org-roam-unlinked-references`
- [#783](https://github.com/org-roam/org-roam/pull/783) Add support for headlines
- [#757](https://github.com/org-roam/org-roam/pull/757) Roam global properties are now case-insensitive
- [#680](https://github.com/org-roam/org-roam/pull/680) , [#703](https://github.com/org-roam/org-roam/pull/703), [#708](https://github.com/org-roam/org-roam/pull/708) Add `org-roam-doctor` checkers for `ROAM_*` properties

View File

@ -42,6 +42,7 @@
(require 'cl-lib)
(require 'dash)
(require 'f)
(require 'rx)
(require 's)
(require 'seq)
(eval-when-compile (require 'subr-x))
@ -1230,6 +1231,7 @@ Otherwise, behave as if called interactively."
(lwarn '(org-roam) :error "Cannot find executable 'sqlite3'. \
Ensure it is installed and can be found within `exec-path'. \
M-x info for more information at Org-roam > Installation > Post-Installation Tasks."))
(add-to-list 'org-execute-file-search-functions 'org-roam--execute-file-row-col)
(add-hook 'find-file-hook #'org-roam--find-file-hook-function)
(add-hook 'kill-emacs-hook #'org-roam-db--close-all)
(add-hook 'org-open-at-point-functions #'org-roam-open-id-at-point)
@ -1237,6 +1239,7 @@ M-x info for more information at Org-roam > Installation > Post-Installation Tas
(advice-add 'delete-file :before #'org-roam--delete-file-advice)
(org-roam-db-build-cache))
(t
(setq org-execute-file-search-functions (delete 'org-roam--execute-file-row-col org-execute-file-search-functions))
(remove-hook 'find-file-hook #'org-roam--find-file-hook-function)
(remove-hook 'kill-emacs-hook #'org-roam-db--close-all)
(remove-hook 'org-open-at-point-functions #'org-roam-open-id-at-point)
@ -1408,6 +1411,88 @@ command will offer you to create one."
:require-match t)))
(switch-to-buffer (cdr (assoc name names-and-buffers))))))
(defun org-roam--execute-file-row-col (s)
"Move to row:col if S match the row:col syntax. To be used with `org-execute-file-search-functions'."
(when (string-match (rx (group (1+ digit))
":"
(group (1+ digit))) s)
(let ((row (string-to-number (match-string 1 s)))
(col (string-to-number (match-string 2 s))))
(org-goto-line row)
(move-to-column (- col 1))
t)))
;;###autoload
(defun org-roam-unlinked-references ()
"Check for unlinked references in the current buffer.
The check here is naive: it uses a regex that detects for
strict (case-insensitive) occurrences of possible titles (see
`org-roam--extract-titles'), and shows them in a buffer. This
means that the results can be noisy, and may not truly indicate
an unlinked reference.
Users are encouraged to think hard about whether items should be
linked, lest the network graph get too crowded."
(interactive)
(unless (org-roam--org-roam-file-p)
(user-error "Not in org-roam file"))
(if (not (executable-find "rg"))
(user-error "Cannot find the \"rg\" executable, aborting")
(let* ((titles (org-roam--extract-titles))
(rg-command (concat "rg -o --vimgrep -P -i "
(string-join (mapcar (lambda (glob) (concat "-g " glob))
(org-roam--list-files-search-globs org-roam-file-extensions)) " ")
(format " '\\[([^[]]++|(?R))*\\]%s' "
(mapconcat (lambda (title)
(format "|(\\b%s\\b)" (shell-quote-argument title)))
titles ""))
org-roam-directory))
(file-loc (buffer-file-name))
(buf (get-buffer-create "*org-roam unlinked references*"))
(results (split-string (shell-command-to-string rg-command) "\n"))
(result-regex (rx (group (one-or-more anychar))
":"
(group (one-or-more digit))
":"
(group (one-or-more digit))
":"
(group (zero-or-more anything)))))
(pop-to-buffer buf)
(let ((inhibit-read-only t))
(erase-buffer)
(org-mode)
(insert (propertize (car titles) 'font-lock-face 'org-document-title) "\n\n"
"* Unlinked References\n")
(dolist (line results)
(save-match-data
(when (string-match result-regex line)
(let ((file (match-string 1 line))
(row (match-string 2 line))
(col (match-string 3 line))
(match (match-string 4 line)))
(when (and match
(member (downcase match) (mapcar #'downcase titles))
(not (f-equal-p (expand-file-name file org-roam-directory)
file-loc)))
(let ((rowcol (concat row ":" col)))
(insert "- "
(org-link-make-string (concat "file:" file "::" rowcol)
(format "[%s] %s" rowcol (org-roam--get-title-or-slug file))))
(when (executable-find "sed") ; insert line contents when sed is available
(insert " :: "
(shell-command-to-string
(concat "sed -n "
row
"p "
file))))
(insert "\n")))))))
(read-only-mode +1)
(dolist (title titles)
(highlight-phrase (downcase title) 'bold-italic))
(goto-char (point-min))))))
;;;###autoload
(defun org-roam-version (&optional message)
"Return `org-roam' version.