1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-06 06:20:55 -08:00

* lisp/replace.el (replace--push-stack, perform-replace): Use markers

Don't use integers to store match data for "long term".
Otherwise, buffer edits that occur between two steps
(e.g. via process filters of post-command-hooks) makes it invalid,
leading to very confusing behavior, e.g. after `C-M-% ... y`
the right (next) match is highlighted yet if a process-filter or
post-command-hook runs, the next `y` may replace something else
than what was highlighted.
This commit is contained in:
Stefan Monnier 2025-11-13 09:17:03 -05:00
parent 5d9eab261f
commit ff2383a00f

View file

@ -2782,19 +2782,19 @@ to a regexp that is actually used for the search.")
(defmacro replace--push-stack (replaced search-str next-replace stack) (defmacro replace--push-stack (replaced search-str next-replace stack)
(declare (indent 0) (debug (form form form gv-place))) (declare (indent 0) (debug (form form form gv-place)))
`(push (list (point) ,replaced `(push (list (point) ,replaced
;;; If the replacement has already happened, all we need is the ;; If the replacement has already happened, all we need is the
;;; current match start and end. We could get this with a trivial ;; current match start and end. We could get this with a trivial
;;; match like ;; match like
;;; (save-excursion (goto-char (match-beginning 0)) ;; (save-excursion (goto-char (match-beginning 0))
;;; (search-forward (match-string 0)) ;; (search-forward (match-string 0))
;;; (match-data t)) ;; (match-data t))
;;; if we really wanted to avoid manually constructing match data. ;; if we really wanted to avoid manually constructing match data.
;;; Adding current-buffer is necessary so that match-data calls can ;; Adding current-buffer is necessary so that match-data calls
;;; return markers which are appropriate for editing. ;; can return markers which are appropriate for editing.
(if ,replaced (if ,replaced
(list (list
(match-beginning 0) (match-end 0) (current-buffer)) (match-beginning 0) (match-end 0) (current-buffer))
(match-data t)) (match-data))
,search-str ,next-replace) ,search-str ,next-replace)
,stack)) ,stack))
@ -2962,7 +2962,7 @@ characters."
(nth 0 match-again) (nth 0 match-again)
(nth 1 match-again))) (nth 1 match-again)))
(replace-match-data (replace-match-data
t real-match-data match-again)) nil real-match-data match-again))
;; MATCH-AGAIN non-nil means accept an ;; MATCH-AGAIN non-nil means accept an
;; adjacent match. ;; adjacent match.
(match-again (match-again
@ -2972,7 +2972,7 @@ characters."
case-fold-search backward) case-fold-search backward)
;; For speed, use only integers and ;; For speed, use only integers and
;; reuse the list used last time. ;; reuse the list used last time.
(replace-match-data t real-match-data))) (replace-match-data nil real-match-data)))
((and (if backward ((and (if backward
(> (1- (point)) (point-min)) (> (1- (point)) (point-min))
(< (1+ (point)) (point-max))) (< (1+ (point)) (point-max)))
@ -2990,7 +2990,7 @@ characters."
regexp-flag delimited-flag regexp-flag delimited-flag
case-fold-search backward) case-fold-search backward)
(replace-match-data (replace-match-data
t real-match-data) nil real-match-data)
(goto-char opoint) (goto-char opoint)
nil)))))) nil))))))
@ -3082,7 +3082,7 @@ characters."
(save-excursion (save-excursion
(goto-char (nth 0 real-match-data)) (goto-char (nth 0 real-match-data))
(looking-at search-string) (looking-at search-string)
(match-data t real-match-data)))) (match-data nil real-match-data))))
;; Matched string and next-replacement-replaced ;; Matched string and next-replacement-replaced
;; stored in stack. ;; stored in stack.
(setq search-string-replaced (buffer-substring-no-properties (setq search-string-replaced (buffer-substring-no-properties
@ -3146,7 +3146,7 @@ characters."
(setq replaced (nth 1 elt) (setq replaced (nth 1 elt)
real-match-data real-match-data
(replace-match-data (replace-match-data
t real-match-data nil real-match-data
(nth 2 elt)))) (nth 2 elt))))
(message "No previous match") (message "No previous match")
(ding 'no-terminate) (ding 'no-terminate)
@ -3194,7 +3194,7 @@ characters."
(goto-char (match-beginning 0)) (goto-char (match-beginning 0))
;; We must quote the string (Bug#37073) ;; We must quote the string (Bug#37073)
(looking-at (regexp-quote search-string)) (looking-at (regexp-quote search-string))
(match-data t (nth 2 elt))) (match-data nil (nth 2 elt)))
noedit noedit
(replace-match-maybe-edit (replace-match-maybe-edit
last-replacement nocasify literal last-replacement nocasify literal
@ -3203,10 +3203,11 @@ characters."
real-match-data real-match-data
(save-excursion (save-excursion
(goto-char (match-beginning 0)) (goto-char (match-beginning 0))
(if regexp-flag (looking-at (if regexp-flag
(looking-at last-replacement) last-replacement
(looking-at (regexp-quote last-replacement))) (regexp-quote
(match-data t (nth 2 elt)))) last-replacement)))
(match-data nil (nth 2 elt))))
(when regexp-flag (when regexp-flag
(setq next-replacement (nth 4 elt))) (setq next-replacement (nth 4 elt)))
;; Set replaced nil to keep in loop ;; Set replaced nil to keep in loop
@ -3250,7 +3251,7 @@ characters."
noedit real-match-data backward) noedit real-match-data backward)
replace-count (1+ replace-count) replace-count (1+ replace-count)
real-match-data (replace-match-data real-match-data (replace-match-data
t real-match-data) nil real-match-data)
replaced t last-was-act-and-show t) replaced t last-was-act-and-show t)
(replace--push-stack (replace--push-stack
replaced replaced