branch: externals/denote
commit 89071cffce46e1fd7de928692b7a767e263aa14b
Author: Protesilaos Stavrou <i...@protesilaos.com>
Commit: Protesilaos Stavrou <i...@protesilaos.com>

    Expand query links to also work for file names and change their format
    
    I am now using the format suggested by Jean-Philippe Gagné Guay, which
    is "denote:TYPE:QUERY". The technical discussion for this is in issue 561:
    <https://github.com/protesilaos/denote/issues/561>.
    
    Perhaps there is a way to apply a different face to the query links,
    though I do not think this is a critical feature.
    
    What remains to be decided is if we can/should have shorter TYPE
    values than the ones I am using now.
---
 denote.el | 117 ++++++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 91 insertions(+), 26 deletions(-)

diff --git a/denote.el b/denote.el
index 7d90cac3ab..418c1a5328 100644
--- a/denote.el
+++ b/denote.el
@@ -639,7 +639,7 @@ and/or the documentation string of `display-buffer'."
 
 (defcustom denote-query-links-display-buffer-action
   '((display-buffer-reuse-mode-window display-buffer-below-selected)
-    (mode . denote-query-mode)
+    (mode . (denote-query-mode dired))
     (window-height . 0.3)
     (preserve-size . (t . t)))
   "The action used to display query links.
@@ -1739,7 +1739,7 @@ also prompt for SORT-BY-COMPONENT, REVERSE, and 
EXCLUDE-REGEXP.
    OMIT-CURRENT have been applied.
 
 When called from Lisp, the arguments are a string, a symbol among
-`denote-sort-components', and a non-nil value, respectively."
+`denote-sort-components', a non-nil value, and a string, respectively."
   (interactive
    (append (list (denote-files-matching-regexp-prompt)) 
(denote-sort-dired--prompts)))
   (let ((component (or sort-by-component
@@ -1770,9 +1770,7 @@ When called from Lisp, the arguments are a string, a 
symbol among
                           ;; `denote-update-dired-buffers'.
                           (kill-buffer dired-buffer)
                           (denote-sort-dired files-matching-regexp component 
reverse-sort exclude-rx))))
-          ;; Because of the above NOTE, I am printing a message.  Not
-          ;; what I want, but it is better than nothing...
-          (message denote-sort-dired-buffer-name))
+          buffer-name)
       (message "No matching files for: %s" files-matching-regexp))))
 
 (defalias 'denote-sort-dired 'denote-dired
@@ -5214,10 +5212,10 @@ Place the buffer below the current window or wherever 
the user option
 (defalias 'denote-show-backlinks-buffer 'denote-backlinks
   "Alias for `denote-backlinks' command.")
 
-(defvar denote-query-history nil
-  "Minibuffer history of `denote-query-prompt'.")
+(defvar denote-query-link-history nil
+  "Minibuffer history of `denote-query-link-prompt'.")
 
-(defun denote-query-prompt (&optional initial-query prompt-text)
+(defun denote-query-link-prompt (&optional initial-query prompt-text)
   "Prompt for query string.
 With optional INITIAL-QUERY use it as the initial minibuffer text.  With
 optional PROMPT-TEXT use it in the minibuffer instead of the default
@@ -5230,21 +5228,89 @@ non-nil value."
     (setq initial-query nil))
   (denote--with-conditional-completion
    'denote-signature-prompt
-   (format-prompt (or prompt-text "Query in files") nil)
-   denote-query-history
+   (format-prompt (or prompt-text "Query for") nil)
+   denote-query-link-history
    initial-query))
 
+(defconst denote-query-link-types '(query-contents query-filenames)
+  "Types of query links.")
+
+(defun denote--format-query-link (type query)
+  "Format QUERY link of TYPE.
+Return an error if TYPE is not one among the symbols specified in
+`denote-query-link-types'."
+  (unless (memq type denote-query-link-types)
+    (error "Type `%s' is not one among `denote-query-link-types'" type))
+  (format "[[denote:%s:%s]]" type query))
+
+;;;###autoload
+(defun denote-query-contents-link (query)
+  "Insert query link for file contents.
+Prompt for QUERY or use the text of the active region.
+
+Query links of this sort do not point to any file but instead initiate a
+search in the contents of files inside the variable `denote-directory'.
+They are always formatted as [[denote:query-contents:QUERY]].  This is
+unlike what `denote-link' and related commands do, which always
+establish a direct connection to a file and their format is more
+flexible."
+  (interactive
+   (list
+    (or (denote--get-active-region-content)
+        (denote-query-link-prompt nil "Query in file contents"))))
+  (denote--delete-active-region-content)
+  (insert (denote--format-query-link 'query-contents query)))
+
 ;;;###autoload
-(defun denote-query (query)
-  "Create query link at point, prompting for QUERY or using the active region.
-Query links do not point to any file but instead initiate a search in
-the contents of files inside the variable `denote-directory'.  They are
-always formatted as [[denote:QUERY]].  This is unlike what `denote-link'
-and related commands do, which always establish a direct connection to a
-file and their format is more flexible."
-  (interactive (list (or (denote--get-active-region-content) 
(denote-query-prompt))))
+(defun denote-query-filenames-link (query)
+  "Insert query link for file names.
+Prompt for QUERY or use the text of the active region.
+
+Query links of this sort do not point to any file but instead initiate a
+search in the contents of files inside the variable `denote-directory'.
+They are always formatted as [[denote:query-filenames:QUERY]].  This is
+unlike what `denote-link' and related commands do, which always
+establish a direct connection to a file and their format is more
+flexible."
+  (interactive
+   (list
+    (or (denote--get-active-region-content)
+        (denote-query-link-prompt nil "Query in file names"))))
   (denote--delete-active-region-content)
-  (insert (format "[[denote:%s]]" query)))
+  (insert (denote--format-query-link 'query-filenames query)))
+
+(defvar denote--query-last-dired-buffer nil
+  "Buffer object produced by the last query for file names.")
+
+(defun denote--act-on-query-link (query)
+  "Act on QUERY link.
+QUERY is a string of the form TYPE:SEARCH, where TYPE is one among
+`denote-query-link-types' while SEARCH is the regular expression to
+search for."
+  (cond
+   ((string-prefix-p "query-contents:" query)
+    (setq query (replace-regexp-in-string "query-contents:" "" query))
+    (funcall denote-query-links-buffer-function query 
denote-query-links-display-buffer-action))
+   ((string-prefix-p "query-filenames:" query)
+    (setq query (replace-regexp-in-string "query-filenames:" "" query))
+    ;; NOTE 2025-03-27: I do not think we need to add another
+    ;; parameter to `denote-sort-dired' for handling the
+    ;; `display-buffer'.  This is a special case, but we can always
+    ;; change it later if the need arises.
+    ;;
+    ;; Here we handle the buffer and window state to make it behave
+    ;; like the Xref buffer.  Otherwise, Dired does not reuse its
+    ;; buffer (which is generally okay).
+    (let ((buffer (save-window-excursion (denote-sort-dired query nil nil 
nil))))
+      (when denote--query-last-dired-buffer
+        (when-let* ((window (get-buffer-window 
denote--query-last-dired-buffer))
+                    (_ (window-live-p window)))
+          (delete-window window))
+        (kill-buffer denote--query-last-dired-buffer))
+      (display-buffer buffer denote-query-links-display-buffer-action)
+      (setq denote--query-last-dired-buffer buffer)))
+   (t
+    (error "Cannot open `%s' of unknown link type" query))))
 
 ;;;;; Link buttons
 
@@ -5283,11 +5349,10 @@ To be assigned to `markdown-follow-link-functions'."
 
 (defun denote--link-open-at-point-subr ()
   "Open link at point."
-  (let* ((query (get-text-property (point) 'denote-link-query-part))
-         (path (denote-get-path-by-id query)))
-    (if path
+  (let ((query (get-text-property (point) 'denote-link-query-part)))
+    (if-let* ((path (denote-get-path-by-id query)))
         (funcall denote-open-link-function path)
-      (funcall denote-query-links-buffer-function query 
denote-query-links-display-buffer-action))))
+      (denote--act-on-query-link query))))
 
 (defun denote-link-open-at-point ()
   "Open Denote link at point."
@@ -5659,14 +5724,14 @@ option akin to that of standard Org `file:' link types. 
 Read Info
 node `(org) Query Options'.
 
 If LINK is not an identifier, then it is not pointing to a file but to a
-query of file contents.  Those are displayed in a separate buffer which
-uses `denote-query-mode'.
+query of file contents or file names (see the commands
+`denote-query-contents-link' and `denote-query-filenames-link').
 
 Uses the function `denote-directory' to establish the path to the file."
   (if-let* ((match (denote-link--ol-resolve-link-to-target link))
             (_ (file-exists-p match)))
       (org-link-open-as-file match nil)
-    (funcall denote-query-links-buffer-function match 
denote-query-links-display-buffer-action)))
+    (denote--act-on-query-link match)))
 
 ;;;###autoload
 (defun denote-link-ol-complete ()

Reply via email to