(fix): fix fuzzy link completions (#1022)

This commit is contained in:
Jethro Kuan 2020-08-10 15:38:17 +08:00 committed by GitHub
parent 8c442a72de
commit 9753ee451f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 65 deletions

View file

@ -1089,11 +1089,14 @@ This function hooks into `org-open-at-point' via
nil)))))
;;; Completion at point
(defconst org-roam-open-bracket-regexp
"\\[\\[\\([^\]]*\\)")
(defconst org-roam-title-headline-split-regexp
"\\([^\*]*\\)\\(\*?\\)\\([^\]]*\\)")
(defconst org-roam-fuzzy-link-regexp
(rx (seq "[["
(group
(zero-or-more
(or (not (any "[]\\"))
(and "\\" (zero-or-more "\\\\") (any "[]"))
(and (one-or-more "\\") (not (any "[]"))))))
"]]")))
(defun org-roam-complete-at-point ()
"Do appropriate completion for the thing at point."
@ -1112,41 +1115,31 @@ This function hooks into `org-open-at-point' via
exit-fn (lambda (str _status)
(delete-char (- (length str)))
(insert "\"" str "\""))))
(;; In an open bracket
(looking-back (concat "^.*" org-roam-open-bracket-regexp) (line-beginning-position))
(;; In a fuzzy link
(org-in-regexp org-roam-fuzzy-link-regexp)
(setq start (match-beginning 1)
end (match-end 1))
(save-match-data
(save-excursion
(goto-char start)
(when (looking-at (concat org-roam-title-headline-split-regexp "\]\]"))
(let ((title (match-string-no-properties 1))
(has-headline-p (not (string-empty-p (match-string-no-properties 2))))
(headline-start (match-beginning 3)))
(cond (;; title and headline present
(and (not (string-empty-p title))
has-headline-p)
(when-let ((file (org-roam--get-file-from-title title t)))
(setq collection (apply-partially #'org-roam--get-headlines file))
(setq start headline-start)))
(;; Only title
(not has-headline-p)
(setq collection #'org-roam--get-titles))
(;; Only headline
(string-empty-p title)
has-headline-p
(setq collection #'org-roam--get-headlines)
(setq start headline-start)))))))))
(when collection
(let ((prefix (buffer-substring-no-properties start end)))
(list start end
(if (functionp collection)
(completion-table-dynamic
(lambda (_)
(cl-remove-if (apply-partially 'string= prefix) (funcall collection))))
collection)
:exit-function exit-fn
'ignore)))))
(pcase-let ((`(,type ,title _ ,star-idx)
(org-roam--split-fuzzy-link (match-string-no-properties 1))))
(pcase type
('title+headline
(when-let ((file (org-roam--get-file-from-title title t)))
(setq collection (apply-partially #'org-roam--get-headlines file))
(setq start (+ start star-idx 1))))
('title
(setq collection #'org-roam--get-titles))
('headline
(setq collection #'org-roam--get-headlines)
(setq start (+ start star-idx 1)))))))
(when collection
(let ((prefix (buffer-substring-no-properties start end)))
(list start end
(if (functionp collection)
(completion-table-dynamic
(lambda (_)
(cl-remove-if (apply-partially 'string= prefix) (funcall collection))))
collection)
:exit-function exit-fn)))))
;;; Fuzzy Links
(defcustom org-roam-auto-replace-fuzzy-links t
@ -1156,12 +1149,23 @@ This function hooks into `org-open-at-point' via
(defun org-roam--split-fuzzy-link (link)
"Splits LINK into title and headline.
Return a list of the form (title has-headline-p headline), nil otherwise."
Return a list of the form (type title has-headline-p headline star-idx).
type is one of `title', `headline', `title+headline'.
title is the title component of the link.
headline is the headline component of the link.
star-idx is the index of the asterisk, if any."
(save-match-data
(when (string-match org-roam-title-headline-split-regexp link)
(list (match-string-no-properties 1 link)
(not (string-empty-p (match-string-no-properties 2 link)))
(match-string-no-properties 3 link)))))
(let* ((star-index (string-match-p "\\*" link))
(title (substring-no-properties link 0 star-index))
(headline (if star-index
(substring-no-properties link (+ 1 star-index))
""))
(type (cond ((not star-index)
'title)
((= 0 star-index)
'headline)
(t 'title+headline))))
(list type title headline star-index))))
(defun org-roam--get-titles ()
"Return all titles within Org-roam."
@ -1248,14 +1252,11 @@ nil is returned if there is no matching location.
link-type is either \"file\" or \"id\".
loc is the target location: e.g. a file path, or an id.
marker is a marker to the headline, if applicable."
(let ((splits (org-roam--split-fuzzy-link link))
mkr link-type desc loc)
(when splits
(pcase-let ((`(,title ,has-headline-p ,headline) splits))
(cond (;; title and headline present
(and (not (string-empty-p title))
has-headline-p)
(let ((file (org-roam--get-file-from-title title)))
(let (mkr link-type desc loc)
(pcase-let ((`(,type ,title ,headline _) (org-roam--split-fuzzy-link link)))
(pcase type
('title+headline
(let ((file (org-roam--get-file-from-title title)))
(if (not file)
(org-roam-message "Cannot find matching file")
(setq mkr (org-roam--get-id-from-headline headline file))
@ -1266,24 +1267,21 @@ marker is a marker to the headline, if applicable."
link-type "id"
desc headline))
(_ (org-roam-message "cannot find matching id"))))))
(;; Only title
(not has-headline-p)
(setq loc (org-roam--get-file-from-title title)
('title
(setq loc (org-roam--get-file-from-title title)
desc title
link-type "file")
(when loc (setq loc (file-relative-name loc))))
(;; Only headline
(and (string-empty-p title)
has-headline-p)
(setq mkr (org-roam--get-id-from-headline headline))
(pcase mkr
(when loc (setq loc (file-relative-name loc))))
('headline
(setq mkr (org-roam--get-id-from-headline headline))
(pcase mkr
(`(,marker . ,target-id)
(setq mkr marker
loc target-id
desc headline
link-type "id"))
(_ (org-roam-message "Cannot find matching headline")))))
(list link-type loc desc mkr)))))
(list link-type loc desc mkr))))
(defun org-roam--open-fuzzy-link (link)
"Open a Org fuzzy LINK.

View file

@ -260,22 +260,26 @@
["801b58eb-97e2-435f-a33e-ff59a2f0c213" ,(test-org-roam--abs-path "headlines/headline.org")])))))
(describe "Test fuzzy links"
(it ""
(expect (org-roam--split-fuzzy-link "")
:to-equal
'(title "" "" nil)))
(it "title"
(expect (org-roam--split-fuzzy-link "title")
:to-equal
'("title" nil "")))
'(title "title" "" nil)))
(it "title*"
(expect (org-roam--split-fuzzy-link "title*")
:to-equal
'("title" t "")))
'(title+headline "title" "" 5)))
(it "title*headline"
(expect (org-roam--split-fuzzy-link "title*headline")
:to-equal
'("title" t "headline")))
'(title+headline "title" "headline" 5)))
(it "*headline"
(expect (org-roam--split-fuzzy-link "*headline")
:to-equal
'("" t "headline"))))
'(headline "" "headline" 0))))
;;; Tests
(xdescribe "org-roam-db-build-cache"