emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/evil 22d76a4080: Restore match data after eval:ing replace


From: ELPA Syncer
Subject: [nongnu] elpa/evil 22d76a4080: Restore match data after eval:ing replacement
Date: Mon, 20 Feb 2023 14:01:34 -0500 (EST)

branch: elpa/evil
commit 22d76a4080e40381aae194c94f3bc16ba67a330a
Author: Axel Forsman <axelsfor@gmail.com>
Commit: Axel Forsman <axelsfor@gmail.com>

    Restore match data after eval:ing replacement
    
    This fixes #1481.
    
    Also pass along the number of the current replacement to function called
    to generate each replacement, which fixes #1411.
---
 evil-commands.el | 203 +++++++++++++++++++++++++++----------------------------
 evil-common.el   |  29 +++-----
 evil-search.el   |  21 +++---
 evil-tests.el    |  10 ++-
 4 files changed, 127 insertions(+), 136 deletions(-)

diff --git a/evil-commands.el b/evil-commands.el
index b66268def7..e8cdb2ebda 100644
--- a/evil-commands.el
+++ b/evil-commands.el
@@ -3849,129 +3849,124 @@ reveal.el. OPEN-SPOTS is a local version of 
`reveal-open-spots'."
   :motion evil-line
   (interactive "<r><s/>")
   (evil-ex-nohighlight)
-  (unless pattern
-    (user-error "No pattern given"))
-  (setq replacement (or replacement ""))
-  (setq evil-ex-last-was-search nil)
+  (unless pattern (user-error "No pattern given"))
+  (setq replacement (or replacement "")
+        evil-ex-last-was-search nil
+        evil-ex-substitute-pattern pattern
+        evil-ex-substitute-replacement replacement)
   (let* ((flags (append flags nil))
          (count-only (memq ?n flags))
          (confirm (and (memq ?c flags) (not count-only)))
          (case-fold-search (evil-ex-pattern-ignore-case pattern))
          (case-replace case-fold-search)
-         (evil-ex-substitute-regex (evil-ex-pattern-regex pattern))
-         (evil-ex-substitute-nreplaced 0)
-         (evil-ex-substitute-last-point (point))
+         (regex (evil-ex-pattern-regex pattern))
+         (nreplaced 0)
+         (last-point (point))
          (whole-line (evil-ex-pattern-whole-line pattern))
          (evil-ex-substitute-overlay (make-overlay (point) (point)))
          (orig-point-marker (move-marker (make-marker) (point)))
          (end-marker (move-marker (make-marker) end))
          (use-reveal confirm)
          (match-end (make-marker))
+         match-data
          reveal-open-spots
          transient-mark-mode)
-    (setq evil-ex-substitute-pattern pattern
-          evil-ex-substitute-replacement replacement
-          evil-ex-substitute-flags flags
-          isearch-string evil-ex-substitute-regex)
-    (isearch-update-ring evil-ex-substitute-regex t)
+    (setq evil-ex-substitute-flags flags
+          isearch-string regex)
+    (isearch-update-ring regex t)
     (unwind-protect
-        (progn
+        (catch 'exit-search
           (evil-ex-hl-change 'evil-ex-substitute pattern)
           (overlay-put evil-ex-substitute-overlay 'face 'isearch)
           (overlay-put evil-ex-substitute-overlay 'priority 1001)
           (goto-char beg)
-          (catch 'exit-search
-            (while (re-search-forward evil-ex-substitute-regex end-marker t)
-              (unless (and query-replace-skip-read-only
-                           (text-property-any (match-beginning 0) (match-end 
0) 'read-only t))
-                (let ((inhibit-field-text-motion t)
-                      (match-beg (match-beginning 0))
-                      (match-data (match-data))
-                      match-contains-newline zero-length-match)
-                  (move-marker match-end (match-end 0))
-                  (goto-char match-beg)
-                  (setq match-contains-newline (< (line-end-position) 
match-end)
-                        zero-length-match (= match-beg match-end))
-                  (when (and (= match-beg end-marker) (> end-marker beg) 
(bolp))
-                    ;; This line is not included due to range being exclusive
-                    (throw 'exit-search t))
-                  (setq evil-ex-substitute-last-point match-beg)
-                  (if confirm
-                      (let ((prompt
-                             (format "Replace %s with %s (y/n/a/q/l/^E/^Y)? "
-                                     (match-string 0)
-                                     (evil-match-substitute-replacement
-                                      evil-ex-substitute-replacement
-                                      (not case-replace))))
-                            (search-invisible t)
-                            response)
-                        (move-overlay evil-ex-substitute-overlay match-beg 
match-end)
-                        ;; Simulate `reveal-mode'. `reveal-mode' uses
-                        ;; `post-command-hook' but that won't work here.
-                        (when use-reveal
-                          (reveal-post-command))
-                        (catch 'exit-read-char
-                          (while (setq response (read-char prompt))
-                            (when (member response '(?y ?a ?l))
-                              (unless count-only
-                                (set-match-data match-data)
-                                (evil-replace-match 
evil-ex-substitute-replacement
-                                                    (not case-replace)))
-                              (setq evil-ex-substitute-nreplaced
-                                    (1+ evil-ex-substitute-nreplaced))
-                              (evil-ex-hl-set-region 'evil-ex-substitute
-                                                     (save-excursion
-                                                       (forward-line)
-                                                       (point))
-                                                     (evil-ex-hl-get-max
-                                                      'evil-ex-substitute)))
-                            (cl-case response
-                              ((?y ?n) (throw 'exit-read-char t))
-                              (?a (setq confirm nil)
-                                  (throw 'exit-read-char t))
-                              ((?q ?l ?\C-\[) (throw 'exit-search t))
-                              (?\C-e (evil-scroll-line-down 1))
-                              (?\C-y (evil-scroll-line-up 1))))))
-                    (setq evil-ex-substitute-nreplaced
-                          (1+ evil-ex-substitute-nreplaced))
-                    (unless count-only
+          (while (re-search-forward regex end-marker t)
+            (unless (and query-replace-skip-read-only
+                         (text-property-any (match-beginning 0) (match-end 0) 
'read-only t))
+              (let ((inhibit-field-text-motion t)
+                    (match-beg (match-beginning 0))
+                    match-contains-newline zero-length-match)
+                (move-marker match-end (match-end 0))
+                (goto-char match-beg)
+                (setq match-data (match-data t match-data)
+                      match-contains-newline (< (line-end-position) match-end)
+                      zero-length-match (= match-beg match-end))
+                (when (and (= match-beg end-marker) (> end-marker beg) (bolp))
+                  ;; This line is not included due to range being exclusive
+                  (throw 'exit-search t))
+                (setq last-point match-beg)
+                (if confirm
+                    (let* ((next-replacement
+                            (if (stringp replacement) replacement
+                              (funcall (car replacement) (cdr replacement)
+                                       nreplaced)))
+                           (prompt
+                            (format "Replace %s with %s (y/n/a/q/l/^E/^Y)? "
+                                    (match-string 0)
+                                    (match-substitute-replacement
+                                     next-replacement (not case-replace))))
+                           (search-invisible t)
+                           response)
+                      (move-overlay evil-ex-substitute-overlay match-beg 
match-end)
+                      ;; Simulate `reveal-mode'. `reveal-mode' uses
+                      ;; `post-command-hook' but that won't work here.
+                      (when use-reveal
+                        (reveal-post-command))
+                      (catch 'exit-read-char
+                        (while (setq response (read-char prompt))
+                          (when (member response '(?y ?a ?l))
+                            (unless count-only
+                              (set-match-data match-data)
+                              (replace-match next-replacement (not 
case-replace)))
+                            (cl-incf nreplaced)
+                            (evil-ex-hl-set-region
+                             'evil-ex-substitute
+                             (line-beginning-position 2)
+                             (evil-ex-hl-get-max 'evil-ex-substitute)))
+                          (cl-case response
+                            ((?y ?n) (throw 'exit-read-char t))
+                            (?a (setq confirm nil)
+                                (throw 'exit-read-char t))
+                            ((?q ?l ?\C-\[) (throw 'exit-search t))
+                            (?\C-e (evil-scroll-line-down 1))
+                            (?\C-y (evil-scroll-line-up 1))))))
+                  (unless count-only
+                    (let ((next-replacement
+                           (if (stringp replacement) replacement
+                             (funcall (car replacement) (cdr replacement)
+                                      nreplaced))))
                       (set-match-data match-data)
-                      (evil-replace-match evil-ex-substitute-replacement
-                                          (not case-replace))))
-                  (goto-char match-end)
-                  (cond ((>= (point) end-marker)
-                         ;; Don't want to perform multiple replacements at the 
end
-                         ;; of the search region.
-                         (throw 'exit-search t))
-                        ((and (not whole-line)
-                              (not match-contains-newline))
-                         (forward-line)
-                         ;; forward-line just moves to the end of the line on 
the
-                         ;; last line of the buffer.
-                         (when (or (eobp)
-                                   (> (point) end-marker))
-                           (throw 'exit-search t)))
-                        ;; For zero-length matches check to see if point won't
-                        ;; move next time. This is a problem when matching the
-                        ;; regexp "$" because we can enter an infinite loop,
-                        ;; repeatedly matching the same character
-                        ((and zero-length-match
-                              (let ((pnt (point)))
-                                (save-excursion
-                                  (and
-                                   (re-search-forward
-                                    evil-ex-substitute-regex end-marker t)
-                                   (= pnt (point))))))
-                         (if (or (eobp)
-                                 (>= (point) end-marker))
-                             (throw 'exit-search t)
-                           (forward-char)))))))))
+                      (replace-match next-replacement (not case-replace))))
+                  (cl-incf nreplaced))
+                (goto-char match-end)
+                (cond ((>= (point) end-marker)
+                       ;; Don't want to perform multiple replacements at the 
end
+                       ;; of the search region.
+                       (throw 'exit-search t))
+                      ((and (not whole-line)
+                            (not match-contains-newline))
+                       (forward-line)
+                       ;; forward-line just moves to the end of the line on the
+                       ;; last line of the buffer.
+                       (when (or (eobp)
+                                 (> (point) end-marker))
+                         (throw 'exit-search t)))
+                      ;; For zero-length matches check to see if point won't
+                      ;; move next time. This is a problem when matching the
+                      ;; regexp "$" because we can enter an infinite loop,
+                      ;; repeatedly matching the same character
+                      ((and zero-length-match
+                            (let ((pnt (point)))
+                              (save-excursion
+                                (and (re-search-forward regex end-marker t)
+                                     (= pnt (point))))))
+                       (when (eobp) (throw 'exit-search t))
+                       (forward-char)))))))
       (evil-ex-delete-hl 'evil-ex-substitute)
       (delete-overlay evil-ex-substitute-overlay)
 
-      (if count-only
-          (goto-char orig-point-marker)
-        (goto-char evil-ex-substitute-last-point))
+      (goto-char (if count-only orig-point-marker
+                   last-point))
 
       (move-marker orig-point-marker nil)
       (move-marker end-marker nil)
@@ -3981,9 +3976,9 @@ reveal.el. OPEN-SPOTS is a local version of 
`reveal-open-spots'."
 
     (message "%s %d occurrence%s"
              (if count-only "Found" "Replaced")
-             evil-ex-substitute-nreplaced
-             (if (/= evil-ex-substitute-nreplaced 1) "s" ""))
-    (if (and (= 0 evil-ex-substitute-nreplaced) evil-ex-point)
+             nreplaced
+             (if (/= nreplaced 1) "s" ""))
+    (if (and (= 0 nreplaced) evil-ex-point)
         (goto-char evil-ex-point)
       (evil-first-non-blank))))
 
