branch: externals/hyperbole
commit 1736985befc90b3e5482a365bcfbd0a87229e735
Author: bw <r...@gnu.org>
Commit: bw <r...@gnu.org>

    hyrolo.el - Add consult completion support to `hyrolo-edit'
    
    hyrolo-yank - Fix consult completion support.
    hyrolo--cache-major-mode - Fix hash table cache initialization.
---
 ChangeLog       | 31 ++++++++++++++++++++++++++++++
 hsys-consult.el | 59 +++++++++++++++++++++++++++++++++++++++------------------
 hyrolo.el       | 53 +++++++++++++++++++++++++++++++++------------------
 3 files changed, 107 insertions(+), 36 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index bf4b1fec53..45715515b3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,34 @@
+2025-06-02  Bob Weiner  <r...@gnu.org>
+
+* hsys-consult.el (hsys-consult-selected-candidate): Rewrite to fix byte
+    compilation errors.
+
+2025-06-01  Bob Weiner  <r...@gnu.org>
+
+* hyrolo.el (hyrolo-grep-file): Fix to handle regexp-quoted asterisks, i.e.
+    "\\*".  This fixes a bug where 'hyrolo-yank' did not match to entries
+    starting with multiple asterisks.
+            (hyrolo-edit): Add consult completion support.
+
+* hsys-consult.el (hsys-consult-selected-candidate): Rewrite to allow 
non-command
+    functions that take arguments (so can send a prompt) and remove
+    'no-properties-flag'.  Use 'substring-no-properties' to handle that in a
+    separate call.
+                  (hsys-consult-grep-headlines-read-regexp): Add.
+  hyrolo.el (hyrolo-consult-yank-grep): Generalize and rename to
+    'hsys-consult-grep-headlines-with-prompt' in "hsys-consult.el".
+
+* hyrolo.el (hyrolo--cache-major-mode): Initialize hash table if not done
+    already.  Fixes bug when 'hyrolo-grep' is called prior to init.
+            (hyrolo-yank): Fix to get for (fboundp 'consult-grep) rather than
+    (featurep 'consult) so that the consult package can be autoloaded.  Also
+    add error handling if invalid 'name' value is given.
+            (hyrolo-consult-yank-grep): Add (require 'consult) before locally
+    disabling 'consult-preview-key' so do not get this error when consult
+    is loaded lower in the call stack:
+      (error "Defining as dynamic an already lexical var")
+      custom-declare-variable(consult-preview-key)
+
 2025-05-27  Bob Weiner  <r...@gnu.org>
 
 * hsys-www.el (www-url): Fix bug where "www.google.com" would not actually
diff --git a/hsys-consult.el b/hsys-consult.el
index 9435ae6173..c1b8f0635a 100644
--- a/hsys-consult.el
+++ b/hsys-consult.el
@@ -2,7 +2,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:     4-Jul-24 at 09:57:18
-;; Last-Mod:     26-May-25 at 03:30:20 by Bob Weiner
+;; Last-Mod:      2-Jun-25 at 00:29:20 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -81,7 +81,8 @@
          (kill-buffer buf))))))
 
 ;;;###autoload
-(defun hsys-consult-grep (grep-includes ripgrep-globs &optional regexp 
max-matches path-list prompt)
+(defun hsys-consult-grep (grep-includes ripgrep-globs &optional regexp 
max-matches
+                                       path-list prompt)
   "Interactively search PATH-LIST with a consult package grep command.
 
 With GREP-INCLUDES or RIPGREP-GLOBS file suffixes to include, search
@@ -91,6 +92,7 @@ Use ripgrep (rg) if found, otherwise, plain grep.  Initialize 
search with
 optional REGEXP and interactively prompt for changes.  Limit matches
 per file to the absolute value of MAX-MATCHES, if given and not 0.  If
 0, match to headlines only (lines that start with a '^[*#]+[ \t]+' regexp).
+
 With optional PROMPT string, use this as the first part of the grep prompt;
 omit any trailing colon and space in the prompt."
   (unless (package-installed-p 'consult)
@@ -121,6 +123,30 @@ omit any trailing colon and space in the prompt."
                  path-list)))
     (hsys-consult--grep-paths paths regexp max-matches prompt)))
 
+(defun hsys-consult-grep-headlines-with-prompt (grep-function prompt
+                                               &optional regexp)
+  "Call Hyperbole consult GREP-FUNCTION over headlines with PROMPT.
+Optional REGEXP is the initial pattern for the grep.
+Suppress preview and return the selected \"file:line:line-contents\".
+
+GREP-FUNCTION must take these arguments: regexp max-matches path-list
+prompt."
+  (let ((consult-preview-key nil))
+    (funcall grep-function regexp 0 nil prompt)))
+
+(defun hsys-consult-grep-headlines-read-regexp (grep-function prompt
+                                               &optional regexp)
+  "With `consult', completing read a string with GREP-FUNCTION and PROMPT.
+Optional REGEXP is the initial pattern for the grep."
+  (if (fboundp 'consult-grep)
+      (substring-no-properties
+       (hsys-consult-selected-candidate
+       #'hsys-consult-grep-headlines-with-prompt
+       grep-function
+       prompt
+       regexp))
+    (read-regexp (concat prompt ": ") regexp)))
+
 (defun hsys-consult-grep-tags (org-consult-grep-function)
   "When on an Org tag, call ORG-CONSULT-GREP-FUNCTION to find matches.
 If on a colon, match to sections with all tags around point;
@@ -208,21 +234,17 @@ that start with the '^[*#]+[ \t]*' regexp)."
      (org-roam-node-find nil nil (lambda (node) (zerop (org-roam-node-level 
node)))))))
 
 ;;;###autoload
