Function: evil-ex-substitute
evil-ex-substitute is an interactive and byte-compiled function
defined in evil-commands.el.
Signature
(evil-ex-substitute BEG END &optional PATTERN REPLACEMENT FLAGS)
Documentation
The Ex substitute command.
[BEG,END]substitute/PATTERN/REPLACEMENT/FLAGS
Key Bindings
Source Code
;; Defined in ~/.emacs.d/elpa/evil-20251108.138/evil-commands.el
(evil-define-operator evil-ex-substitute
(beg end pattern replacement flags)
"The Ex substitute command.
\[BEG,END]substitute/PATTERN/REPLACEMENT/FLAGS"
:repeat nil
:jump t
:move-point nil
:motion evil-line
(interactive "<r><s/>")
(evil-ex-nohighlight)
(unless pattern (user-error "No pattern given"))
(setq replacement (or replacement "")
flags (append flags)
evil-ex-last-was-search nil
evil-ex-substitute-pattern pattern
evil-ex-substitute-replacement replacement
evil-ex-substitute-flags flags)
(let* ((inhibit-field-text-motion t)
(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)
(regex (evil-ex-pattern-regex pattern))
(nreplaced 0)
(orig-point (point-marker))
(last-point (point))
(whole-line (evil-ex-pattern-whole-line pattern))
(evil-ex-substitute-overlay (make-overlay (point) (point)))
(end-marker (move-marker (make-marker) end))
(use-reveal confirm)
match-data
reveal-open-spots
transient-mark-mode)
(unwind-protect
(catch 'exit-search
(isearch-update-ring (setq isearch-string regex) t)
(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)
(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* ((match-beg (match-beginning 0))
(match-end (match-end 0))
(zero-length-match (= match-beg match-end))
match-contains-newline)
(goto-char match-beg)
(when (and (= match-beg end-marker) (> end-marker beg) (bolp))
;; This line is not included due to range being exclusive
(throw 'exit-search nil))
(setq match-data (match-data t match-data)
match-contains-newline (search-forward "\n" match-end t))
(goto-char match-end)
(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 nil))
(?a (setq confirm nil)
(throw 'exit-read-char nil))
((?q ?l ?\C-\[) (throw 'exit-search nil))
(?\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)
(replace-match next-replacement (not case-replace))))
(cl-incf nreplaced))
(setq last-point (point))
(cond ((>= (point) end-marker)
;; Don't want to perform multiple replacements at the end
;; of the search region.
(throw 'exit-search nil))
((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 (>= (point) end-marker) (throw 'exit-search nil)))
;; 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 nil))
(forward-char)))))))
(evil-ex-delete-hl 'evil-ex-substitute)
(delete-overlay evil-ex-substitute-overlay)
(goto-char (if count-only orig-point last-point))
(move-marker orig-point nil)
(move-marker end-marker nil)
(when use-reveal
(evil-revert-reveal reveal-open-spots)))
(evil--ex-substitute-final-message nreplaced flags)
(if (and (= nreplaced 0) evil-ex-point)
(goto-char evil-ex-point)
(evil-first-non-blank))))