From bc85df88bf3bee99997163b6233ff82445eac66b Mon Sep 17 00:00:00 2001 From: Augusto Stoffel Date: Thu, 17 Mar 2022 20:17:26 +0100 Subject: [PATCH] Display lazy highlight and match count in query-replace * lisp/isearch.el (isearch-query-replace): Don't clean up lazy highlight if applicable. * lisp/replace.el (query-replace-read-args, query-replace-read-to): Add lazy highlighting and count. (replace--region-filter): New function, extracted from 'perform-replace'. (perform-replace): Use 'replace--region-filter'. --- lisp/isearch.el | 21 +++++++---- lisp/replace.el | 99 ++++++++++++++++++++++++++++++++++++------------- 2 files changed, 87 insertions(+), 33 deletions(-) diff --git a/lisp/isearch.el b/lisp/isearch.el index 9b311cb49e..e93e4d8b92 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -2352,7 +2352,9 @@ isearch-query-replace (isearch-recursive-edit nil) (isearch-string-propertized (isearch-string-propertize isearch-string))) - (isearch-done nil t) + (let ((lazy-highlight-cleanup (and lazy-highlight-cleanup + (not query-replace-lazy-highlight)))) + (isearch-done nil t)) (isearch-clean-overlays) (if (and isearch-other-end (if backward @@ -2368,13 +2370,16 @@ isearch-query-replace (symbol-value query-replace-from-history-variable))) (perform-replace isearch-string-propertized - (query-replace-read-to - isearch-string-propertized - (concat "Query replace" - (isearch--describe-regexp-mode (or delimited isearch-regexp-function) t) - (if backward " backward" "") - (if (use-region-p) " in region" "")) - isearch-regexp) + (condition-case error + (query-replace-read-to + isearch-string-propertized + (concat "Query replace" + (isearch--describe-regexp-mode (or delimited isearch-regexp-function) t) + (if backward " backward" "") + (if (use-region-p) " in region" "")) + isearch-regexp) + (t (lazy-highlight-cleanup lazy-highlight-cleanup) + (signal (car error) (cdr error)))) t isearch-regexp (or delimited isearch-regexp-function) nil nil (if (use-region-p) (region-beginning)) (if (use-region-p) (region-end)) diff --git a/lisp/replace.el b/lisp/replace.el index 06be597855..a56e493d99 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -352,8 +352,15 @@ query-replace-read-to (query-replace-compile-replacement (save-excursion (let* ((history-add-new-input nil) + (count (if (and query-replace-lazy-highlight + minibuffer-lazy-count-format + isearch-lazy-count + isearch-lazy-count-total) + (format minibuffer-lazy-count-format + isearch-lazy-count-total) + "")) (to (read-from-minibuffer - (format "%s %s with: " prompt (query-replace-descr from)) + (format "%s%s %s with: " count prompt (query-replace-descr from)) nil nil nil query-replace-to-history-variable from t))) (add-to-history query-replace-to-history-variable to nil t) @@ -365,14 +372,49 @@ query-replace-read-args (unless noerror (barf-if-buffer-read-only)) (save-mark-and-excursion - (let* ((from (query-replace-read-from prompt regexp-flag)) - (to (if (consp from) (prog1 (cdr from) (setq from (car from))) - (query-replace-read-to from prompt regexp-flag)))) - (list from to - (or (and current-prefix-arg (not (eq current-prefix-arg '-))) - (and (plist-member (text-properties-at 0 from) 'isearch-regexp-function) - (get-text-property 0 'isearch-regexp-function from))) - (and current-prefix-arg (eq current-prefix-arg '-)))))) + (condition-case error + (let (;; Variables controlling lazy highlighting while reading + ;; FROM and TO. + (isearch-case-fold-search case-fold-search) + (isearch-lazy-highlight query-replace-lazy-highlight) + (isearch-regexp regexp-flag) + (isearch-regexp-function (or replace-regexp-function + (and current-prefix-arg + (not (eq current-prefix-arg '-))) + (and replace-char-fold + (not regexp-flag) + #'char-fold-to-regexp))) + (lazy-highlight-cleanup nil) + (minibuffer-lazy-highlight-transform + (lambda (string) + (let* ((split (query-replace--split-string string)) + (from-string (if (consp split) (car split) split))) + (when (and case-fold-search search-upper-case) + (setq isearch-case-fold-search + (isearch-no-upper-case-p from-string regexp-flag))) + from-string))) + from to) + (when query-replace-lazy-highlight + (add-hook 'minibuffer-setup-hook #'minibuffer-lazy-highlight-setup) + (when (use-region-p) + (letrec ((region-filter (replace--region-filter + (funcall region-extract-function 'bounds))) + (cleanup (lambda () + (remove-function isearch-filter-predicate region-filter) + (remove-hook 'minibuffer-exit-hook cleanup)))) + (add-function :after-while isearch-filter-predicate region-filter) + (add-hook 'minibuffer-exit-hook cleanup)))) + (setq from (query-replace-read-from prompt regexp-flag)) + (setq to (if (consp from) + (prog1 (cdr from) (setq from (car from))) + (query-replace-read-to from prompt regexp-flag))) + (list from to + (or (and current-prefix-arg (not (eq current-prefix-arg '-))) + (and (plist-member (text-properties-at 0 from) 'isearch-regexp-function) + (get-text-property 0 'isearch-regexp-function from))) + (and current-prefix-arg (eq current-prefix-arg '-)))) + (t (lazy-highlight-cleanup) + (signal (car error) (cdr error)))))) (defun query-replace (from-string to-string &optional delimited start end backward region-noncontiguous-p) "Replace some occurrences of FROM-STRING with TO-STRING. @@ -2773,6 +2815,26 @@ replace--push-stack ,search-str ,next-replace) ,stack)) +(defun replace--region-filter (bounds) + "Return a function that decides if a region is inside BOUNDS. +BOUNDS is a list of cons cells of the form (START . END). The +returned function takes as argument two buffer positions, START +and END." + (let ((region-bounds + (mapcar (lambda (position) + (cons (copy-marker (car position)) + (copy-marker (cdr position)))) + bounds))) + (lambda (start end) + (delq nil (mapcar + (lambda (bounds) + (and + (>= start (car bounds)) + (<= start (cdr bounds)) + (>= end (car bounds)) + (<= end (cdr bounds)))) + region-bounds))))) + (defun perform-replace (from-string replacements query-flag regexp-flag delimited-flag &optional repeat-count map start end backward region-noncontiguous-p) @@ -2857,22 +2919,9 @@ perform-replace ;; Unless a single contiguous chunk is selected, operate on multiple chunks. (when region-noncontiguous-p - (let ((region-bounds - (mapcar (lambda (position) - (cons (copy-marker (car position)) - (copy-marker (cdr position)))) - (funcall region-extract-function 'bounds)))) - (setq region-filter - (lambda (start end) - (delq nil (mapcar - (lambda (bounds) - (and - (>= start (car bounds)) - (<= start (cdr bounds)) - (>= end (car bounds)) - (<= end (cdr bounds)))) - region-bounds)))) - (add-function :after-while isearch-filter-predicate region-filter))) + (setq region-filter (replace--region-filter + (funcall region-extract-function 'bounds))) + (add-function :after-while isearch-filter-predicate region-filter)) ;; If region is active, in Transient Mark mode, operate on region. (if backward -- 2.35.1