summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAugusto Stoffel <arstoffel@gmail.com>2022-04-09 12:38:14 +0200
committerJuri Linkov <juri@linkov.net>2022-04-10 22:36:47 +0300
commit4c0c9d23abc28c7fa7eacf2f4d7a5aff02d84ab0 (patch)
tree5d33ebc7a7d409c31e2159865327b780e96953a8
parent7c6cdc1effe247a727a53eb3855894c0f00ef2ca (diff)
downloademacs-4c0c9d23abc28c7fa7eacf2f4d7a5aff02d84ab0.tar.gz
Rewrite the minibuffer lazy highlight feature
The new API was discussed in bug#53126. It's more robust and easier to use in complex cases like that of 'query-replace'. * etc/NEWS: Amend the feature announcement * lisp/isearch.el (isearch-edit-string): Use new API. (minibuffer-lazy-highlight-transform, minibuffer-lazy-highlight--overlay, minibuffer-lazy-highlight--count, minibuffer-lazy-highlight--after-change, minibuffer-lazy-highlight--exit) Remove helper functions, which are now kept together with the lazy highlight configuration variables within a closure. (minibuffer-lazy-highlight-setup): This function now takes the lazy highlighting configuration variables as argument, and returns a closure that is intended to run as part of the minibuffer setup.
-rw-r--r--etc/NEWS5
-rw-r--r--lisp/isearch.el148
2 files changed, 88 insertions, 65 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 2fac893cc52..2cddfcc8db6 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1593,9 +1593,8 @@ the clipboard, and insert it into the buffer.
---
** New function 'minibuffer-lazy-highlight-setup'.
-This function is intended to be added to 'minibuffer-setup-hook'.
-It sets up the minibuffer for lazy highlighting of matches
-in the original window.
+This function allows to set up the minibuffer so that lazy
+highlighting of its content is applied in the original window.
+++
** New text property 'inhibit-isearch'.
diff --git a/lisp/isearch.el b/lisp/isearch.el
index 956b115ce42..168d71ada3a 100644
--- a/lisp/isearch.el
+++ b/lisp/isearch.el
@@ -1812,20 +1812,20 @@ The following additional command keys are active while editing.
(minibuffer-history-symbol)
;; Search string might have meta information on text properties.
(minibuffer-allow-text-properties t))
- (when isearch-lazy-highlight
- (add-hook 'minibuffer-setup-hook #'minibuffer-lazy-highlight-setup))
(setq isearch-new-string
- (read-from-minibuffer
- (isearch-message-prefix nil isearch-nonincremental)
- (cons isearch-string (1+ (or (isearch-fail-pos)
- (length isearch-string))))
- minibuffer-local-isearch-map nil
- (if isearch-regexp
- (cons 'regexp-search-ring
- (1+ (or regexp-search-ring-yank-pointer -1)))
- (cons 'search-ring
- (1+ (or search-ring-yank-pointer -1))))
- nil t)
+ (minibuffer-with-setup-hook
+ (minibuffer-lazy-highlight-setup)
+ (read-from-minibuffer
+ (isearch-message-prefix nil isearch-nonincremental)
+ (cons isearch-string (1+ (or (isearch-fail-pos)
+ (length isearch-string))))
+ minibuffer-local-isearch-map nil
+ (if isearch-regexp
+ (cons 'regexp-search-ring
+ (1+ (or regexp-search-ring-yank-pointer -1)))
+ (cons 'search-ring
+ (1+ (or search-ring-yank-pointer -1))))
+ nil t))
isearch-new-message
(mapconcat 'isearch-text-char-description
isearch-new-string "")))))
@@ -4361,57 +4361,81 @@ Attempt to do the search exactly the way the pending Isearch would."
:group 'lazy-count
:version "29.1")
-(defvar minibuffer-lazy-highlight-transform #'identity
- "Function to transform minibuffer text into a `isearch-string' for highlighting.")
-
-(defvar minibuffer-lazy-highlight--overlay nil
- "Overlay for minibuffer prompt updates.")
-
-(defun minibuffer-lazy-highlight--count ()
- "Display total match count in the minibuffer prompt."
- (when minibuffer-lazy-highlight--overlay
- (overlay-put minibuffer-lazy-highlight--overlay
- 'before-string
- (and isearch-lazy-count-total
- (not isearch-error)
- (format minibuffer-lazy-count-format
- isearch-lazy-count-total)))))
-
-(defun minibuffer-lazy-highlight--after-change (_beg _end _len)
- "Update lazy highlight state in minibuffer selected window."
- (when isearch-lazy-highlight
- (let ((inhibit-redisplay t) ;; Avoid cursor flickering
- (string (minibuffer-contents)))
- (with-minibuffer-selected-window
- (setq isearch-string (funcall minibuffer-lazy-highlight-transform string))
- (isearch-lazy-highlight-new-loop)))))
-
-(defun minibuffer-lazy-highlight--exit ()
- "Unwind changes from `minibuffer-lazy-highlight-setup'."
- (remove-hook 'after-change-functions
- #'minibuffer-lazy-highlight--after-change)
- (remove-hook 'lazy-count-update-hook #'minibuffer-lazy-highlight--count)
- (remove-hook 'minibuffer-exit-hook #'minibuffer-lazy-highlight--exit)
- (setq minibuffer-lazy-highlight--overlay nil)
- (when lazy-highlight-cleanup
- (lazy-highlight-cleanup)))
-
-(defun minibuffer-lazy-highlight-setup ()
+(cl-defun minibuffer-lazy-highlight-setup
+ (&key (highlight isearch-lazy-highlight)
+ (cleanup lazy-highlight-cleanup)
+ (transform #'identity)
+ (filter nil)
+ (regexp isearch-regexp)
+ (regexp-function isearch-regexp-function)
+ (case-fold isearch-case-fold-search)
+ (lax-whitespace (if regexp
+ isearch-regexp-lax-whitespace
+ isearch-lax-whitespace)))
"Set up minibuffer for lazy highlight of matches in the original window.
-This function is intended to be added to `minibuffer-setup-hook'.
-Note that several other isearch variables influence the lazy
-highlighting, including `isearch-regexp',
-`isearch-lazy-highlight' and `isearch-lazy-count'."
- (remove-hook 'minibuffer-setup-hook #'minibuffer-lazy-highlight-setup)
- (add-hook 'after-change-functions
- #'minibuffer-lazy-highlight--after-change)
- (add-hook 'lazy-count-update-hook #'minibuffer-lazy-highlight--count)
- (add-hook 'minibuffer-exit-hook #'minibuffer-lazy-highlight--exit)
- (setq minibuffer-lazy-highlight--overlay
- (and minibuffer-lazy-count-format
- (make-overlay (point-min) (point-min) (current-buffer) t)))
- (minibuffer-lazy-highlight--after-change nil nil nil))
+This function return a closure intended to be added to
+`minibuffer-setup-hook'. It accepts the following keyword
+arguments, all of which have a default based on the current
+isearch settings.
+
+HIGHLIGHT: Whether to perform lazy highlight.
+CLEANUP: Whether to clean up the lazy highlight when the minibuffer
+exits.
+TRANSFORM: A function taking one argument, the minibuffer contents,
+and returning the `isearch-string' to use for lazy highlighting.
+FILTER: A function to add to `isearch-filter-predicate'.
+REGEXP: The value of `isearch-regexp' to use for lazy highlighting.
+REGEXP-FUNCTION: The value of `isearch-regexp-function' to use for
+lazy highlighting.
+CASE-FOLD: The value of `isearch-case-fold' to use for lazy
+highlighting.
+LAX-WHITESPACE: The value of `isearch-lax-whitespace' and
+`isearch-regexp-lax-whitespace' to use for lazy highlighting."
+ (if (not highlight)
+ #'ignore
+ (let ((unwind (make-symbol "minibuffer-lazy-highlight--unwind"))
+ (after-change (make-symbol "minibuffer-lazy-highlight--after-change"))
+ (display-count (make-symbol "minibuffer-lazy-highlight--display-count"))
+ overlay)
+ (fset unwind
+ (lambda ()
+ (remove-function isearch-filter-predicate filter)
+ (remove-hook 'lazy-count-update-hook display-count)
+ (when overlay (delete-overlay overlay))
+ (remove-hook 'after-change-functions after-change)
+ (remove-hook 'minibuffer-exit-hook unwind)
+ (let ((lazy-highlight-cleanup cleanup))
+ (lazy-highlight-cleanup))))
+ (fset after-change
+ (lambda (_beg _end _len)
+ (let ((inhibit-redisplay t) ;; Avoid cursor flickering
+ (string (minibuffer-contents)))
+ (with-minibuffer-selected-window
+ (let* ((isearch-forward t)
+ (isearch-regexp regexp)
+ (isearch-regexp-function regexp-function)
+ (isearch-case-fold-search case-fold)
+ (isearch-lax-whitespace lax-whitespace)
+ (isearch-regexp-lax-whitespace lax-whitespace)
+ (isearch-string (funcall transform string)))
+ (isearch-lazy-highlight-new-loop))))))
+ (fset display-count
+ (lambda ()
+ (overlay-put overlay 'before-string
+ (and isearch-lazy-count-total
+ (not isearch-error)
+ (format minibuffer-lazy-count-format
+ isearch-lazy-count-total)))))
+ (lambda ()
+ (add-hook 'minibuffer-exit-hook unwind)
+ (add-hook 'after-change-functions after-change)
+ (when minibuffer-lazy-count-format
+ (setq overlay (make-overlay (point-min) (point-min) (current-buffer) t))
+ (add-hook 'lazy-count-update-hook display-count))
+ (when filter
+ (add-function :after-while isearch-filter-predicate filter))
+ (funcall after-change nil nil nil)))))
(defun isearch-resume (string regexp word forward message case-fold)