From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Juri Linkov Newsgroups: gmane.emacs.bugs Subject: bug#11746: feature request: `isearch-query-replace' should open invisible text Date: Thu, 14 Feb 2013 21:02:15 +0200 Organization: JURTA Message-ID: <87pq02btxv.fsf@mail.jurta.org> References: <87mx3z9od7.fsf@web.de> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: ger.gmane.org 1360868981 22197 80.91.229.3 (14 Feb 2013 19:09:41 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Thu, 14 Feb 2013 19:09:41 +0000 (UTC) Cc: 11746@debbugs.gnu.org To: Michael Heerdegen Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Thu Feb 14 20:10:01 2013 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1U64C0-0000R9-HG for geb-bug-gnu-emacs@m.gmane.org; Thu, 14 Feb 2013 20:10:00 +0100 Original-Received: from localhost ([::1]:43185 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U64Bg-00044g-CX for geb-bug-gnu-emacs@m.gmane.org; Thu, 14 Feb 2013 14:09:40 -0500 Original-Received: from eggs.gnu.org ([208.118.235.92]:58987) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U64AW-0003pQ-PG for bug-gnu-emacs@gnu.org; Thu, 14 Feb 2013 14:08:33 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1U64AS-0005hy-HX for bug-gnu-emacs@gnu.org; Thu, 14 Feb 2013 14:08:28 -0500 Original-Received: from debbugs.gnu.org ([140.186.70.43]:51105) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U64AS-0005hs-Ey for bug-gnu-emacs@gnu.org; Thu, 14 Feb 2013 14:08:24 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.72) (envelope-from ) id 1U64B4-0000zu-F7 for bug-gnu-emacs@gnu.org; Thu, 14 Feb 2013 14:09:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Juri Linkov Original-Sender: debbugs-submit-bounces@debbugs.gnu.org Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Thu, 14 Feb 2013 19:09:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 11746 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: Original-Received: via spool by 11746-submit@debbugs.gnu.org id=B11746.13608688963741 (code B ref 11746); Thu, 14 Feb 2013 19:09:02 +0000 Original-Received: (at 11746) by debbugs.gnu.org; 14 Feb 2013 19:08:16 +0000 Original-Received: from localhost ([127.0.0.1]:56569 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.72) (envelope-from ) id 1U64AJ-0000yG-5t for submit@debbugs.gnu.org; Thu, 14 Feb 2013 14:08:15 -0500 Original-Received: from ps18281.dreamhost.com ([69.163.218.105]:49230 helo=ps18281.dreamhostps.com) by debbugs.gnu.org with esmtp (Exim 4.72) (envelope-from ) id 1U64AG-0000y3-MZ for 11746@debbugs.gnu.org; Thu, 14 Feb 2013 14:08:14 -0500 Original-Received: from localhost (ps18281.dreamhostps.com [69.163.218.105]) by ps18281.dreamhostps.com (Postfix) with ESMTP id 005B520213CF36; Thu, 14 Feb 2013 11:07:31 -0800 (PST) In-Reply-To: <87mx3z9od7.fsf@web.de> (Michael Heerdegen's message of "Tue, 19 Jun 2012 19:56:52 +0200") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3.50 (x86_64-pc-linux-gnu) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.13 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-Received-From: 140.186.70.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.bugs:71281 Archived-At: > 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