From 5ed0e5a850992c62189c0dc74ef98b892522d4df Mon Sep 17 00:00:00 2001 From: Augusto Stoffel Date: Sat, 9 Apr 2022 12:38:14 +0200 Subject: [PATCH 1/2] 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. --- etc/NEWS | 5 +- lisp/isearch.el | 148 ++++++++++++++++++++++++++++-------------------- 2 files changed, 88 insertions(+), 65 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 2fac893cc5..2cddfcc8db 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 956b115ce4..168d71ada3 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -1812,20 +1812,20 @@ isearch-edit-string (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 @@ minibuffer-lazy-count-format :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) -- 2.35.1