diff --git a/evil-common.el b/evil-common.el
index 8db8d3c8bf..ecf0bdd306 100644
--- a/evil-common.el
+++ b/evil-common.el
@@ -3912,26 +3912,17 @@ The magic character , (comma) start an Emacs-lisp 
expression."
       (cons 'replace-eval-replacement
             (car (evil-compile-subreplacement to))))))
 
-(defun evil-replace-match (replacement &optional fixedcase string)
-  "Replace text match by last search with REPLACEMENT.
-If REPLACEMENT is an expression it will be evaluated to compute
-the replacement text, otherwise the function behaves as
-`replace-match'."
-  (if (stringp replacement)
-      (replace-match replacement fixedcase nil string)
-    (replace-match (funcall (car replacement)
-                            (cdr replacement)
-                            0)
-                   fixedcase nil string)))
-
 (defun evil-match-substitute-replacement (replacement &optional fixedcase 
string)
-  "Return REPLACEMENT as it will be inserted by `evil-replace-match'."
-  (if (stringp replacement)
-      (match-substitute-replacement replacement fixedcase nil string)
-    (match-substitute-replacement (funcall (car replacement)
-                                           (cdr replacement)
-                                           0)
-                                  fixedcase nil string)))
+  "Return REPLACEMENT as it will be inserted by `evil-replace-match'.
+If REPLACEMENT is an expression it will be evaluated to compute the
+replacement text first."
+  (match-substitute-replacement
+   (if (stringp replacement)
+       replacement
+     (funcall (car replacement)
+              (cdr replacement)
+              0))
+   fixedcase nil string))
 
 ;;; Alignment
 
