From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Juri Linkov Newsgroups: gmane.emacs.bugs Subject: bug#22479: 25.0.50; isearch and query-replace histories do not remember if we were looking for symbols Date: Sun, 15 Apr 2018 00:22:50 +0300 Organization: LINKOV.NET Message-ID: <871sfhmo7r.fsf@mail.linkov.net> References: <87zivq8xp2.fsf@secretsauce.net> <87r3h2boyj.fsf@mail.linkov.net> <89D2C9D3-7CA3-49A8-9BFC-CE455C91A8A8@secretsauce.net> <87io2apqad.fsf@mail.linkov.net> <87k2mk3orm.fsf@secretsauce.net> <87bmftotph.fsf@mail.linkov.net> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: blaine.gmane.org 1523744231 3963 195.159.176.226 (14 Apr 2018 22:17:11 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Sat, 14 Apr 2018 22:17:11 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (x86_64-pc-linux-gnu) Cc: 22479@debbugs.gnu.org To: Dima Kogan Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Sun Apr 15 00:17:07 2018 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1f7TTm-0000ub-HX for geb-bug-gnu-emacs@m.gmane.org; Sun, 15 Apr 2018 00:17:06 +0200 Original-Received: from localhost ([::1]:42117 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f7TVs-0007e0-Pi for geb-bug-gnu-emacs@m.gmane.org; Sat, 14 Apr 2018 18:19:16 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:40375) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f7TVk-0007cX-13 for bug-gnu-emacs@gnu.org; Sat, 14 Apr 2018 18:19:10 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f7TVe-0000gu-W1 for bug-gnu-emacs@gnu.org; Sat, 14 Apr 2018 18:19:08 -0400 Original-Received: from debbugs.gnu.org ([208.118.235.43]:44966) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1f7TVe-0000gk-Qg for bug-gnu-emacs@gnu.org; Sat, 14 Apr 2018 18:19:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1f7TVe-00063B-Ei for bug-gnu-emacs@gnu.org; Sat, 14 Apr 2018 18:19:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Juri Linkov Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 14 Apr 2018 22:19:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 22479 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: Original-Received: via spool by 22479-submit@debbugs.gnu.org id=B22479.152374430123207 (code B ref 22479); Sat, 14 Apr 2018 22:19:02 +0000 Original-Received: (at 22479) by debbugs.gnu.org; 14 Apr 2018 22:18:21 +0000 Original-Received: from localhost ([127.0.0.1]:52863 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1f7TUy-00062E-V9 for submit@debbugs.gnu.org; Sat, 14 Apr 2018 18:18:21 -0400 Original-Received: from sub3.mail.dreamhost.com ([69.163.253.7]:56376 helo=homiemail-a12.g.dreamhost.com) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1f7TUw-000626-T6 for 22479@debbugs.gnu.org; Sat, 14 Apr 2018 18:18:19 -0400 Original-Received: from homiemail-a12.g.dreamhost.com (localhost [127.0.0.1]) by homiemail-a12.g.dreamhost.com (Postfix) with ESMTP id DA33F262065; Sat, 14 Apr 2018 15:18:17 -0700 (PDT) Original-Received: from localhost.linkov.net (m91-129-105-236.cust.tele2.ee [91.129.105.236]) (using TLSv1 with cipher DHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) (Authenticated sender: jurta@jurta.org) by homiemail-a12.g.dreamhost.com (Postfix) with ESMTPSA id 90D90262062; Sat, 14 Apr 2018 15:18:16 -0700 (PDT) In-Reply-To: <87bmftotph.fsf@mail.linkov.net> (Juri Linkov's message of "Mon, 12 Mar 2018 23:43:54 +0200") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.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" Xref: news.gmane.org gmane.emacs.bugs:145375 Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable >>> Yes, this is a harder problem. We have to remember meta-data for >>> every search history element. There are several possibilities: >>> >>> 4. Adding meta-data by text-properties to the strings in >>> =E2=80=98search-ring=E2=80=99 and =E2=80=98regexp-search-ring=E2=80= =99 poses a problem of saving >>> the values in the desktop and restoring in another session. >> >> This feels like the best solution. I looked at desktop.el, and it >> doesn't save the properties, as you say. But it could be made to. Do y= ou >> think some external packages would get broken by this change? > > This seems to be the least radical change as concluded in > https://lists.gnu.org/archive/html/emacs-devel/2018-03/msg00296.html > The patch makes the search mode to be remembered in isearch as well as > in query-replace. As predicted, the solution with using text properties caused more trouble= : 1. To be able to use =E2=80=98C-s M-p=E2=80=99 and restore a previous sym= bol isearch it was necessary to let-bind minibuffer-allow-text-properties to t in isearch-edit-string. 2. To use a previous replacement with text properties required to replace =E2=80=98substring-no-properties=E2=80=99 with =E2=80=98substring=E2=80= =99 in =E2=80=98query-replace--split-string=E2=80=99. 3. For the same purpose to use e.g. =E2=80=98M-% M-p RET=E2=80=99 also re= quired to completely rewrite =E2=80=98query-replace-descr=E2=80=99 to keep text properties = non-destructively in the replacement string. I'm not sure if I found all problems or there will be more trouble, but at least these fixes were necessary for this patch: --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=isearch-text-properties.3.patch diff --git a/lisp/isearch.el b/lisp/isearch.el index 15a1543..c0f6f92 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -1105,7 +1105,9 @@ isearch-done (if (and (> (length isearch-string) 0) (not nopush)) ;; Update the ring data. - (isearch-update-ring isearch-string isearch-regexp)) + (isearch-update-ring isearch-string isearch-regexp + `(isearch-regexp-function ,isearch-regexp-function + isearch-case-fold-search ,isearch-case-fold-search))) (let ((isearch-mode-end-hook-quit (and nopush (not edit)))) (run-hooks 'isearch-mode-end-hook)) @@ -1121,13 +1123,14 @@ isearch-done (and (not edit) isearch-recursive-edit (exit-recursive-edit))) -(defun isearch-update-ring (string &optional regexp) +(defun isearch-update-ring (string &optional regexp properties) "Add STRING to the beginning of the search ring. REGEXP if non-nil says use the regexp search ring." (add-to-history (if regexp 'regexp-search-ring 'search-ring) - string - (if regexp regexp-search-ring-max search-ring-max))) + (if properties (apply 'propertize string properties) string) + (if regexp regexp-search-ring-max search-ring-max) + t)) ;; Switching buffers should first terminate isearch-mode. ;; ;; For Emacs 19, the frame switch event is handled. @@ -1342,6 +1345,13 @@ with-isearch-suspended multi-isearch-file-list multi-isearch-file-list-new multi-isearch-buffer-list multi-isearch-buffer-list-new) + (when (memq 'isearch-regexp-function (text-properties-at 0 isearch-string)) + (setq isearch-regexp-function + (get-text-property 0 'isearch-regexp-function isearch-string))) + (when (memq 'isearch-case-fold-search (text-properties-at 0 isearch-string)) + (setq isearch-case-fold-search + (get-text-property 0 'isearch-case-fold-search isearch-string))) + ;; Restore the minibuffer message before moving point. (funcall (or isearch-message-function #'isearch-message) nil t) @@ -1408,7 +1418,9 @@ isearch-edit-string (history-add-new-input nil) ;; Binding minibuffer-history-symbol to nil is a work-around ;; for some incompatibility with gmhist. - (minibuffer-history-symbol)) + (minibuffer-history-symbol) + ;; Search string might have meta information on text properties. + (minibuffer-allow-text-properties t)) (setq isearch-new-string (read-from-minibuffer (isearch-message-prefix nil isearch-nonincremental) @@ -1836,7 +1848,11 @@ isearch-query-replace ;; `exit-recursive-edit' in `isearch-done' that terminates ;; the execution of this command when it is non-nil. ;; We call `exit-recursive-edit' explicitly at the end below. - (isearch-recursive-edit nil)) + (isearch-recursive-edit nil) + (isearch-string-propertized + (propertize isearch-string + 'isearch-regexp-function isearch-regexp-function + 'isearch-case-fold-search isearch-case-fold-search))) (isearch-done nil t) (isearch-clean-overlays) (if (and isearch-other-end @@ -1849,12 +1865,12 @@ isearch-query-replace (< (mark) (point)))))) (goto-char isearch-other-end)) (set query-replace-from-history-variable - (cons isearch-string + (cons isearch-string-propertized (symbol-value query-replace-from-history-variable))) (perform-replace - isearch-string + isearch-string-propertized (query-replace-read-to - isearch-string + isearch-string-propertized (concat "Query replace" (isearch--describe-regexp-mode (or delimited isearch-regexp-function) t) (if backward " backward" "") @@ -2562,7 +2578,13 @@ isearch-ring-adjust1 length))) (setq isearch-string (nth yank-pointer ring) isearch-message (mapconcat 'isearch-text-char-description - isearch-string ""))))) + isearch-string "")) + (when (memq 'isearch-regexp-function (text-properties-at 0 isearch-string)) + (setq isearch-regexp-function + (get-text-property 0 'isearch-regexp-function isearch-string))) + (when (memq 'isearch-case-fold-search (text-properties-at 0 isearch-string)) + (setq isearch-case-fold-search + (get-text-property 0 'isearch-case-fold-search isearch-string)))))) (defun isearch-ring-adjust (advance) ;; Helper for isearch-ring-advance and isearch-ring-retreat @@ -2778,11 +2800,17 @@ isearch-search-fun (defun isearch--lax-regexp-function-p () "Non-nil if next regexp-function call should be lax." - (not (or isearch-nonincremental - (null (car isearch-cmds)) - (eq (length isearch-string) - (length (isearch--state-string - (car isearch-cmds))))))) + ;; FIXME: maybe simpler to use this: + (or (memq this-command '(isearch-printing-char isearch-del-char)) + isearch-yank-flag) + ;; (not (or isearch-nonincremental + ;; (null (car isearch-cmds)) + ;; (eq (length isearch-string) + ;; (length (isearch--state-string + ;; (car isearch-cmds)))) + ;; ;; Search string comes from the history with text properties + ;; (memq 'isearch-regexp-function (text-properties-at 0 isearch-string)))) + ) (defun isearch-search-fun-default () "Return default functions to use for the search." diff --git a/lisp/replace.el b/lisp/replace.el index 4916cb1..b943a2e 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -147,16 +147,27 @@ replace-count See `replace-regexp' and `query-replace-regexp-eval'.") (defun query-replace-descr (string) - (mapconcat 'isearch-text-char-description string "")) + (let ((string (copy-sequence string))) + (dotimes (i (length string) string) + (let ((c (aref string i))) + (cond + ((< c ?\s) (add-text-properties + i (1+ i) + `(display ,(propertize (format "^%c" (+ c 64)) 'face 'escape-glyph)) + string)) + ((= c ?\^?) (add-text-properties + i (1+ i) + `(display ,(propertize "^?" 'face 'escape-glyph)) + string))))))) (defun query-replace--split-string (string) "Split string STRING at a substring with property `separator'." (let* ((length (length string)) (split-pos (text-property-any 0 length 'separator t string))) (if (not split-pos) - (substring-no-properties string) - (cons (substring-no-properties string 0 split-pos) - (substring-no-properties + string + (cons (substring string 0 split-pos) + (substring string (or (text-property-not-all (1+ split-pos) length 'separator t string) length) @@ -301,7 +312,9 @@ query-replace-read-args (to (if (consp from) (prog1 (cdr from) (setq from (car from))) (query-replace-read-to from prompt regexp-flag)))) (list from to - (and current-prefix-arg (not (eq current-prefix-arg '-))) + (or (and current-prefix-arg (not (eq current-prefix-arg '-))) + (and (memq 'isearch-regexp-function (text-properties-at 0 from)) + (get-text-property 0 'isearch-regexp-function from))) (and current-prefix-arg (eq current-prefix-arg '-))))) (defun query-replace (from-string to-string &optional delimited start end backward region-noncontiguous-p) @@ -2361,8 +2372,17 @@ perform-replace (message (if query-flag (apply 'propertize - (substitute-command-keys - "Query replacing %s with %s: (\\\\[help] for help) ") + (concat "Query replacing " + (if backward "backward " "") + (if delimited-flag + (or (and (symbolp delimited-flag) + (get delimited-flag + 'isearch-message-prefix)) + "word ") "") + (if regexp-flag "regexp " "") + "%s with %s: " + (substitute-command-keys + "(\\\\[help] for help) ")) minibuffer-prompt-properties)))) ;; Unless a single contiguous chunk is selected, operate on multiple chunks. @@ -2580,13 +2600,13 @@ perform-replace (with-output-to-temp-buffer "*Help*" (princ (concat "Query replacing " + (if backward "backward " "") (if delimited-flag (or (and (symbolp delimited-flag) (get delimited-flag 'isearch-message-prefix)) "word ") "") (if regexp-flag "regexp " "") - (if backward "backward " "") from-string " with " next-replacement ".\n\n" (substitute-command-keys --=-=-=--