From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Augusto Stoffel Newsgroups: gmane.emacs.bugs Subject: bug#53126: 29.0.50; [PATCH] Lazy highlight/count when reading query-replace string, etc. Date: Mon, 10 Jan 2022 18:34:18 +0100 Message-ID: <87o84jcx5x.fsf@gmail.com> References: <87sftyweb2.fsf@gmail.com> <861r1iyrvw.fsf@mail.linkov.net> <87zgo6owaf.fsf@gmail.com> <86k0f9xnrn.fsf@mail.linkov.net> <87tuedp6pl.fsf@gmail.com> <861r1g7n3b.fsf@mail.linkov.net> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="25288"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) Cc: 53126@debbugs.gnu.org To: Juri Linkov Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Mon Jan 10 18:35:50 2022 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1n6yaE-0006NL-60 for geb-bug-gnu-emacs@m.gmane-mx.org; Mon, 10 Jan 2022 18:35:50 +0100 Original-Received: from localhost ([::1]:36326 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1n6yaC-0005VA-4R for geb-bug-gnu-emacs@m.gmane-mx.org; Mon, 10 Jan 2022 12:35:48 -0500 Original-Received: from eggs.gnu.org ([209.51.188.92]:44596) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1n6yZT-0005Ul-0j for bug-gnu-emacs@gnu.org; Mon, 10 Jan 2022 12:35:03 -0500 Original-Received: from debbugs.gnu.org ([209.51.188.43]:60332) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1n6yZS-0003OP-OS for bug-gnu-emacs@gnu.org; Mon, 10 Jan 2022 12:35:02 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1n6yZS-0004Ow-DS for bug-gnu-emacs@gnu.org; Mon, 10 Jan 2022 12:35:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Augusto Stoffel Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Mon, 10 Jan 2022 17:35:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 53126 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 53126-submit@debbugs.gnu.org id=B53126.164183607216873 (code B ref 53126); Mon, 10 Jan 2022 17:35:02 +0000 Original-Received: (at 53126) by debbugs.gnu.org; 10 Jan 2022 17:34:32 +0000 Original-Received: from localhost ([127.0.0.1]:53235 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1n6yYx-0004O4-LX for submit@debbugs.gnu.org; Mon, 10 Jan 2022 12:34:32 -0500 Original-Received: from mail-wr1-f42.google.com ([209.85.221.42]:37665) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1n6yYt-0004Nj-54 for 53126@debbugs.gnu.org; Mon, 10 Jan 2022 12:34:30 -0500 Original-Received: by mail-wr1-f42.google.com with SMTP id t28so21418912wrb.4 for <53126@debbugs.gnu.org>; Mon, 10 Jan 2022 09:34:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version; bh=pKlFXI4hqbg5bUzdL9GYEL60wd8IM9vJU2PTZzc6Rrs=; b=f5aDXswxJy5RT1FyZL5Y9TKwKBs7VIQTU2tc7WEkgMjTkRYPA26bqZxke4d9fBYefP gyLUT9T5TELLj9h8N/jtmMgsqwdG6wG78sroBY7Z5DlDM1JUl2Sl19jb0qinghUPYtmq WJ3VYLumHYAAfTp/cQZuy7rBLKxLuxdMnI14/8eMY6DyapjXiDkAcEjnqbX/qhXywgt/ /Hh3L8j6/K98bBaGZhk4pfkTwW04LpOMW3vmhdrXOufOsWxc42cepRh3AZO8nEgJFmHR 46YSgiEUbPNr1mP7f5a+osKyIH/ZULCUqzMvUma+QGYQhG2oFj2SArQM9Ks8F0mKU9DU n53A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version; bh=pKlFXI4hqbg5bUzdL9GYEL60wd8IM9vJU2PTZzc6Rrs=; b=KiDJIxjwTUuuKmAtmfI7aYVhnzI3pKfx+hHoI0NeMFf8FfFO0fbxA8HaCYLr0aioUc 6w3dZxp8YubG6t3QBYLalmc+adtOBt0Wv67keaijwwum7zETN7+PQl5eW+L5HHZow3+M IoXrZpDx2CofWudWkd/+u2SSL8jWAZJ9AjeiF6mf53H0FBS3INxB7xXGSZQVGlAKyFQj EhDaLoII78ghi8lik8PXXRUqdnZBa3IM7+x6MXJr1dI9Bhy561n4RSXi5r07Cs4uT/P/ 3aTDIA+G9vLBg2Rn6U/A+mihu1cH9IWmhUJeLmBZpN5dBK2hIFzjthGIlfxbBtuaMkA7 0Vmw== X-Gm-Message-State: AOAM532EzN+C/SuxRsVvEKjjToMMuAVDIX8WLVsc1eEXtE61qkwXccZb lOsYBfnjxSFByFAw21dusSF9tf2c1gQ= X-Google-Smtp-Source: ABdhPJy1ZLRKpsF1pBvJE9ACrwl1sjUBu4muypnSj12jEsMMTx8HfqZkbmtc2FHA/ks9N2pyTJEpJA== X-Received: by 2002:adf:d226:: with SMTP id k6mr530173wrh.243.1641836061002; Mon, 10 Jan 2022 09:34:21 -0800 (PST) Original-Received: from ars3 ([2a02:8109:8ac0:56d0::23a0]) by smtp.gmail.com with ESMTPSA id l6sm9933140wry.18.2022.01.10.09.34.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 10 Jan 2022 09:34:20 -0800 (PST) In-Reply-To: <861r1g7n3b.fsf@mail.linkov.net> (Juri Linkov's message of "Sun, 09 Jan 2022 20:58:32 +0200") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list 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-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:223884 Archived-At: --=-=-= Content-Type: text/plain Hi Juri, I attached a new patch (still a sketch) that requires no changes in comint.el and simple.el. Perhaps you will find this approach more acceptable. More comments below. On Sun, 9 Jan 2022 at 20:58, Juri Linkov wrote: > It would be great to use your new variable with a function > to show replacement counts in perform-replace. IIUC, > let-binding isearch-lazy-count-display-function to > isearch-read-with-highlight-count will suppress isearch-message? > I tried this and it's relatively simple to do, but there is a problem. Suppose you want to replace all "a" with "z", and your buffer has 20 "a"s initially. Then, as you keep hitting "y" to confirm a replacement the count will be 1/20, 1/19, ..., 1/1 since the number of "a"s decrease, and the point is always at the first of the still-existing ones. But probably one should count the number of prompts, so 1/20, 2/20, ..., 20/20 I think this means `perform-replace' has to implement its own way to display a count. > I meant using simply > > (add-hook 'minibuffer-setup-hook 'isearch-read-with-highlight-setup) > > But it seems isearch-read-with-highlight-setup doesn't set > isearch-lazy-count-display-function. > I guess this could be done. But note that there are two possible types of counts: a "current/total" counter or just a "total" counter. Each use case calls for a different count style. >>> Then maybe a new feature could be named e.g. "lazy-minibuffer"? > > This feature has little to do with isearch. This is why there are > efforts to move away from the prefix isearch- for lazy-related > functions and variables, so we have now: > > lazy-count-prefix-format > lazy-count-suffix-format > lazy-highlight-buffer > lazy-highlight-buffer-max-at-a-time > lazy-highlight-cleanup > lazy-highlight-initial-delay > lazy-highlight-interval > lazy-highlight-max-at-a-time > ... > > There are still isearch-specific names like isearch-lazy-count > that enables lazy-count in isearch-mode. What would be a similar > name for the minibuffer? Maybe minibuffer-lazy-count? I see, the lazy-* names are the new ones! > > Then the prefix isearch- needs to be removed from other names too, > e.g. isearch-lazy-count-display-function -> lazy-count-display-function > isearch-read-with-highlight-setup maybe to minibuffer-lazy-highlight-setup, > etc. Yes, I agree. The names I came up with are horrible and `lazy-minibuffer' is weird, but your current suggestion is nice. By the way, I'm debating a bit whether `isearch-lazy-count-display-function' should be: 1. Either nil or function, as it is right now, 2. #'ignore by default, so similar to 1) but a bit easier to use with `add-function' 3. a hook, the main inconvenience being that it can't be easily let-bound. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Allow-reading-from-minibuffer-with-lazy-highlight-an.patch >From 471c37844f0baba925bd948e13005d2227d43f65 Mon Sep 17 00:00:00 2001 From: Augusto Stoffel Date: Sat, 8 Jan 2022 11:08:46 +0100 Subject: [PATCH 1/2] Allow reading from minibuffer with lazy highlight and match count * lisp/isearch.el (isearch-lazy-count-display-function): New variable allowing to display the lazy count in special ways. (isearch-edit-string): Add lazy highlight and count of matching text. (isearch-lazy-highlight-new-loop, isearch-lazy-highlight-buffer-update): Use `isearch-lazy-count-display-function' instead of hardcoded call to `isearch-message'. (isearch-read-with-highlight--overlay, isearch-read-with-highlight--after-change, isearch-read-with-highlight--exit, isearch-read-with-highlight-setup, isearch-read-with-highlight-count): Variable and functions implementing the lazy highlight functionality while reading from minibuffer. * lisp/simple.el (minibuffer-history-isearch-setup): Set `isearch-lazy-count-display-function' appropriately. * lisp/comint.el (comint-history-isearch-setup, comint-history-isearch-end): Set `isearch-lazy-count-display-function' appropriately. --- lisp/isearch.el | 100 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 82 insertions(+), 18 deletions(-) diff --git a/lisp/isearch.el b/lisp/isearch.el index 7593a0ec98..c10f365ee5 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -465,6 +465,9 @@ lazy-count-suffix-format :group 'lazy-count :version "27.1") +(defvar isearch-lazy-count-display-function nil + "Function called when new lazy count results are available.") + ;; Define isearch help map. @@ -1808,19 +1811,21 @@ isearch-edit-string ;; for some incompatibility with gmhist. (minibuffer-history-symbol) ;; Search string might have meta information on text properties. - (minibuffer-allow-text-properties t)) + (minibuffer-allow-text-properties t) + (isearch-lazy-count-display-function #'isearch-read-with-highlight-count)) (setq isearch-new-string - (read-from-minibuffer - (isearch-message-prefix nil isearch-nonincremental) - (cons isearch-string (1+ (or (isearch-fail-pos) - (length isearch-string)))) - minibuffer-local-isearch-map nil - (if isearch-regexp - (cons 'regexp-search-ring - (1+ (or regexp-search-ring-yank-pointer -1))) - (cons 'search-ring - (1+ (or search-ring-yank-pointer -1)))) - nil t) + (minibuffer-with-setup-hook #'isearch-read-with-highlight-setup + (read-from-minibuffer + (isearch-message-prefix nil isearch-nonincremental) + (cons isearch-string (1+ (or (isearch-fail-pos) + (length isearch-string)))) + minibuffer-local-isearch-map nil + (if isearch-regexp + (cons 'regexp-search-ring + (1+ (or regexp-search-ring-yank-pointer -1))) + (cons 'search-ring + (1+ (or search-ring-yank-pointer -1)))) + nil t)) isearch-new-message (mapconcat 'isearch-text-char-description isearch-new-string ""))))) @@ -4023,7 +4028,7 @@ isearch-lazy-highlight-new-loop isearch-lazy-highlight-window-end)))))) ;; something important did indeed change (lazy-highlight-cleanup t (not (equal isearch-string ""))) ;stop old timer - (when (and isearch-lazy-count isearch-mode (null isearch-message-function)) + (when isearch-lazy-count (when (or (equal isearch-string "") ;; Check if this place was reached by a condition above ;; other than changed window boundaries (that shouldn't @@ -4042,7 +4047,11 @@ isearch-lazy-highlight-new-loop (setq isearch-lazy-count-current nil isearch-lazy-count-total nil) ;; Delay updating the message if possible, to avoid flicker - (when (string-equal isearch-string "") (isearch-message)))) + (when (string-equal isearch-string "") + (when (and isearch-mode (null isearch-message-function)) + (isearch-message)) + (when isearch-lazy-count-display-function + (funcall isearch-lazy-count-display-function))))) (setq isearch-lazy-highlight-window-start-changed nil) (setq isearch-lazy-highlight-window-end-changed nil) (setq isearch-lazy-highlight-error isearch-error) @@ -4095,13 +4104,16 @@ isearch-lazy-highlight-new-loop 'isearch-lazy-highlight-start)))) ;; Update the current match number only in isearch-mode and ;; unless isearch-mode is used specially with isearch-message-function - (when (and isearch-lazy-count isearch-mode (null isearch-message-function)) + (when isearch-lazy-count ;; Update isearch-lazy-count-current only when it was already set ;; at the end of isearch-lazy-highlight-buffer-update (when isearch-lazy-count-current (setq isearch-lazy-count-current (gethash (point) isearch-lazy-count-hash 0)) - (isearch-message)))) + (when (and isearch-mode (null isearch-message-function)) + (isearch-message)) + (when isearch-lazy-count-display-function + (funcall isearch-lazy-count-display-function))))) (defun isearch-lazy-highlight-search (string bound) "Search ahead for the next or previous match, for lazy highlighting. @@ -4302,16 +4314,68 @@ isearch-lazy-highlight-buffer-update (setq looping nil nomore t)))) (if nomore - (when (and isearch-lazy-count isearch-mode (null isearch-message-function)) + (when isearch-lazy-count (unless isearch-lazy-count-total (setq isearch-lazy-count-total 0)) (setq isearch-lazy-count-current (gethash opoint isearch-lazy-count-hash 0)) - (isearch-message)) + (when (and isearch-mode (null isearch-message-function)) + (isearch-message)) + (when isearch-lazy-count-display-function + (funcall isearch-lazy-count-display-function))) (setq isearch-lazy-highlight-timer (run-at-time lazy-highlight-interval nil 'isearch-lazy-highlight-buffer-update))))))))) +;; Reading from minibuffer with lazy highlight and match count + +(defvar isearch-read-with-highlight--overlay nil + "Overlay for minibuffer prompt updates.") + +(defvar isearch-read-with-highlight-transform #'identity + "Function to transform minibuffer text into a `isearch-string' for highlighting.") + +(defun isearch-read-with-highlight--after-change (_beg _end _len) + "Update lazy highlight state in minibuffer selected window." + (when isearch-lazy-highlight + (let ((inhibit-redisplay t) ;; Avoid cursor flickering + (string (minibuffer-contents))) + (with-minibuffer-selected-window + (setq isearch-string (funcall isearch-read-with-highlight-transform string)) + (isearch-lazy-highlight-new-loop))))) + +(defun isearch-read-with-highlight--exit () + "Unwind changes from `isearch-read-with-highlight-setup'." + (remove-hook 'after-change-functions + #'isearch-read-with-highlight--after-change) + (remove-hook 'minibuffer-exit-hook #'isearch-read-with-highlight--exit) + (setq isearch-read-with-highlight--overlay nil) + (lazy-highlight-cleanup)) + +(defun isearch-read-with-highlight-setup () + "Set up minibuffer for lazy highlight of matches in the original window. + +This is intended to be called via `minibuffer-with-setup-hook'. +Note that several other isearch variables influence the lazy +highlighting, including `isearch-regexp' and +`isearch-lazy-count-display-function'." + (add-hook 'after-change-functions + #'isearch-read-with-highlight--after-change) + (add-hook 'minibuffer-exit-hook #'isearch-read-with-highlight--exit) + (setq isearch-read-with-highlight--overlay + (make-overlay (point-min) (point-min) (current-buffer) t t)) + (isearch-read-with-highlight--after-change nil nil nil)) + +(defun isearch-read-with-highlight-count () + "Display total match count in the minibuffer prompt." + (when isearch-read-with-highlight--overlay + (overlay-put isearch-read-with-highlight--overlay + 'before-string + (and isearch-lazy-count-total + (not isearch-error) + (format "%s " isearch-lazy-count-total))))) + + (defun isearch-resume (string regexp word forward message case-fold) "Resume an incremental search. STRING is the string or regexp searched for. -- 2.34.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-Lazy-highlight-when-reading-query-replace-text.patch >From 8a24c1cc976e003494c3526304a02de8f37b5896 Mon Sep 17 00:00:00 2001 From: Augusto Stoffel Date: Sat, 8 Jan 2022 13:15:40 +0100 Subject: [PATCH 2/2] Lazy highlight when reading query-replace text * lisp/replace.el (query-replace-read-from): Add lazy highlighting. --- lisp/replace.el | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lisp/replace.el b/lisp/replace.el index 60e507c642..31478ee4a9 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -244,6 +244,19 @@ query-replace-read-from (query-replace-descr (cdar query-replace-defaults))))) (t (format-prompt prompt nil)))) + ;; Set up lazy highlighting while reading FROM regexp. + ;; TODO: Treat the `region-noncontiguous-p' case by setting + ;; `isearch-filter-predicate'. + (isearch-lazy-highlight query-replace-highlight) + (isearch-regexp regexp-flag) + (isearch-regexp-function nil) + (isearch-case-fold-search case-fold-search) ;; TODO: the case-folding rule here is complicated... + (isearch-read-with-highlight-transform + (lambda (string) + (let ((from (query-replace--split-string string))) + (if (consp from) (car from) from)))) + (isearch-lazy-count-display-function + #'isearch-read-with-highlight-count) (from ;; The save-excursion here is in case the user marks and copies ;; a region in order to specify the minibuffer input. @@ -251,6 +264,7 @@ query-replace-read-from (save-excursion (minibuffer-with-setup-hook (lambda () + (isearch-read-with-highlight-setup) (setq-local text-property-default-nonsticky (append '((separator . t) (face . t)) text-property-default-nonsticky))) -- 2.34.1 --=-=-=--