unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Juri Linkov <juri@jurta.org>
To: Michael Heerdegen <michael_heerdegen@web.de>
Cc: 11746@debbugs.gnu.org
Subject: bug#11746: feature request: `isearch-query-replace' should open invisible text
Date: Thu, 14 Feb 2013 21:02:15 +0200	[thread overview]
Message-ID: <87pq02btxv.fsf@mail.jurta.org> (raw)
In-Reply-To: <87mx3z9od7.fsf@web.de> (Michael Heerdegen's message of "Tue, 19 Jun 2012 19:56:52 +0200")

> if you have `search-invisible' non-nil, isearch "opens" invisible
> text.  But when you hit M-% or C-M-% while searching, you loose this
> ability: point will just be put inside invisible areas, and you don't
> see what you're doing.

The recent adaptation of isearch functions to `perform-replace'
makes it easy to implement this now.

Depending on the value of `search-invisible', if `open' then M-% or C-M-%
will open invisible overlays, if `nil' then they will skip invisible text,
and if `t' they will match replacements inside invisible areas like now.

The key point is using a search loop like in `isearch-search' that
either opens invisible overlays or skips them.

BTW, a similar loop could be later added to occur and hi-lock too,
but since in occur and hi-lock it makes no sense to open overlays,
they should just skip invisible areas like in `isearch-lazy-highlight-search'.

The patch below moves the search related part of code from `perform-replace'
to a new function `replace-search', adds a loop like in `isearch-search',
and moves handling of `query-replace-skip-read-only' to this loop.

It's worth to note that `wdired-isearch-filter-read-only' already has
exactly the same condition that checks for read-only-ness, so the
same condition is duplicated for modes that set both a read-only-skipping
isearch filter and `query-replace-skip-read-only', but this is not a problem.

=== modified file 'lisp/replace.el'
--- lisp/replace.el	2013-02-01 23:38:41 +0000
+++ lisp/replace.el	2013-02-14 18:55:14 +0000
@@ -1794,6 +1796,54 @@ (defvar replace-re-search-function nil
 It is called with three arguments, as if it were
 `re-search-forward'.")
 
+(defun replace-search (search-string limit regexp-flag delimited-flag
+				     case-fold-search)
+  "Search the next occurence of SEARCH-STRING to replace."
+  ;; 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'.
+  ;; These isearch-* bindings can't be placed higher
+  ;; outside of this function because then another I-search
+  ;; used after `recursive-edit' might override them.
+  (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)	; don't use lax word mode
+	 (isearch-forward t)
+	 (search-function
+	  (or (if regexp-flag
+		  replace-re-search-function
+		replace-search-function)
+	      (isearch-search-fun-default)))
+	 (retry t)
+	 (success nil))
+    ;; Use a loop like in `isearch-search'.
+    (while retry
+      (setq success (funcall search-function search-string limit t))
+      ;; Clear RETRY unless the search predicate says
+      ;; to skip this search hit.
+      (if (or (not success)
+	      (and (run-hook-with-args-until-failure
+		    'isearch-filter-predicates
+		    (match-beginning 0) (match-end 0))
+		   (or (eq search-invisible t)
+		       (not (isearch-range-invisible
+			     (match-beginning 0) (match-end 0))))
+		   ;; Optionally ignore matches that have a read-only property.
+		   (or (not query-replace-skip-read-only)
+		       (not (text-property-not-all
+			     (match-beginning 0) (match-end 0)
+			     'read-only nil)))))
+	  (setq retry nil)))
+    success))
+
 (defun perform-replace (from-string replacements
 		        query-flag regexp-flag delimited-flag
 			&optional repeat-count map start end)
@@ -1881,29 +1931,6 @@ (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'.
-		    ;; These isearch-* bindings can't be placed higher
-		    ;; outside of this loop because then another I-search
-		    ;; used after `recursive-edit' might override them.
-		    (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) ; don't use lax word mode
-			   (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.
@@ -1916,8 +1943,9 @@ (defun perform-replace (from-string repl
 				  ;; adjacent match.
 				  (match-again
 				   (and
-				    (funcall search-function search-string
-					     limit t)
+				  (replace-search search-string limit
+						  regexp-flag delimited-flag
+						  case-fold-search)
 				    ;; For speed, use only integers and
 				    ;; reuse the list used last time.
 				    (replace-match-data t real-match-data)))
@@ -1930,13 +1958,12 @@ (defun perform-replace (from-string repl
 				   ;; if the search fails.
 				   (let ((opoint (point)))
 				     (forward-char 1)
-				     (if (funcall
-					  search-function search-string
-					  limit t)
-					 (replace-match-data
-					  t real-match-data)
+				   (if (replace-search search-string limit
+						       regexp-flag delimited-flag
+						       case-fold-search)
+				       (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.
@@ -1957,13 +1984,6 @@ (defun perform-replace (from-string repl
 			      (let ((match (match-data)))
 				(and (/= (nth 0 match) (nth 1 match))
 				     match))))))
-
-	  ;; Optionally ignore matches that have a read-only property.
-	  (unless (and query-replace-skip-read-only
-		       (text-property-not-all
-			(nth 0 real-match-data) (nth 1 real-match-data)
-			'read-only nil))
-
 	    ;; Calculate the replacement string, if necessary.
 	    (when replacements
 	      (set-match-data real-match-data)
@@ -2168,7 +2188,7 @@ (defun perform-replace (from-string repl
 				 (match-end 0)
 				 (current-buffer))
 			      (match-data t)))
-		      stack)))))
+		    stack))))
 
       (replace-dehighlight))
     (or unread-command-events






  parent reply	other threads:[~2013-02-14 19:02 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-06-19 17:56 bug#11746: feature request: `isearch-query-replace' should open invisible text Michael Heerdegen
2012-06-19 21:15 ` Juri Linkov
2013-02-14 19:02 ` Juri Linkov [this message]
2013-02-14 20:17   ` Michael Heerdegen
2013-02-15  7:54     ` Juri Linkov
2013-05-27 23:04     ` Juri Linkov
2013-05-28 22:28       ` Juri Linkov
2013-05-30  0:03         ` Juri Linkov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87pq02btxv.fsf@mail.jurta.org \
    --to=juri@jurta.org \
    --cc=11746@debbugs.gnu.org \
    --cc=michael_heerdegen@web.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).