Subject: Re: bug#13579: 24.3.50; query-replace ressurrects previous minibuffer contents

From: Juri Linkov <[email-masked]>
Date: Thu, 31 Jan 2013 02:07:04 +0200

> It is evident now from your report that the search space for replacements
> should be narrowed to the strict set of search functions defined in isearch.el.

If someone wants to perform replacements through the minibuffer history,
this can be implemented as a new separate feature like multi-buffer
replacements (where going to the previous history element is like
going to the previous buffer in a sequence.)

> This is a regression, so I propose to install the following patch to the
> emacs-24 release branch:

`isearch-search-fun-default' prevents the search from going through
the history, but it fixes only part of the problem.  Another part of
the problem is that it tried to go backwards through the history
using the global nil value of `isearch-forward' and ignoring the
let-binding t of `isearch-forward' in `perform-replace'.

That's because `isearch-forward' is not lexically bound when the
lambda in `minibuffer-history-isearch-search' is evaluated.
Now `isearch-search-fun-default' should not use that lambda,
but there is another lambda in `isearch-search-fun-default'
used for `isearch-word' mode.  It causes another regression
when using delimited replacements in the minibuffer - the let-bindings
of isearch variables in `perform-replace' such as binding
`isearch-word' to `delimited-flag' are no more effective
at the moment when the lambda in `isearch-search-fun-default'
is evaluated.

This regression can be fixed by the following patch that will let-bind
isearch-related variables at the moment when the search function
is called:

=== modified file 'lisp/replace.el'
--- lisp/replace.el	2013-01-01 09:11:05 +0000
+++ lisp/replace.el	2013-01-31 00:04:17 +0000
@@ -1823,15 +1823,17 @@ (defun perform-replace (from-string repl
 	  (or (if regexp-flag
 		  replace-re-search-function
 		replace-search-function)
-	      (let ((isearch-regexp regexp-flag)
-		    (isearch-word delimited-flag)
-		    (isearch-lax-whitespace
-		     replace-lax-whitespace)
-		    (isearch-regexp-lax-whitespace
-		     replace-regexp-lax-whitespace)
-		    (isearch-case-fold-search case-fold-search)
-		    (isearch-forward t))
-		(isearch-search-fun))))
+	      (lambda (string &optional bound noerror count)
+		(let ((isearch-regexp regexp-flag)
+		      (isearch-word delimited-flag)
+		      (isearch-lax-whitespace
+		       replace-lax-whitespace)
+		      (isearch-regexp-lax-whitespace
+		       replace-regexp-lax-whitespace)
+		      (isearch-case-fold-search case-fold-search)
+		      (isearch-nonincremental t)
+		      (isearch-forward t))
+		  (funcall (isearch-search-fun-default) string bound noerror count)))))
          (search-string from-string)
          (real-match-data nil)       ; The match data for the current match.
          (next-replacement nil)