diff --git a/evil-search.el b/evil-search.el
index a662a730dc..b42d924eef 100644
--- a/evil-search.el
+++ b/evil-search.el
@@ -1240,18 +1240,15 @@ This handler highlights the pattern of the current 
substitution."
 
 (defun evil-ex-pattern-update-replacement (_hl overlay)
   "Update the replacement display."
-  (when (fboundp 'match-substitute-replacement)
-    (let ((fixedcase (not case-replace))
-          repl)
-      (setq repl (if evil-ex-substitute-current-replacement
-                     (evil-match-substitute-replacement
-                      evil-ex-substitute-current-replacement
-                      fixedcase)
-                   ""))
-      (put-text-property 0 (length repl)
-                         'face 'evil-ex-substitute-replacement
-                         repl)
-      (overlay-put overlay 'after-string repl))))
+  (let ((repl (if evil-ex-substitute-current-replacement
+                  (evil-match-substitute-replacement
+                   evil-ex-substitute-current-replacement
+                   (not case-replace))
+                "")))
+    (put-text-property 0 (length repl)
+                       'face 'evil-ex-substitute-replacement
+                       repl)
+    (overlay-put overlay 'after-string repl)))
 
 (defun evil-ex-parse-global (string)
   "Parse STRING as a global argument."
diff --git a/evil-tests.el b/evil-tests.el
index ebb673beb8..1940333031 100644
--- a/evil-tests.el
+++ b/evil-tests.el
@@ -7849,7 +7849,15 @@ golf h[o]>tel")))
     (evil-test-buffer
       "[f]oo"
       (":s/foo")
-      "")))
+      ""))
+  (ert-info ("Use replace count in substitution")
+    (evil-test-buffer "xx"
+      (":s/./\\#/g")
+      "01"))
+  (ert-info ("Substitute with `calc' Lisp expression")
+    (evil-test-buffer "1 + 2"
+      (":s/.*/\\,(calc-eval \\0)")
+      "3")))
 
 (ert-deftest evil-test-ex-repeat-substitute-replacement ()
   "Test `evil-ex-substitute' with repeating of previous substitutions."



reply via email to

[Prev in Thread] Current Thread [Next in Thread]