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

From: Juri Linkov <[email-masked]>
Date: Fri, 01 Feb 2013 02:17:33 +0200

> A better fix is to say that isearch-search-fun-function should return
> a function that does not pay attention to isearch-* variables.

It is possible to construct a lambda for `isearch-word' in
`isearch-search-fun-default' that won't use isearch-* variables.
Rewriting more complex functions like `minibuffer-history-isearch-search'
would be more tricky.  And may be some external packages use global values too.
Also there are some variables that still will use the global values like
using `search-whitespace-regexp' in `search-forward-lax-whitespace'
(currently this shouldn't cause a problem since replace.el doesn't use
a replace-specific counterpart option for `search-whitespace-regexp';
introducing an option `replace-whitespace-regexp' might break this).
I'll try to do this in trunk.

Regarding fixing the regression in the emacs-24 branch, I propose a patch
that let-binds isearch-* variables in the same place where `search-function'
is funcalled.  I believe this is a more reliable and less error-prone fix.

=== modified file 'lisp/replace.el'
--- lisp/replace.el	2013-01-01 09:11:05 +0000
+++ lisp/replace.el	2013-02-01 00:15:31 +0000
@@ -1819,19 +1819,6 @@ (defun perform-replace (from-string repl
 	    case-fold-search))
          (nocasify (not (and case-replace case-fold-search)))
          (literal (or (not regexp-flag) (eq regexp-flag 'literal)))
-         (search-function
-	  (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))))
          (search-string from-string)
          (real-match-data nil)       ; The match data for the current match.
          (next-replacement nil)
@@ -1894,6 +1881,26 @@ (defun perform-replace (from-string repl
 	;; Loop finding occurrences that perhaps should be replaced.
 	(while (and keep-going
 		    (not (or (eobp) (and limit (>= (point) limit))))
+		    ;; Let-bind global isearch-* variables to values used
+		    ;; to search the next replacement.  These let-bindings
+		    ;; should be effective both at the time of calling
+		    ;; `isearch-search-fun-default' and also at the
+		    ;; time of funcalling `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-adjusted nil)
+			   (isearch-nonincremental t)
+			   (isearch-forward t)
+			   (search-function
+			    (or (if regexp-flag
+				    replace-re-search-function
+				  replace-search-function)
+				(isearch-search-fun-default))))
 		    ;; Use the next match if it is already known;
 		    ;; otherwise, search for a match after moving forward
 		    ;; one char if progress is required.
@@ -1926,7 +1933,7 @@ (defun perform-replace (from-string repl
 				       (replace-match-data
 					t real-match-data)
 				     (goto-char opoint)
-				     nil))))))
+				       nil)))))))
 
 	  ;; Record whether the match is nonempty, to avoid an infinite loop
 	  ;; repeatedly matching the same empty string.