[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/denote 0665a1e367 6/6: Merge branch 'xref-refinement-pr
From: |
ELPA Syncer |
Subject: |
[elpa] externals/denote 0665a1e367 6/6: Merge branch 'xref-refinement-project-integration' |
Date: |
Mon, 21 Nov 2022 22:57:31 -0500 (EST) |
branch: externals/denote
commit 0665a1e367bfd16991b928617ce27b20bdd0d607
Merge: 22829d8541 0a94f3e3c3
Author: Protesilaos Stavrou <info@protesilaos.com>
Commit: Protesilaos Stavrou <info@protesilaos.com>
Merge branch 'xref-refinement-project-integration'
---
denote-org-dblock.el | 3 +-
denote.el | 216 ++++++++++++++++++++++++++++++++-------------------
2 files changed, 139 insertions(+), 80 deletions(-)
diff --git a/denote-org-dblock.el b/denote-org-dblock.el
index 9b1714f9b1..111fbb7c6a 100644
--- a/denote-org-dblock.el
+++ b/denote-org-dblock.el
@@ -139,8 +139,7 @@ Used by `org-dblock-update' with PARAMS provided by the
dynamic block."
Used by `org-dblock-update' with PARAMS provided by the dynamic block."
(when-let* ((file (buffer-file-name))
(id (denote-retrieve-filename-identifier file))
- (files (denote--retrieve-files-in-xrefs
- (denote--retrieve-process-grep id))))
+ (files (delete file (denote--retrieve-files-in-xrefs id)))))
(insert (denote-link--prepare-links files file nil))
(join-line))) ;; remove trailing empty line
diff --git a/denote.el b/denote.el
index a6c26fe7d1..e24a1db9bf 100644
--- a/denote.el
+++ b/denote.el
@@ -661,7 +661,8 @@ value, as explained in its doc string."
((when-let ((regexp denote-excluded-directories-regexp))
(not (string-match-p regexp f))))
((file-readable-p f))
- (t)))))))
+ (t)))
+ :follow-symlinks))))
(defun denote-directory-text-only-files ()
"Return list of text files in variable `denote-directory'.
@@ -696,7 +697,11 @@ whatever matches `denote-excluded-directories-regexp'."
"Return absolute path of ID string in `denote-directory-files'."
(seq-find
(lambda (f)
- (string-prefix-p id (file-name-nondirectory f)))
+ (and (string-prefix-p id (file-name-nondirectory f))
+ ;; The directory can contain exported html and other
+ ;; derivative files that have the same name sans extetion as
+ ;; the note.
+ (denote-file-is-note-p f)))
(denote-directory-files)))
(define-obsolete-function-alias
@@ -719,10 +724,13 @@ whatever matches `denote-excluded-directories-regexp'."
(defun denote-file-prompt (&optional initial-text)
"Prompt for file with identifier in variable `denote-directory'.
With optional INITIAL-TEXT, use it to prepopulate the minibuffer."
- (read-file-name "Select note: " (denote-directory) nil nil initial-text
- (lambda (f)
- (or (denote-file-has-identifier-p f)
- (denote-file-directory-p f)))))
+ (let* ((project-find-functions #'denote-project-find)
+ (project (project-current nil (denote-directory)))
+ (dirs (list (project-root project)))
+ (all-files (project-files project dirs))
+ (completion-ignore-case read-file-name-completion-ignore-case))
+ (funcall project-read-file-name-function
+ "Select note: " all-files nil 'denote--title-history
initial-text)))
(define-obsolete-function-alias
'denote--retrieve-read-file-prompt
@@ -1245,50 +1253,16 @@ Run `denote-desluggify' on title if the extraction is
sucessful."
title
(denote-retrieve-filename-title file)))
-(defun denote--retrieve-xrefs (identifier &optional file)
- "Return xrefs of IDENTIFIER in variable `denote-directory'.
-The xrefs are returned as an alist of the form:
-
- ((GROUP . (XREF ...)) ...)
-
-GROUP is an absolute file name as retrieved by Xref facility.
-
-When FILE is present, remove its GROUP from the alist."
- (let ((alist
- (xref--alistify
- (xref-matches-in-files identifier (denote-directory-text-only-files))
- (lambda (x)
- (xref-location-group (xref-item-location x))))))
- (if file (assoc-delete-all file alist) alist)))
-
-(defun denote--retrieve-files-in-xrefs (xref-alist)
- "Return sorted, deduplicated file names from XREF-ALIST."
+(defun denote--retrieve-files-in-xrefs (identifier)
+ "Return sorted, deduplicated file names from IDENTIFIER."
(sort
- (delete-dups (mapcar #'car xref-alist))
+ (delete-dups
+ (mapcar #'xref-location-group
+ (mapcar #'xref-match-item-location
+ (xref-matches-in-files identifier
+
(denote-directory-text-only-files)))))
#'string-lessp))
-(defun denote--retrieve-process-grep (identifier)
- "Process lines matching IDENTIFIER and return list of xref-alist.
-
-The alist is of the form ((GROUP . (XREF ...)) ...).
-
-The alist excludes GROUP for the file that current buffer is
-visiting so that only its backlinks are colleced.
-
-In addition, GROUP is a transformed to filename relative to
-variable `denote-directory', which is the string displayed in the
-backlinks' buffer."
- ;;; This `mapcar' form is doing what function `xref--analyze' would
- ;;; do. `xref--analyze' can be flexibly configured but is not used
- ;;; directly here because it assumes that the current directory is in
- ;;; a "project" as defined in project.el. For Denote, this is not the
- ;;; case (at least as at the time of this writing).
- (mapcar
- (lambda (xref)
- (cons (denote-get-file-name-relative-to-denote-directory (car xref))
- (cdr xref)))
- (denote--retrieve-xrefs identifier (buffer-file-name))))
-
;;;; New note
;;;;; Common helpers for new notes
@@ -1726,13 +1700,6 @@ set to \\='(template title keywords)."
(string-match (denote-directory) title)
(substring title (match-end 0))))
-(defun denote--push-extracted-title-to-history ()
- "Add `denote--extract-title-from-file-history' to `denote--title-history'."
- (when-let* ((last-input (denote--extract-title-from-file-history))
- ((not (string-empty-p last-input)))
- ((not (string-blank-p last-input))))
- (push last-input denote--title-history)))
-
;;;###autoload
(defun denote-open-or-create (target)
"Visit TARGET file in variable `denote-directory'.
@@ -1747,7 +1714,6 @@ note's actual title. At the `denote-title-prompt' type
(interactive (list (denote-file-prompt)))
(if (file-exists-p target)
(find-file target)
- (denote--push-extracted-title-to-history)
(call-interactively #'denote)))
;;;###autoload
@@ -2635,9 +2601,7 @@ Like `denote-link-find-file', but select backlink to
follow."
(interactive)
(if-let* ((file (buffer-file-name))
(id (denote-retrieve-filename-identifier file))
- (files
- (denote--retrieve-files-in-xrefs
- (denote--retrieve-xrefs id (buffer-file-name)))))
+ (files (delete file (denote--retrieve-files-in-xrefs id))))
(find-file
(denote-get-path-by-id
(denote-extract-id-from-string
@@ -2694,7 +2658,6 @@ file's title. This has the same meaning as in
`denote-link'."
(interactive (list (denote-file-prompt) current-prefix-arg))
(if (file-exists-p target)
(denote-link target id-only)
- (denote--push-extracted-title-to-history)
(call-interactively #'denote-link-after-creating)))
(defalias 'denote-link-to-existing-or-new-note (symbol-function
'denote-link-or-create))
@@ -2823,24 +2786,37 @@ nil)."
(define-derived-mode denote-backlinks-mode xref--xref-buffer-mode "Backlinks"
"Major mode for backlinks buffers."
(unless denote-backlinks-show-context
- (font-lock-add-keywords nil denote-faces-file-name-keywords-for-backlinks
t)))
+ (font-lock-add-keywords nil denote-faces-file-name-keywords-for-backlinks
t))
+ (add-hook 'project-find-functions #'denote-project-find nil t))
(make-obsolete-variable 'denote-backlink-mode 'denote-backlinks-mode "0.6.0")
-(defun denote-link--prepare-backlinks (id xref-alist &optional title)
- "Create backlinks' buffer for ID using XREF-ALIST.
-Use optional TITLE for a prettier heading."
- (let ((inhibit-read-only t)
- (buf (format "*denote-backlinks to %s*" id))
- (file (buffer-file-name)))
+(defun denote-link--prepare-backlinks (fetcher _alist)
+ "Create backlinks' buffer for the current note.
+FETCHER is a function that fetches a list of xrefs. It is called
+with `funcall' with no argument like `xref--fetcher'.
+
+In the case of `denote', `apply-partially' is used to create a
+function that has already applied another function to multiple
+arguments.
+
+ALIST is not used in favour of using
+`denote-link-backlinks-display-buffer-action'."
+ (let* ((inhibit-read-only t)
+ (file (buffer-file-name))
+ (file-type (denote-filetype-heuristics file))
+ (id (denote-retrieve-filename-identifier file))
+ (buf (format "*denote-backlinks to %s*" id))
+ (xref-alist (xref--analyze (funcall fetcher))))
(with-current-buffer (get-buffer-create buf)
(setq-local default-directory (denote-directory))
(erase-buffer)
+ (setq overlay-arrow-position nil)
(denote-backlinks-mode)
(goto-char (point-min))
- (when-let* ((title)
- (heading (format "Backlinks to %S (%s)" title id))
- (l (length heading)))
+ (when-let* ((title (denote-retrieve-title-value file file-type))
+ (heading (format "Backlinks to %S (%s)" title id))
+ (l (length heading)))
(insert (format "%s\n%s\n\n" heading (make-string l ?-))))
(if denote-backlinks-show-context
(xref--insert-xrefs xref-alist)
@@ -2852,9 +2828,11 @@ Use optional TITLE for a prettier heading."
(goto-char (point-min))
(setq-local revert-buffer-function
(lambda (_ignore-auto _noconfirm)
- (when-let ((buffer-file-name file)
- (xref-alist (denote--retrieve-process-grep id)))
- (denote-link--prepare-backlinks id xref-alist title)))))
+ (when-let ((buffer-file-name file))
+ (denote-link--prepare-backlinks
+ (apply-partially #'xref-matches-in-files id
+ (delete file
(denote-directory-text-only-files)))
+ nil)))))
(denote-link--display-buffer buf)))
;;;###autoload
@@ -2875,12 +2853,14 @@ default, it will show up below the current window."
(let ((file (buffer-file-name)))
(when (denote-file-is-writable-and-supported-p file)
(let* ((id (denote-retrieve-filename-identifier file))
- (file-type (denote-filetype-heuristics file))
- (title (denote-retrieve-title-value file file-type)))
- (if-let ((xref-alist (denote--retrieve-process-grep id)))
- (progn (xref--push-markers)
- (denote-link--prepare-backlinks id xref-alist title))
- (user-error "No links to the current note"))))))
+ (xref-show-xrefs-function #'denote-link--prepare-backlinks)
+ (project-find-functions #'denote-project-find))
+ (xref--show-xrefs
+ (apply-partially #'xref-matches-in-files id
+ ;; remove the current buffer file from the
+ ;; backlinks
+ (delete file (denote-directory-text-only-files)))
+ nil)))))
(defalias 'denote-link-show-backlinks-buffer (symbol-function
'denote-link-backlinks))
@@ -3181,5 +3161,85 @@ Consult the manual for template samples."
(make-obsolete 'denote-migrate-old-org-filetags nil "1.1.0")
(make-obsolete 'denote-migrate-old-markdown-yaml-tags nil "1.1.0")
+
+;;;; project.el integration
+;; This is also used by xref integration
+
+(cl-defmethod project-root ((project (head denote)))
+ "Denote's implementation of `project-root' method from `project'.
+Return current variable `denote-directory' as the root of the
+current denote PROJECT."
+ (cdr project))
+
+(cl-defmethod project-files ((_project (head denote)) &optional _dirs)
+ "Denote's implementation of `project-files' method from `project'.
+Return all files that have an identifier for the current denote
+PROJECT. The return value may thus include file types that are
+not implied by `denote-file-type'. To limit the return value to
+text files, use the function `denote-directory-text-only-files'."
+ (denote-directory-files))
+
+(defun denote-project-find (dir)
+ "Return project instance if DIR is part of variable `denote-directory'.
+The format of project instance is aligned with `project-try-vc'
+defined in `project'."
+ (let ((dir (expand-file-name dir)) ; canonicalize current directory name
+ (root (denote-directory)))
+ (when (or (file-equal-p dir root) ; currently at `denote-directory'
+ (string-prefix-p root dir)) ; or its subdirectory
+ (cons 'denote root))))
+
+;;;; Xref integration
+;; Set `xref-backend-functions' like this.
+;; (add-hook 'xref-backend-functions #'denote--xref-backend)
+;;
+;; You can tell xref-references not to prompt by adding the following:
+;; (add-to-list 'xref-prompt-for-identifier #'xref-find-references
+;; :append)
+
+(defun denote--xref-backend ()
+ "Return denote if `default-directory' is in denote directory."
+ (when (denote--dir-in-denote-directory-p default-directory)
+ 'denote))
+
+(cl-defmethod xref-backend-identifier-at-point ((_backend (eql 'denote)))
+ "Return the \"thing\" at point.
+The same logic as `elisp-mode'. The \"thing\" is assumed to be a
+Denote identifier, but can be any word. The method checks this
+and errors and if the word at point is not a Denote identifer."
+ (let ((bounds (bounds-of-thing-at-point 'word)))
+ (and bounds
+ (let ((id (buffer-substring-no-properties
+ (car bounds) (cdr bounds))))
+ (if (string-match-p denote-id-regexp id)
+ ;; Use a property to transport the location of the identifier.
+ (propertize id 'pos (car bounds))
+ (user-error "%s is not a Denote identifier" id))))))
+
+(cl-defmethod xref-backend-definitions ((_backend (eql 'denote)) identifier)
+ "Return xref for the note IDENTIFIER points to."
+ (let ((file (denote-get-path-by-id identifier)))
+ (when file
+ (if (file-equal-p file (buffer-file-name (current-buffer)))
+ (user-error "Identifier points to the current buffer")
+ ;; Without the message, Xref will report that the ID does not
+ ;; exist, which is incorrect in this case.
+ (list (xref-make nil (xref-make-file-location file 0 0)))))))
+
+(cl-defgeneric xref-backend-references ((_backend (eql 'denote)) identifier)
+ "Return list of xrefs where IDENTIFIER is referenced.
+This include the definition itself."
+ (xref-matches-in-files identifier (denote-directory-text-only-files)))
+
+(cl-defmethod xref-backend-identifier-completion-table ((_backend
+ (eql 'denote)))
+ "Return list of Denote identifers as completion table."
+
+ (let* ((project-find-functions #'denote-project-find)
+ (project (project-current nil (denote-directory)))
+ (dirs (list (project-root project)))
+ (all-files (project-files project dirs)))
+ (mapcar #'denote-retrieve-filename-identifier all-files)))
+
(provide 'denote)
;;; denote.el ends here
- [elpa] externals/denote updated (69824125b9 -> 0665a1e367), ELPA Syncer, 2022/11/21
- [elpa] externals/denote 3e074afb4b 2/6: feat: follow-symlinks, ELPA Syncer, 2022/11/21
- [elpa] externals/denote 22829d8541 5/6: Remove reference to non-existing function, ELPA Syncer, 2022/11/21
- [elpa] externals/denote 93971de099 3/6: fix: denote-get-path-by-id to send only denote notes file, ELPA Syncer, 2022/11/21
- [elpa] externals/denote 6bb6da0882 1/6: feat: project.el integration & backlinks refactoring with xref, ELPA Syncer, 2022/11/21
- [elpa] externals/denote 0a94f3e3c3 4/6: feat: xref-backend facility to enable xref integration, ELPA Syncer, 2022/11/21
- [elpa] externals/denote 0665a1e367 6/6: Merge branch 'xref-refinement-project-integration',
ELPA Syncer <=