-(defun hsys-consult-selected-candidate (consult-command &optional 
no-properties-flag)
-  "Return the input from interactively calling CONSULT-COMMAND, a symbol.
-CONSULT-COMMAND is called with no arguments.  Add optional
-NO-PROPERTIES-FLAG non-nil to strip the properties from the
-returned input string."
-  (unless (commandp consult-command)
-    (user-error "(hsys-consult-selected-candidate): First arg must be a 
command, not `%s'" consult-command))
+(defun hsys-consult-selected-candidate (consult-function &rest args)
+  "Return the input from calling CONSULT-FUNCTION, a symbol, with rest of 
ARGS."
+  (unless (fboundp consult-function)
+    (user-error "(hsys-consult-selected-candidate): First arg must be a bound 
function, not `%s'"
+               consult-function))
   (save-excursion
     (save-window-excursion
-      (cl-flet ((mapcar (lambda (state-function)
-                         `(,state-function () cand))
-                       (apropos-internal "consult--.+-state" #'fboundp)))
-       (if no-properties-flag
-           (substring-no-properties (or (call-interactively consult-command) 
""))
-         (call-interactively consult-command))))))
+      (eval `(cl-flet ((mapcar (lambda (state-function)
+                                `(,state-function () cand))
+                              (apropos-internal "consult--.+-state" 
#'fboundp)))
+              (apply ',consult-function ',args))))))
 
 ;;; ************************************************************************
 ;;; Private functions
@@ -238,9 +260,10 @@ Initialize search with optional REGEXP and interactively 
prompt
 for changes.  Limit matches per file to the absolute value of
 optional MAX-MATCHES, if given and not 0.  If 0, match to the
 start of headline text only (lines that start with a '^[*#]+[
-\t]*' regexp).  With optional PROMPT string, use this as the first
-part of the grep prompt; omit any trailing colon and space in the
-prompt."
+\t]*' regexp).
+
+With optional PROMPT string, use this as the first part of the
+grep prompt; omit any trailing colon and space in the prompt."
   (unless (package-installed-p 'consult)
     (package-install 'consult))
   (require 'consult)
diff --git a/hyrolo.el b/hyrolo.el
index 4eaa16b0ef..70ed3c9c3d 100644
--- a/hyrolo.el
+++ b/hyrolo.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:     7-Jun-89 at 22:08:29
-;; Last-Mod:     27-May-25 at 01:22:36 by Bob Weiner
+;; Last-Mod:      1-Jun-25 at 23:31:09 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -381,7 +381,7 @@ String search expressions are converted to regular 
expressions.")
 
 ;;;###autoload
 (defun hyrolo-add (name &optional file)
-  "Add a new entry in personal rolo for NAME.
+  "Add a new entry for NAME in the first file from `hyrolo-file-list'.
 Last name first is best, e.g. \"Smith, John\".
 With prefix argument, prompts for optional FILE to add entry within.
 NAME may be of the form: parent/child to insert child below a parent
@@ -397,7 +397,8 @@ entry which begins with the parent string."
                                (or name email))))
        (list (if (and email name
                      (string-match (concat "\\`" (regexp-quote entry)) name))
-                (format hyrolo-email-format entry email) entry)
+                (format hyrolo-email-format entry email)
+              entry)
             current-prefix-arg))))
   (when (or (not (stringp name)) (string-equal name ""))
     (error "(hyrolo-add): Invalid name: `%s'" name))
@@ -592,12 +593,25 @@ within which to locate entry.  With no NAME arg, simply 
display
 FILE-OR-BUF or the first entry in `hyrolo-file-list' in an editable
 mode.  NAME may be of the form: parent/child to edit child below
 a parent entry which begins with the parent string."
-  (interactive "sEdit rolo entry named: \nP")
+  (interactive (list
+               (hsys-consult-grep-headlines-read-regexp
+                #'hyrolo-consult-grep "Edit rolo entry named")
+               current-prefix-arg))
   (when (string-empty-p name)
     (setq name nil))
   (when (and name (not (stringp name)))
     (error "(hyrolo-edit): Invalid name: `%s'" name))
 
+  ;; With consult-grep, 'name' is the entire line matched prefixed
+  ;; by filename and line number, so remove these prefixes.
+  (when (and name
+            (fboundp 'consult-grep)
+            (string-match "\\([^ \t\n\r\"'`]*[^ \t\n\r:\"'`0-9]\\): 
?\\([1-9][0-9]*\\)[ :]"
+                          name))
+    (setq file-or-buf (expand-file-name (match-string 1 name))
+         name (substring name (match-end 0)))
+    (put-text-property 0 1 'hyrolo-line-entry 0 name))
+
   (let* ((found-point)
         (all-files-or-bufs (hyrolo-get-file-list))
         (file-or-buf-list (if file-or-buf (list file-or-buf) 
all-files-or-bufs)))
@@ -609,6 +623,7 @@ a parent entry which begins with the parent string."
                               (mapcar #'list all-files-or-bufs)))))
     (unless file-or-buf
       (setq file-or-buf (car file-or-buf-list)))
+
     (if (or (null name)
            (setq found-point (hyrolo-to name (list file-or-buf))))
        (cond ((stringp file-or-buf)
@@ -1519,22 +1534,26 @@ hyrolo-file-list."
 ;;;###autoload
 (defun hyrolo-yank (name &optional regexp-flag)
   "Insert at point the first rolo entry with a headline containing NAME.
-If the `consult' package is loaded, interactively select and complete
+If the `consult' package is installed, interactively select and complete
 the entry to be inserted.
 
 With optional prefix arg, REGEXP-FLAG, treat NAME as a regular expression
 instead of a string."
   (interactive (list 
-               (if (featurep 'consult)
-                   (hsys-consult-selected-candidate 'hyrolo-consult-yank-grep 
t)
-                 (read-string "Yank rolo headline matching: "))
+               (hsys-consult-grep-headlines-read-regexp
+                #'hyrolo-consult-grep "Yank rolo headline matching")
                current-prefix-arg))
+  (when (string-empty-p name)
+    (setq name nil))
+  (when (or (null name) (not (stringp name)))
+    (error "(hyrolo-yank): Invalid name: `%s'" name))
+
   (let ((hyrolo-display-buffer (current-buffer))
        (start (point))
        found)
     (save-excursion
       (setq found
-           (if (and (featurep 'consult)
+           (if (and (fboundp 'consult-grep)
                     (string-match "\\([^ \t\n\r\"'`]*[^ \t\n\r:\"'`0-9]\\): 
?\\([1-9][0-9]*\\)[ :]"
                                   name))
                (hyrolo-grep-file (match-string-no-properties 1 name)
@@ -1542,8 +1561,8 @@ instead of a string."
                                  -1 nil t)
              (hyrolo-grep (if regexp-flag name (regexp-quote name)) -1 nil nil 
t))))
     ;; Let user reformat the region just yanked.
-    (if (= found 1)
-       (funcall hyrolo-yank-reformat-function start (point)))
+    (when (= found 1)
+      (funcall hyrolo-yank-reformat-function start (point)))
     found))
 
 ;;; ************************************************************************
@@ -2027,8 +2046,10 @@ Return number of matching entries found."
                         max-matches (- max-matches)))))
          (set-buffer actual-buf)
 
+         ;; Allow for initial asterisks being regexp-quoted in
+         ;; string-match below.
          (when (and headline-only
-                    (not (string-match (concat "\\`\\([*#]+[ \t]+\\|"
+                    (not (string-match (concat "\\`\\([\\*#]+[ \t]+\\|"
                                                "\\\\\\*+[ \t]+\\|"
                                                "#+[ \t]+\\|"
                                                (regexp-quote "^") "\\|"
@@ -2929,12 +2950,6 @@ HYROLO-BUF may be a file-name, `buffer-name', or buffer."
                             hyrolo-buf))
             (buffer-list))))
 
-(defun hyrolo-consult-yank-grep ()
-  "Support function for `hyrolo-yank'."
-  (interactive)
-  (let ((consult-preview-key nil))
-    (hyrolo-consult-grep nil 0 nil "Yank rolo headline matching")))
-
 (defun hyrolo-current-date ()
   "Return the current date (a string) in a form used for rolo entry insertion."
   (format-time-string hyrolo-date-format))
@@ -3470,6 +3485,8 @@ Push (point-max) of `hyrolo-display-buffer' onto
 `hyrolo--cache-loc-match-bounds'.  Push hash table's index key to
 `hyrolo--cache-major-mode-indexes'.  Ensure MATCHED-BUF's
 `major-mode' is stored in the hash table."
+  (unless (hash-table-p hyrolo--cache-major-mode-to-index-hasht)
+    (hyrolo--cache-initialize))
   (with-current-buffer hyrolo-display-buffer
     (let* ((matched-buf-file-name (buffer-local-value 'buffer-file-name 
matched-buf))
           (matched-buf-major-mode (or (hyrolo-major-mode-from-file-name 
matched-buf-file-name)

Reply via email to