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
next prev 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).