branch: scratch/mheerdegen-preview commit 62fc5c5a9da558330f8ec20f00e12f4db57954f4 Author: Michael Heerdegen <michael_heerde...@web.de> Commit: Michael Heerdegen <michael_heerde...@web.de>
WIP [el-search] Minibuffer hints when entering pattern, Fix case when search pattern fails for some sexps --- packages/el-search/el-search.el | 512 ++++++++++++++++++++++++++-------------- 1 file changed, 335 insertions(+), 177 deletions(-) diff --git a/packages/el-search/el-search.el b/packages/el-search/el-search.el index 05f5de8..c0202cd 100644 --- a/packages/el-search/el-search.el +++ b/packages/el-search/el-search.el @@ -471,6 +471,21 @@ "Expression based search and replace for Emacs Lisp." :group 'lisp) +(defcustom el-search-display-mb-hints t + "Whether to show hints in the search pattern prompt." + :type 'boolean) + +(defcustom el-search-mb-hints-delay 0.8 + "Time before displaying minibuffer hints. + +Setting this has only an effect if `el-search-display-mb-hints' +is non-nil." + :type 'number) + +(defcustom el-search-mb-hints-timeout 15 + "How long to display minibuffer hints." + :type 'number) + (defface el-search-match '((((class color) (min-colors 88) (background dark)) (:background "#600000")) (((class color) (min-colors 88) (background light)) @@ -869,10 +884,13 @@ nil." input) (symbol-value histvar))))) +(defun el-search--pattern-is-unquoted-symbol-p (pattern) + (and (symbolp pattern) + (not (eq pattern '_)) + (not (keywordp pattern)))) + (defun el-search--maybe-warn-about-unquoted-symbol (pattern) - (when (and (symbolp pattern) - (not (eq pattern '_)) - (not (keywordp pattern))) + (when (el-search--pattern-is-unquoted-symbol-p pattern) (message "Free variable `%S' (missing a quote?)" pattern) (sit-for 2.))) @@ -882,7 +900,110 @@ nil." (el-search--pushnew-to-history input histvar) (if (not (string= input "")) input (car (symbol-value histvar))))) -(defun el-search-read-pattern-for-interactive (&optional prompt) +(defvar el-search--display-match-count-in-prompt nil) +(defvar el-search--mb-hints-timer nil) +(defvar el-search--reading-input-for-query-replace nil) + +(defun el-search-read-pattern-trigger-mb-hints () + (if (not (timerp el-search--mb-hints-timer)) + (setq el-search--mb-hints-timer (run-at-time 3 nil #'el-search-read-display-mb-hints)) + (timer-set-time el-search--mb-hints-timer (time-add (current-time) el-search-mb-hints-delay)) + (timer-activate el-search--mb-hints-timer))) + +(defun el-search-read-pattern-setup-mb-hints () + (when el-search-display-mb-hints + (when (timerp el-search--mb-hints-timer) (cancel-timer el-search--mb-hints-timer)) + (setq el-search--mb-hints-timer nil) + (add-hook 'post-command-hook #'el-search-read-pattern-trigger-mb-hints t t))) + +(defvar el-search--search-pattern-1-do-fun nil) +(defvar el-search--busy-animation + ;; '("." "o" "O" "o" "." " ") + ;; '("|" "/" "-" "\\") + '("* " " * " " * " " *" " * " " * ")) + +(defun el-search--make-display-animation-function (display-fun) + (let ((last-update (seconds-to-time 0)) + (anim (copy-sequence el-search--busy-animation))) + (setcdr (last anim) anim) + (lambda () + (let ((now (current-time))) + (when (< .33 (float-time (time-subtract now last-update))) + (setq last-update now) + (funcall display-fun (pop anim))))))) + +(defun el-search-read-display-mb-hints () + (when (minibufferp) + (while-no-input + (let (err) + (cl-macrolet ((try (&rest body) + (let ((err-data (make-symbol "err-data"))) + `(condition-case ,err-data + (progn ,@body) + (error (setq err ,err-data) + nil))))) + (let* ((input (minibuffer-contents)) + (pattern (pcase (ignore-errors (read-from-string input)) + (`(,expr . ,(or (guard el-search--reading-input-for-query-replace) + (pred (= (length input))))) + expr))) + (matcher (and pattern (try (el-search-make-matcher pattern))))) + (let* ((base-win (minibuffer-selected-window)) + (buf (window-buffer base-win))) + (if (and el-search--display-match-count-in-prompt matcher) + (progn (with-current-buffer buf + (setq el-search--current-search + (el-search-make-search + pattern + (let ((b (current-buffer))) + (lambda () (stream (list b))))))) + (sit-for .3) + (let ((ol (make-overlay (point-max) (point-max) nil t t))) + (unwind-protect + (cl-flet ((display-message + (lambda (message &rest args) + (setq message + (propertize (apply #'format message args) + 'face 'shadow)) + (put-text-property 0 1 'cursor t message) + (overlay-put ol 'after-string message) + (redisplay)))) + (when (el-search--pattern-is-unquoted-symbol-p pattern) + ;; A very common mistake: input "foo" instead of "'foo" + (display-message + " [Free variable `%S' (missing a quote?)]" pattern) + (sit-for 2)) + (let ((el-search--search-pattern-1-do-fun + (el-search--make-display-animation-function + (lambda (icon) + (display-message (concat " " icon)))))) + (display-message + " %-12s" + (or (try (with-current-buffer buf + (cl-letf (((point) (window-point base-win))) + (el-search-display-match-count 'dont-message)))) + (error-message-string err)))) + (sit-for el-search-mb-hints-timeout)) + (delete-overlay ol)))) + (sit-for .3) + (unless (string= input "") + (catch 'no-message + (let ((minibuffer-message-timeout el-search-mb-hints-timeout)) + (minibuffer-message + (propertize + (format " [%s]" + (cond + ((not pattern) "invalid input") + (err (error-message-string err)) + (el-search--display-match-count-in-prompt "No match") + (t (throw 'no-message t)))) + 'face 'shadow))))))))))) + (when quit-flag + ;; When `quit-flag' is bound here, it had been set by `while-no-input' + ;; meaning the user explicitly quit. This means we must: + (funcall (key-binding [(control ?g)]))))) + +(defun el-search-read-pattern-for-interactive (&optional prompt display-match-count) "Read an \"el-search\" pattern from the minibuffer, prompting with PROMPT. This function is designed to be used in the interactive form of @@ -893,11 +1014,14 @@ from reading the pattern it also sets `this-command' to PROMPT defaults to \"El-search pattern: \". The return value is the `read' input pattern." - (let* ((input (el-search--read-pattern (or prompt "El-search pattern: ") - (car el-search-pattern-history))) + (let* ((input + (unwind-protect (minibuffer-with-setup-hook #'el-search-read-pattern-setup-mb-hints + (let ((el-search--display-match-count-in-prompt display-match-count)) + (el-search--read-pattern (or prompt "El-search pattern: ") + (car el-search-pattern-history)))) + (when (timerp el-search--mb-hints-timer) + (cancel-timer el-search--mb-hints-timer)))) (pattern (el-search-read input))) - ;; A very common mistake: input "foo" instead of "'foo" - (el-search--maybe-warn-about-unquoted-symbol pattern) (setq this-command 'el-search-pattern) ;in case we come from isearch ;; Make input available also in query-replace history (el-search--pushnew-to-history input 'el-search-query-replace-history) @@ -1157,6 +1281,8 @@ be specified as fourth argument, and COUNT becomes the fifth argument." (let ((match-beg nil) current-expr) (if (catch 'no-match (while (not match-beg) + (when el-search--search-pattern-1-do-fun + (funcall el-search--search-pattern-1-do-fun)) (condition-case nil (setq current-expr (el-search--ensure-sexp-start)) (end-of-buffer (throw 'no-match t))) @@ -1820,7 +1946,7 @@ any case." (defun el-search-keyboard-quit (&optional dont-quit) (interactive) (setq el-search--success nil) - (el-search-hl-post-command-fun) ;clear highlighting + (el-search-hl-post-command-fun 'stop) ;clear highlighting (switch-to-buffer (marker-buffer el-search--search-origin)) (goto-char el-search--search-origin) (unless dont-quit @@ -2351,87 +2477,94 @@ the active search and BUFFER-CHARS-MOD-TICK the return value of `buffer-chars-modified-tick' from when this stream had been created.") -(defun el-search-display-match-count () +(defun el-search-display-match-count (&optional just-count) "Display an x/y-style match count in the echo area." - (when (and el-search--success (not el-search--wrap-flag)) - (while-no-input - - ;; Check whether cached stream of buffer matches is still valid - (pcase el-search--buffer-match-count-data - (`(,(pred (eq el-search--current-search)) ,(pred (eq (buffer-chars-modified-tick))) . ,_)) - (_ - ;; (message "Refreshing match count data") (sit-for 1) - (redisplay) ;don't delay highlighting - (setq-local el-search--buffer-match-count-data - (let ((stream-of-buffer-matches - (seq-map #'cadr - (el-search--all-matches - (el-search-make-search - (el-search--current-pattern) - (let ((current-buffer (current-buffer))) - (lambda () (stream (list current-buffer))))))))) - (list - el-search--current-search - (buffer-chars-modified-tick) - stream-of-buffer-matches))))) - - (let ((pos-here (point)) (matches-<=-here 1) total-matches - (defun-bounds (or (el-search--bounds-of-defun) (cons (point) (point)))) - (matches-<=-here-in-defun 1) (total-matches-in-defun 0) - (largest-match-start-not-after-pos-here nil)) - (pcase-let ((`(,_ ,_ ,matches) el-search--buffer-match-count-data)) - (setq total-matches (let ((inhibit-message t)) (seq-length matches))) - (while (and (not (stream-empty-p matches)) (< (stream-first matches) (cdr defun-bounds))) - (when (<= (stream-first matches) pos-here) - (setq largest-match-start-not-after-pos-here (stream-first matches)) - (unless (= (stream-first matches) pos-here) - (cl-incf matches-<=-here))) - (when (<= (car defun-bounds) (stream-first matches)) - (cl-incf total-matches-in-defun) - (when (< (stream-first matches) pos-here) - (cl-incf matches-<=-here-in-defun))) - (stream-pop matches)) - (if (zerop total-matches) ;this can happen for el-search-this-sexp - (el-search--message-no-log "No matches") - (let* ((at-a-match-but-not-at-match-beginning - (and largest-match-start-not-after-pos-here - (and (< largest-match-start-not-after-pos-here pos-here) - (save-excursion - (goto-char largest-match-start-not-after-pos-here) - (<= pos-here (el-search--end-of-sexp)))))) - (at-a-match - (and largest-match-start-not-after-pos-here - (or (= pos-here largest-match-start-not-after-pos-here) - at-a-match-but-not-at-match-beginning)))) - (when (or at-a-match-but-not-at-match-beginning - (not at-a-match)) - (cl-decf matches-<=-here) - (cl-decf matches-<=-here-in-defun)) - (if at-a-match - (el-search--message-no-log - "%s %d/%d %s" - (let ((head (el-search-object-head el-search--current-search))) - (or (el-search-head-file head) - (buffer-name (el-search-head-buffer head)))) - matches-<=-here - total-matches - (propertize - (format (pcase (save-excursion - (goto-char (car defun-bounds)) - (el-search-read (current-buffer))) - (`(,a ,b . ,_) (format "(%s %%d/%%d)" - (truncate-string-to-width - (format "%S %S" a b) - 40 nil nil 'ellipsis))) - (_ "(%d/%d)")) - matches-<=-here-in-defun total-matches-in-defun) - 'face 'shadow)) - (el-search--message-no-log - (concat "[Not at a match] " - (if (= matches-<=-here total-matches) - (format "(%s/%s <-)" matches-<=-here total-matches) - (format "(-> %s/%s)" (1+ matches-<=-here) total-matches)))))))))) - (when quit-flag (el-search-keyboard-quit 'dont-quit)))) + (when (or just-count (and el-search--success (not el-search--wrap-flag))) + (prog1 + (while-no-input + (apply (if just-count #'format #'el-search--message-no-log) + (progn + + ;; Check whether cached stream of buffer matches is still valid + (pcase el-search--buffer-match-count-data + (`(,(pred (eq el-search--current-search)) ,(pred (eq (buffer-chars-modified-tick))) . ,_)) + (_ + ;; (message "Refreshing match count data") (sit-for 1) + (redisplay) ;don't delay highlighting + (setq-local el-search--buffer-match-count-data + (let ((stream-of-buffer-matches + (seq-map #'cadr + (el-search--all-matches + (el-search-make-search + (el-search--current-pattern) + (let ((current-buffer (current-buffer))) + (lambda () (stream (list current-buffer))))))))) + (list + el-search--current-search + (buffer-chars-modified-tick) + stream-of-buffer-matches))))) + + (let ((pos-here (point)) (matches-<=-here 1) total-matches + (defun-bounds (or (el-search--bounds-of-defun) (cons (point) (point)))) + (matches-<=-here-in-defun 1) (total-matches-in-defun 0) + (largest-match-start-not-after-pos-here nil)) + (pcase-let ((`(,_ ,_ ,matches) el-search--buffer-match-count-data)) + (setq total-matches (let ((inhibit-message t)) (seq-length matches))) + (while (and (not (stream-empty-p matches)) (< (stream-first matches) (cdr defun-bounds))) + (when (<= (stream-first matches) pos-here) + (setq largest-match-start-not-after-pos-here (stream-first matches)) + (unless (= (stream-first matches) pos-here) + (cl-incf matches-<=-here))) + (when (<= (car defun-bounds) (stream-first matches)) + (cl-incf total-matches-in-defun) + (when (< (stream-first matches) pos-here) + (cl-incf matches-<=-here-in-defun))) + (stream-pop matches)) + (if (zerop total-matches) + (list "(No matches)") + (let* ((at-a-match-but-not-at-match-beginning + (and largest-match-start-not-after-pos-here + (and (< largest-match-start-not-after-pos-here pos-here) + (save-excursion + (goto-char largest-match-start-not-after-pos-here) + (<= pos-here (el-search--end-of-sexp)))))) + (at-a-match + (and largest-match-start-not-after-pos-here + (or (= pos-here largest-match-start-not-after-pos-here) + at-a-match-but-not-at-match-beginning)))) + (when (or at-a-match-but-not-at-match-beginning + (not at-a-match)) + (cl-decf matches-<=-here) + (cl-decf matches-<=-here-in-defun)) + (if at-a-match + (let ((buffer-or-file + (let ((head (el-search-object-head el-search--current-search))) + (or (el-search-head-file head) + (buffer-name (el-search-head-buffer head)))))) + (if just-count + (list "%d/%d" matches-<=-here total-matches) + (list + "%s %d/%d %s" + buffer-or-file + matches-<=-here + total-matches + (propertize + (format (pcase (save-excursion + (goto-char (car defun-bounds)) + (el-search-read (current-buffer))) + (`(,a ,b . ,_) (format "(%s %%d/%%d)" + (truncate-string-to-width + (format "%S %S" a b) + 40 nil nil 'ellipsis))) + (_ "(%d/%d)")) + matches-<=-here-in-defun total-matches-in-defun) + 'face 'shadow)))) + (list + (concat (if (not just-count) "[Not at a match] " "") + (if (= matches-<=-here total-matches) + (format "(%s/%s <-)" matches-<=-here total-matches) + (format "(-> %s/%s)" (1+ matches-<=-here) total-matches)))))))))))) + (when quit-flag (el-search-keyboard-quit 'dont-quit))))) (defun el-search-hl-other-matches (matcher) "Highlight all visible matches. @@ -2464,18 +2597,39 @@ local binding of `window-scroll-functions'." (setq el-search-hl-other-overlays '()) (el-search-rehide-invisible)) -(defun el-search-hl-post-command-fun () - (pcase this-command - ('el-search-query-replace) - ((guard (el-search--entering-prefix-arg-p))) ; don't hide key input feedback - ('el-search-pattern (el-search-display-match-count)) - ((pred el-search-keep-session-command-p)) - (_ (unless el-search-keep-hl - (el-search-hl-remove) - (remove-hook 'post-command-hook 'el-search-hl-post-command-fun t) - (setq el-search--temp-buffer-flag nil) - (el-search-kill-left-over-search-buffers) - (el-search-close-quick-help-maybe))))) +(defvar el-search-hl-post-command-fun--last-animator nil) + +(defun el-search-hl-post-command-fun (&optional stop) + (cl-flet ((stop (lambda () + (el-search-hl-remove) + (remove-hook 'post-command-hook 'el-search-hl-post-command-fun t) + (setq el-search--temp-buffer-flag nil) + (el-search-kill-left-over-search-buffers) + (el-search-close-quick-help-maybe)))) + (pcase this-command + ((guard stop) (stop)) + ('el-search-query-replace) + ((guard (el-search--entering-prefix-arg-p))) ; don't hide key input feedback + ('el-search-pattern + (let ((el-search--search-pattern-1-do-fun + (if (eq this-command last-command) + el-search-hl-post-command-fun--last-animator + (setq el-search-hl-post-command-fun--last-animator + (el-search--make-display-animation-function + (lambda (icon) + (let ((inhibit-message nil)) + (el-search--message-no-log + "%s %s" + (let ((head (el-search-object-head el-search--current-search))) + (or (el-search-head-file head) + (el-search-head-buffer head))) + icon)))))))) + (condition-case err (el-search-display-match-count) + (error + (el-search--message-no-log + "Error counting matches: %s" (error-message-string err)))))) + ((pred el-search-keep-session-command-p)) + (_ (unless el-search-keep-hl (stop)))))) (defun el-search--pending-search-p () (memq #'el-search-hl-post-command-fun post-command-hook)) @@ -2626,76 +2780,78 @@ continued." (el-search--set-search-origin-maybe)) (el-search-compile-pattern-in-search el-search--current-search) (el-search-protect-search-head - (unwind-protect - (let* ((old-current-buffer (current-buffer)) - (head (el-search-object-head el-search--current-search)) - (current-search-buffer - (or (el-search-head-buffer head) - (el-search--next-buffer el-search--current-search)))) - (when from-here - (cond - ((eq (current-buffer) current-search-buffer) - (setf (el-search-head-position head) (copy-marker (point)))) - ((and current-search-buffer (buffer-live-p current-search-buffer)) - (user-error "Please resume from buffer %s" (buffer-name current-search-buffer))) - (current-search-buffer - (user-error "Search head points to a killed buffer")))) - (let ((match nil) - (matcher (el-search--current-matcher)) - (heuristic-matcher (el-search--current-heuristic-matcher))) - (while (and (el-search-head-buffer head) - (not (setq match (with-current-buffer (el-search-head-buffer head) - (save-excursion - (goto-char (el-search-head-position head)) - (el-search--search-pattern-1 - matcher t nil heuristic-matcher)))))) - (el-search--next-buffer el-search--current-search)) - (if (not match) - (progn - (if (not (or el-search--success - (and from-here - (save-excursion - (goto-char (point-min)) - (el-search--search-pattern-1 matcher t nil heuristic-matcher))))) - (progn - (el-search--message-no-log "No matches") - (sit-for .7)) - (el-search--set-wrap-flag 'forward) - (let ((keys (car (where-is-internal 'el-search-pattern)))) - (el-search--message-no-log - (if keys - (format "No (more) matches - Hit %s to wrap search" - (key-description keys)) - "No (more) matches"))))) - (let (match-start) - ;; If (el-search-head-buffer head) is only a worker buffer, replace it - ;; with a buffer created with `find-file-noselect' - (with-current-buffer (el-search-head-buffer head) - (goto-char match) - (setq match-start (point)) - (when el-search--temp-file-buffer-flag - (let ((file-name buffer-file-name)) - (setq buffer-file-name nil) ;prevent f-f-ns to find this buffer - (let ((buffer-list-before (buffer-list)) - (new-buffer (find-file-noselect file-name))) - (setf (el-search-head-buffer head) new-buffer) - (unless (memq new-buffer buffer-list-before) - (with-current-buffer new-buffer - (setq-local el-search--temp-buffer-flag t))))))) - (pop-to-buffer (el-search-head-buffer head) el-search-display-next-buffer-action) - (goto-char match-start)) - (setf (el-search-object-last-match el-search--current-search) - (copy-marker (point))) - (setf (el-search-head-position head) - (copy-marker (point))) - (el-search-hl-sexp) - (unless (and (eq this-command last-command) - el-search--success - (eq (current-buffer) old-current-buffer)) - (el-search-hl-other-matches matcher)) - (setq el-search--success t))) - (el-search-prefix-key-maybe-set-transient-map)) - (el-search-kill-left-over-search-buffers)))) + (el-search-when-unwind + (unwind-protect + (let* ((old-current-buffer (current-buffer)) + (head (el-search-object-head el-search--current-search)) + (current-search-buffer + (or (el-search-head-buffer head) + (el-search--next-buffer el-search--current-search)))) + (when from-here + (cond + ((eq (current-buffer) current-search-buffer) + (setf (el-search-head-position head) (copy-marker (point)))) + ((and current-search-buffer (buffer-live-p current-search-buffer)) + (user-error "Please resume from buffer %s" (buffer-name current-search-buffer))) + (current-search-buffer + (user-error "Search head points to a killed buffer")))) + (let ((match nil) + (matcher (el-search--current-matcher)) + (heuristic-matcher (el-search--current-heuristic-matcher))) + (while (and (el-search-head-buffer head) + (not (setq match (with-current-buffer (el-search-head-buffer head) + (save-excursion + (goto-char (el-search-head-position head)) + (el-search--search-pattern-1 + matcher t nil heuristic-matcher)))))) + (el-search--next-buffer el-search--current-search)) + (if (not match) + (progn + (if (not (or el-search--success + (and from-here + (save-excursion + (goto-char (point-min)) + (el-search--search-pattern-1 matcher t nil heuristic-matcher))))) + (progn + (el-search--message-no-log "No matches") + (sit-for .7)) + (el-search--set-wrap-flag 'forward) + (let ((keys (car (where-is-internal 'el-search-pattern)))) + (el-search--message-no-log + (if keys + (format "No (more) matches - Hit %s to wrap search" + (key-description keys)) + "No (more) matches"))))) + (let (match-start) + ;; If (el-search-head-buffer head) is only a worker buffer, replace it + ;; with a buffer created with `find-file-noselect' + (with-current-buffer (el-search-head-buffer head) + (goto-char match) + (setq match-start (point)) + (when el-search--temp-file-buffer-flag + (let ((file-name buffer-file-name)) + (setq buffer-file-name nil) ;prevent f-f-ns to find this buffer + (let ((buffer-list-before (buffer-list)) + (new-buffer (find-file-noselect file-name))) + (setf (el-search-head-buffer head) new-buffer) + (unless (memq new-buffer buffer-list-before) + (with-current-buffer new-buffer + (setq-local el-search--temp-buffer-flag t))))))) + (pop-to-buffer (el-search-head-buffer head) el-search-display-next-buffer-action) + (goto-char match-start)) + (setf (el-search-object-last-match el-search--current-search) + (copy-marker (point))) + (setf (el-search-head-position head) + (copy-marker (point))) + (el-search-hl-sexp) + (unless (and (eq this-command last-command) + el-search--success + (eq (current-buffer) old-current-buffer)) + (el-search-hl-other-matches matcher)) + (setq el-search--success t))) + (el-search-prefix-key-maybe-set-transient-map)) + (el-search-kill-left-over-search-buffers)) + (el-search-hl-post-command-fun 'stop)))) (defun el-search-skip-directory (directory) "Skip all subsequent matches in files located under DIRECTORY." @@ -2716,14 +2872,14 @@ continued." (string-match-p "\\`\\.\\." (file-relative-name buffer-or-file-name directory))))) (el-search-prefix-key-maybe-set-transient-map)) -(defun el-search-pattern--interactive (&optional prompt) +(defun el-search-pattern--interactive (&optional prompt display-match-count) (list (if (or ;;Hack to make a pop-up buffer search from occur "stay active" (el-search--pending-search-p) (and (eq this-command last-command) (or el-search--success el-search--wrap-flag))) (el-search--current-pattern) - (el-search-read-pattern-for-interactive prompt)))) + (el-search-read-pattern-for-interactive prompt display-match-count)))) ;;;###autoload (defun el-search-pattern (pattern) @@ -2747,7 +2903,7 @@ types defined with `el-search-defpattern'. See `el-search-defined-patterns' for a list of defined patterns." (declare (interactive-only el-search-forward)) - (interactive (el-search-pattern--interactive)) + (interactive (el-search-pattern--interactive nil 'display-match-count)) (cond ((eq el-search--wrap-flag 'forward) (progn @@ -2914,7 +3070,7 @@ direction. See `el-search-forward' for details." "Search the current buffer backward for matches of PATTERN. See the command `el-search-pattern' for more information." (declare (interactive-only el-search-backward)) - (interactive (el-search-pattern--interactive)) + (interactive (el-search-pattern--interactive nil 'display-match-count)) (if (eq pattern (el-search--current-pattern)) (progn (el-search-compile-pattern-in-search el-search--current-search) @@ -4226,8 +4382,10 @@ Don't save this buffer and all following buffers; don't ask again")))) (el-search-read (car el-search-query-replace-history))) (car el-search-query-replace-history) (car el-search-pattern-history)))))) - (el-search--read-pattern "Query replace pattern: " nil - 'el-search-query-replace-history))) + (minibuffer-with-setup-hook #'el-search-read-pattern-setup-mb-hints + (let ((el-search--reading-input-for-query-replace t)) + (el-search--read-pattern "Query replace pattern: " nil + 'el-search-query-replace-history))))) from to read-from read-to) (with-temp-buffer (emacs-lisp-mode)