-;;; replace.el --- replace commands for Emacs.
+;;; replace.el --- replace commands for Emacs
-;; Copyright (C) 1985, 86, 87, 92, 94, 96, 1997, 2000
+;; Copyright (C) 1985, 86, 87, 92, 94, 96, 1997, 2000, 2001
;; Free Software Foundation, Inc.
;; This file is part of GNU Emacs.
;;; Code:
(defcustom case-replace t
- "*Non-nil means query-replace should preserve case in replacements."
+ "*Non-nil means `query-replace' should preserve case in replacements."
:type 'boolean
:group 'matching)
That becomes the \"string to replace\".")
(defcustom query-replace-from-history-variable 'query-replace-history
- "History list to use for the FROM argument of query-replace commands.
+ "History list to use for the FROM argument of `query-replace' commands.
The value of this variable should be a symbol; that symbol
is used as a variable to hold a history list for the strings
or patterns to be replaced."
:version "20.3")
(defcustom query-replace-to-history-variable 'query-replace-history
- "History list to use for the TO argument of query-replace commands.
+ "History list to use for the TO argument of `query-replace' commands.
The value of this variable should be a symbol; that symbol
is used as a variable to hold a history list for replacement
strings or patterns."
:type 'symbol
:version "20.3")
+(defcustom query-replace-skip-read-only nil
+ "*Non-nil means `query-replace' and friends ignore read-only matches."
+ :type 'boolean
+ :group 'matching
+ :version "21.3")
+
(defun query-replace-read-args (string regexp-flag)
+ (barf-if-buffer-read-only)
(let (from to)
(if query-replace-interactive
(setq from (car (if regexp-flag regexp-search-ring search-ring)))
(setq from (read-from-minibuffer (format "%s: " string)
nil nil nil
query-replace-from-history-variable
- nil t)))
+ nil t))
+ ;; Warn if user types \n or \t, but don't reject the input.
+ (if (string-match "\\\\[nt]" from)
+ (let ((match (match-string 0 from)))
+ (cond
+ ((string= match "\\n")
+ (message "Note: `\\n' here doesn't match a newline; to do that, type C-q C-j instead"))
+ ((string= match "\\t")
+ (message "Note: `\\t' here doesn't match a tab; to do that, just type TAB")))
+ (sit-for 2))))
+
(setq to (read-from-minibuffer (format "%s %s with: " string from)
nil nil nil
query-replace-to-history-variable from t))
To customize possible responses, change the \"bindings\" in `query-replace-map'."
(interactive (query-replace-read-args "Query replace" nil))
- (perform-replace from-string to-string start end t nil delimited))
+ (perform-replace from-string to-string t nil delimited nil nil start end))
(define-key esc-map "%" 'query-replace)
and `\\=\\N' (where N is a digit) stands for
whatever what matched the Nth `\\(...\\)' in REGEXP."
(interactive (query-replace-read-args "Query replace regexp" t))
- (perform-replace regexp to-string start end t t delimited))
+ (perform-replace regexp to-string t t delimited nil nil start end))
(define-key esc-map [?\C-%] 'query-replace-regexp)
(defun query-replace-regexp-eval (regexp to-expr &optional delimited start end)
`prin1-to-string' with the NOESCAPE argument (which see).
For convenience, when entering TO-EXPR interactively, you can use `\\&' or
-`\\0'to stand for whatever matched the whole of REGEXP, and `\\=\\N' (where
-N is a digit) stands for whatever what matched the Nth `\\(...\\)' in REGEXP.
+`\0' to stand for whatever matched the whole of REGEXP, and `\N' (where
+N is a digit) to stand for whatever matched the Nth `\(...\)' in REGEXP.
Use `\\#&' or `\\#N' if you want a number instead of a string.
In Transient Mark mode, if the mark is active, operate on the contents
are non-nil and REGEXP has no uppercase letters.
Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
-only matches surrounded by word boundaries.
+only matches that are surrounded by word boundaries.
Fourth and fifth arg START and END specify the region to operate on."
(interactive
(let (from to start end)
;; We make TO a list because replace-match-string-symbols requires one,
;; and the user might enter a single token.
(replace-match-string-symbols to)
- (list from (car to) start end current-prefix-arg)))
+ (list from (car to) current-prefix-arg start end)))
(perform-replace regexp (cons 'replace-eval-replacement to-expr)
- start end t t delimited))
+ t t delimited nil nil start end))
(defun map-query-replace-regexp (regexp to-strings &optional n start end)
"Replace some matches for REGEXP with various strings, in rotation.
(1+ (string-match " " to-strings))))
(setq replacements (append replacements (list to-strings))
to-strings ""))))
- (perform-replace regexp replacements start end t t nil n)))
+ (perform-replace regexp replacements t t nil n nil start end)))
(defun replace-string (from-string to-string &optional delimited start end)
"Replace occurrences of FROM-STRING with TO-STRING.
\(You may need a more complex loop if FROM-STRING can match the null string
and TO-STRING is also null.)"
(interactive (query-replace-read-args "Replace string" nil))
- (perform-replace from-string to-string start end nil nil delimited))
+ (perform-replace from-string to-string nil nil delimited nil nil start end))
(defun replace-regexp (regexp to-string &optional delimited start end)
"Replace things after point matching REGEXP with TO-STRING.
(replace-match TO-STRING nil nil))
which will run faster and will not set the mark or print anything."
(interactive (query-replace-read-args "Replace regexp" t))
- (perform-replace regexp to-string start end nil t delimited))
+ (perform-replace regexp to-string nil t delimited nil nil start end))
+
\f
(defvar regexp-history nil
"History list for some commands that read regular expressions.")
+
(defalias 'delete-non-matching-lines 'keep-lines)
-(defun keep-lines (regexp)
+(defalias 'delete-matching-lines 'flush-lines)
+(defalias 'count-matches 'how-many)
+
+
+(defun keep-lines-read-args (prompt)
+ "Read arguments for `keep-lines' and friends.
+Prompt for a regexp with PROMPT.
+Value is a list, (REGEXP)."
+ (list (read-from-minibuffer prompt nil nil nil
+ 'regexp-history nil t)))
+
+(defun keep-lines (regexp &optional rstart rend)
"Delete all lines except those containing matches for REGEXP.
A match split across lines preserves all the lines it lies in.
Applies to all lines after point.
If REGEXP contains upper case characters (excluding those preceded by `\\'),
-the matching is case-sensitive."
- (interactive (list (read-from-minibuffer
- "Keep lines (containing match for regexp): "
- nil nil nil 'regexp-history nil t)))
+the matching is case-sensitive.
+
+Second and third arg RSTART and REND specify the region to operate on.
+
+Interactively, in Transient Mark mode when the mark is active, operate
+on the contents of the region. Otherwise, operate from point to the
+end of the buffer."
+
+ (interactive
+ (keep-lines-read-args "Keep lines (containing match for regexp): "))
+ (if rstart
+ (goto-char (min rstart rend))
+ (if (and transient-mark-mode mark-active)
+ (setq rstart (region-beginning)
+ rend (copy-marker (region-end)))
+ (setq rstart (point)
+ rend (point-max-marker)))
+ (goto-char rstart))
(save-excursion
(or (bolp) (forward-line 1))
(let ((start (point))
(case-fold-search (and case-fold-search
(isearch-no-upper-case-p regexp t))))
- (while (not (eobp))
+ (while (< (point) rend)
;; Start is first char not preserved by previous match.
- (if (not (re-search-forward regexp nil 'move))
- (delete-region start (point-max))
+ (if (not (re-search-forward regexp rend 'move))
+ (delete-region start rend)
(let ((end (save-excursion (goto-char (match-beginning 0))
(beginning-of-line)
(point))))
;; Now end is first char preserved by the new match.
(if (< start end)
(delete-region start end))))
- (setq start (save-excursion (forward-line 1)
- (point)))
+
+ (setq start (save-excursion (forward-line 1) (point)))
;; If the match was empty, avoid matching again at same place.
- (and (not (eobp)) (= (match-beginning 0) (match-end 0))
+ (and (< (point) rend)
+ (= (match-beginning 0) (match-end 0))
(forward-char 1))))))
-(defalias 'delete-matching-lines 'flush-lines)
-(defun flush-lines (regexp)
+
+(defun flush-lines (regexp &optional rstart rend)
"Delete lines containing matches for REGEXP.
If a match is split across lines, all the lines it lies in are deleted.
Applies to lines after point.
If REGEXP contains upper case characters (excluding those preceded by `\\'),
-the matching is case-sensitive."
- (interactive (list (read-from-minibuffer
- "Flush lines (containing match for regexp): "
- nil nil nil 'regexp-history nil t)))
+the matching is case-sensitive.
+
+Second and third arg RSTART and REND specify the region to operate on.
+
+Interactively, in Transient Mark mode when the mark is active, operate
+on the contents of the region. Otherwise, operate from point to the
+end of the buffer."
+
+ (interactive
+ (keep-lines-read-args "Flush lines (containing match for regexp): "))
+ (if rstart
+ (goto-char (min rstart rend))
+ (if (and transient-mark-mode mark-active)
+ (setq rstart (region-beginning)
+ rend (copy-marker (region-end)))
+ (setq rstart (point)
+ rend (point-max-marker)))
+ (goto-char rstart))
(let ((case-fold-search (and case-fold-search
(isearch-no-upper-case-p regexp t))))
(save-excursion
- (while (and (not (eobp))
- (re-search-forward regexp nil t))
+ (while (and (< (point) rend)
+ (re-search-forward regexp rend t))
(delete-region (save-excursion (goto-char (match-beginning 0))
(beginning-of-line)
(point))
(progn (forward-line 1) (point)))))))
-(defalias 'count-matches 'how-many)
-(defun how-many (regexp)
+
+(defun how-many (regexp &optional rstart rend)
"Print number of matches for REGEXP following point.
If REGEXP contains upper case characters (excluding those preceded by `\\'),
-the matching is case-sensitive."
- (interactive (list (read-from-minibuffer
- "How many matches for (regexp): "
- nil nil nil 'regexp-history nil t)))
- (let ((count 0) opoint
- (case-fold-search (and case-fold-search
- (isearch-no-upper-case-p regexp t))))
- (save-excursion
- (while (and (not (eobp))
- (progn (setq opoint (point))
- (re-search-forward regexp nil t)))
- (if (= opoint (point))
- (forward-char 1)
- (setq count (1+ count))))
- (message "%d occurrences" count))))
+the matching is case-sensitive.
+
+Second and third arg RSTART and REND specify the region to operate on.
+
+Interactively, in Transient Mark mode when the mark is active, operate
+on the contents of the region. Otherwise, operate from point to the
+end of the buffer."
+
+ (interactive
+ (keep-lines-read-args "How many matches for (regexp): "))
+ (save-excursion
+ (if rstart
+ (goto-char (min rstart rend))
+ (if (and transient-mark-mode mark-active)
+ (setq rstart (region-beginning)
+ rend (copy-marker (region-end)))
+ (setq rstart (point)
+ rend (point-max-marker)))
+ (goto-char rstart))
+ (let ((count 0)
+ opoint
+ (case-fold-search (and case-fold-search
+ (isearch-no-upper-case-p regexp t))))
+ (while (and (< (point) rend)
+ (progn (setq opoint (point))
+ (re-search-forward regexp rend t)))
+ (if (= opoint (point))
+ (forward-char 1)
+ (setq count (1+ count))))
+ (message "%d occurrences" count))))
+
\f
-(defvar occur-mode-map ())
-(if occur-mode-map
- ()
- (setq occur-mode-map (make-sparse-keymap))
- (define-key occur-mode-map [mouse-2] 'occur-mode-mouse-goto)
- (define-key occur-mode-map "\C-c\C-c" 'occur-mode-goto-occurrence)
- (define-key occur-mode-map "\C-m" 'occur-mode-goto-occurrence)
- (define-key occur-mode-map "\M-n" 'occur-next)
- (define-key occur-mode-map "\M-p" 'occur-prev)
- (define-key occur-mode-map "g" 'revert-buffer))
+(defvar occur-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [mouse-2] 'occur-mode-mouse-goto)
+ (define-key map "\C-c\C-c" 'occur-mode-goto-occurrence)
+ (define-key map "\C-m" 'occur-mode-goto-occurrence)
+ (define-key map "\C-o" 'occur-mode-display-occurrence)
+ (define-key map "\M-n" 'occur-next)
+ (define-key map "\M-p" 'occur-prev)
+ (define-key map "g" 'revert-buffer)
+ map)
+ "Keymap for `occur-mode'.")
(defvar occur-buffer nil
(setq mode-name "Occur")
(make-local-variable 'revert-buffer-function)
(setq revert-buffer-function 'occur-revert-function)
+ (set (make-local-variable 'revert-buffer-function) 'occur-revert-function)
(make-local-variable 'occur-buffer)
(make-local-variable 'occur-nlines)
(make-local-variable 'occur-command-arguments)
(run-hooks 'occur-mode-hook))
(defun occur-revert-function (ignore1 ignore2)
- "Handle revert-buffer for *Occur* buffers."
+ "Handle `revert-buffer' for *Occur* buffers."
(let ((args occur-command-arguments ))
(save-excursion
(set-buffer occur-buffer)
(pop-to-buffer occur-buffer)
(goto-char (marker-position pos))))
+(defun occur-mode-display-occurrence ()
+ "Display in another window the occurrence the current line describes."
+ (interactive)
+ (let ((pos (occur-mode-find-occurrence))
+ same-window-buffer-names
+ same-window-regexps
+ window)
+ (setq window (display-buffer occur-buffer))
+ ;; This is the way to set point in the proper window.
+ (save-selected-window
+ (select-window window)
+ (goto-char (marker-position pos)))))
+
(defun occur-next (&optional n)
"Move to the Nth (default 1) next match in the *Occur* buffer."
(interactive "p")
(setq input default))
input)
current-prefix-arg))
- (let ((nlines (if nlines
- (prefix-numeric-value nlines)
- list-matching-lines-default-context-lines))
- (first t)
- ;;flag to prevent printing separator for first match
- (occur-num-matches 0)
- (buffer (current-buffer))
- (dir default-directory)
- (linenum 1)
- (prevpos
- ;;position of most recent match
- (point-min))
- (case-fold-search (and case-fold-search
- (isearch-no-upper-case-p regexp t)))
- (final-context-start
- ;; Marker to the start of context immediately following
- ;; the matched text in *Occur*.
- (make-marker)))
+ (let* ((nlines (if nlines
+ (prefix-numeric-value nlines)
+ list-matching-lines-default-context-lines))
+ (current-tab-width tab-width)
+ (inhibit-read-only t)
+ ;; Minimum width of line number plus trailing colon.
+ (min-line-number-width 6)
+ ;; Width of line number prefix without the colon. Choose a
+ ;; width that's a multiple of `tab-width' in the original
+ ;; buffer so that lines in *Occur* appear right.
+ (line-number-width (1- (* (/ (- (+ min-line-number-width
+ tab-width)
+ 1)
+ tab-width)
+ tab-width)))
+ ;; Format string for line numbers.
+ (line-number-format (format "%%%dd" line-number-width))
+ (empty (make-string line-number-width ?\ ))
+ (first t)
+ ;;flag to prevent printing separator for first match
+ (occur-num-matches 0)
+ (buffer (current-buffer))
+ (dir default-directory)
+ (linenum 1)
+ (prevpos
+ ;;position of most recent match
+ (point-min))
+ (case-fold-search (and case-fold-search
+ (isearch-no-upper-case-p regexp t)))
+ (final-context-start
+ ;; Marker to the start of context immediately following
+ ;; the matched text in *Occur*.
+ (make-marker)))
;;; (save-excursion
;;; (beginning-of-line)
;;; (setq linenum (1+ (count-lines (point-min) (point))))
(goto-char (point-max)))
(save-excursion
;; Find next match, but give up if prev match was at end of buffer.
- (while (and (not (= prevpos (point-max)))
+ (while (and (not (eobp))
(re-search-forward regexp nil t))
(goto-char (match-beginning 0))
(beginning-of-line)
(setq linenum (+ linenum (count-lines prevpos (point)))))
(setq prevpos (point))
(goto-char (match-end 0))
- (let* ((start
- ;;start point of text in source buffer to be put
- ;;into *Occur*
- (save-excursion
+ (let* (;;start point of text in source buffer to be put
+ ;;into *Occur*
+ (start (save-excursion
(goto-char (match-beginning 0))
(forward-line (if (< nlines 0)
nlines
(- nlines)))
(point)))
- (end
;; end point of text in source buffer to be put
;; into *Occur*
- (save-excursion
- (goto-char (match-end 0))
- (if (> nlines 0)
- (forward-line (1+ nlines))
- (forward-line 1))
- (point)))
- (match-beg
+ (end (save-excursion
+ (goto-char (match-end 0))
+ (if (> nlines 0)
+ (forward-line (1+ nlines))
+ (forward-line 1))
+ (point)))
;; Amount of context before matching text
- (- (match-beginning 0) start))
- (match-len
+ (match-beg (- (match-beginning 0) start))
;; Length of matching text
- (- (match-end 0) (match-beginning 0)))
- (tag (format "%5d" linenum))
- (empty (make-string (length tag) ?\ ))
+ (match-len (- (match-end 0) (match-beginning 0)))
+ (tag (format line-number-format linenum))
tem
insertion-start
;; Number of lines of context to show for current match.
(text-end
;; Marker pointing to end of text for one match
;; in *Occur*.
- (make-marker))
- )
+ (make-marker)))
(save-excursion
(setq occur-marker (make-marker))
(set-marker occur-marker (point))
(or first (zerop nlines)
(insert "--------\n"))
(setq first nil)
+ (save-excursion
+ (set-buffer "*Occur*")
+ (setq tab-width current-tab-width))
;; Insert matching text including context lines from
;; source buffer into *Occur*
(let ((this-linenum linenum))
(while (< (point) final-context-start)
(if (null tag)
- (setq tag (format "%5d" this-linenum)))
+ (setq tag (format line-number-format this-linenum)))
(insert tag ?:)
(forward-line 1)
(setq tag nil)
;; Add text properties. The `occur' prop is used to
;; store the marker of the matching text in the
;; source buffer.
- (put-text-property (marker-position text-beg)
- (- (marker-position text-end) 1)
- 'mouse-face 'highlight)
+ (add-text-properties
+ (marker-position text-beg) (- (marker-position text-end) 1)
+ '(mouse-face highlight
+ help-echo "mouse-2: go to this occurence"))
(put-text-property (marker-position text-beg)
(marker-position text-end)
'occur occur-marker)
! to replace all remaining matches with no more questions,
^ to move point back to previous match,
E to edit the replacement string"
- "Help message while in query-replace")
+ "Help message while in `query-replace'.")
(defvar query-replace-map (make-sparse-keymap)
"Keymap that defines the responses to questions in `query-replace'.
(aset data 2 (if (consp next) next (aref data 3))))))
(car (aref data 2)))
-(defun perform-replace (from-string replacements start end
+(defun perform-replace (from-string replacements
query-flag regexp-flag delimited-flag
- &optional repeat-count map)
+ &optional repeat-count map start end)
"Subroutine of `query-replace'. Its complexity handles interactive queries.
Don't use this in your own program unless you want to query and set the mark
just as `query-replace' does. Instead, write a simple loop like this:
- (while (re-search-forward \"foo[ \t]+bar\" nil t)
+
+ (while (re-search-forward \"foo[ \\t]+bar\" nil t)
(replace-match \"foobar\" nil nil))
-which will run faster and probably do exactly what you want."
+
+which will run faster and probably do exactly what you want. Please
+see the documentation of `replace-match' to find out how to simulate
+`case-replace'."
(or map (setq map query-replace-map))
(and query-flag minibuffer-auto-raise
(raise-frame (window-frame (minibuffer-window))))
;; For speed, use only integers and
;; reuse the list used last time.
(match-data t real-match-data)))))
-
- ;; Record whether the match is nonempty, to avoid an infinite loop
- ;; repeatedly matching the same empty string.
- (setq nonempty-match
- (/= (nth 0 real-match-data) (nth 1 real-match-data)))
-
- ;; If the match is empty, record that the next one can't be adjacent.
- ;; Otherwise, if matching a regular expression, do the next
- ;; match now, since the replacement for this match may
- ;; affect whether the next match is adjacent to this one.
- (setq match-again
- (and nonempty-match
- (or (not regexp-flag)
- (and (looking-at search-string)
- (match-data)))))
-
- ;; Calculate the replacement string, if necessary.
- (when replacements
- (set-match-data real-match-data)
- (setq next-replacement
- (funcall (car replacements) (cdr replacements)
- replace-count)))
- (if (not query-flag)
- (progn
- (set-match-data real-match-data)
- (replace-match next-replacement nocasify literal)
- (setq replace-count (1+ replace-count)))
- (undo-boundary)
- (let (done replaced key def)
- ;; Loop reading commands until one of them sets done,
- ;; which means it has finished handling this occurrence.
- (while (not done)
- (set-match-data real-match-data)
- (replace-highlight (match-beginning 0) (match-end 0))
- ;; Bind message-log-max so we don't fill up the message log
- ;; with a bunch of identical messages.
- (let ((message-log-max nil))
- (message message from-string next-replacement))
- (setq key (read-event))
- ;; Necessary in case something happens during read-event
- ;; that clobbers the match data.
- (set-match-data real-match-data)
- (setq key (vector key))
- (setq def (lookup-key map key))
- ;; Restore the match data while we process the command.
- (cond ((eq def 'help)
- (with-output-to-temp-buffer "*Help*"
- (princ
- (concat "Query replacing "
- (if regexp-flag "regexp " "")
- from-string " with "
- next-replacement ".\n\n"
- (substitute-command-keys
- query-replace-help)))
- (save-excursion
- (set-buffer standard-output)
- (help-mode))))
- ((eq def 'exit)
- (setq keep-going nil)
- (setq done t))
- ((eq def 'backup)
- (if stack
- (let ((elt (car stack)))
- (goto-char (car elt))
- (setq replaced (eq t (cdr elt)))
- (or replaced
- (set-match-data (cdr elt)))
- (setq stack (cdr stack)))
- (message "No previous match")
- (ding 'no-terminate)
- (sit-for 1)))
- ((eq def 'act)
- (or replaced
- (progn
- (replace-match next-replacement nocasify literal)
- (setq replace-count (1+ replace-count))))
- (setq done t replaced t))
- ((eq def 'act-and-exit)
- (or replaced
- (progn
- (replace-match next-replacement nocasify literal)
- (setq replace-count (1+ replace-count))))
- (setq keep-going nil)
- (setq done t replaced t))
- ((eq def 'act-and-show)
- (if (not replaced)
- (progn
- (replace-match next-replacement nocasify literal)
- (setq replace-count (1+ replace-count))
- (setq replaced t))))
- ((eq def 'automatic)
- (or replaced
- (progn
- (replace-match next-replacement nocasify literal)
- (setq replace-count (1+ replace-count))))
- (setq done t query-flag nil replaced t))
- ((eq def 'skip)
- (setq done t))
- ((eq def 'recenter)
- (recenter nil))
- ((eq def 'edit)
- (let ((opos (point-marker)))
- (goto-char (match-beginning 0))
- (save-excursion
- (funcall search-function search-string limit t)
- (setq real-match-data (match-data)))
- (save-excursion (recursive-edit))
- (goto-char opos))
- (set-match-data real-match-data)
- ;; Before we make the replacement,
- ;; decide whether the search string
- ;; can match again just after this match.
- (if (and regexp-flag nonempty-match)
- (setq match-again (and (looking-at search-string)
- (match-data)))))
+ ;; Optionally ignore matches that have a read-only property.
+ (unless (and query-replace-skip-read-only
+ (text-property-not-all
+ (match-beginning 0) (match-end 0)
+ 'read-only nil))
+
+ ;; Record whether the match is nonempty, to avoid an infinite loop
+ ;; repeatedly matching the same empty string.
+ (setq nonempty-match
+ (/= (nth 0 real-match-data) (nth 1 real-match-data)))
+
+ ;; If the match is empty, record that the next one can't be
+ ;; adjacent.
+
+ ;; Otherwise, if matching a regular expression, do the next
+ ;; match now, since the replacement for this match may
+ ;; affect whether the next match is adjacent to this one.
+ ;; If that match is empty, don't use it.
+ (setq match-again
+ (and nonempty-match
+ (or (not regexp-flag)
+ (and (looking-at search-string)
+ (let ((match (match-data)))
+ (and (/= (nth 0 match) (nth 1 match))
+ match))))))
+
+ ;; Calculate the replacement string, if necessary.
+ (when replacements
+ (set-match-data real-match-data)
+ (setq next-replacement
+ (funcall (car replacements) (cdr replacements)
+ replace-count)))
+ (if (not query-flag)
+ (let ((inhibit-read-only query-replace-skip-read-only))
+ (set-match-data real-match-data)
+ (replace-match next-replacement nocasify literal)
+ (setq replace-count (1+ replace-count)))
+ (undo-boundary)
+ (let (done replaced key def)
+ ;; Loop reading commands until one of them sets done,
+ ;; which means it has finished handling this occurrence.
+ (while (not done)
+ (set-match-data real-match-data)
+ (replace-highlight (match-beginning 0) (match-end 0))
+ ;; Bind message-log-max so we don't fill up the message log
+ ;; with a bunch of identical messages.
+ (let ((message-log-max nil))
+ (message message from-string next-replacement))
+ (setq key (read-event))
+ ;; Necessary in case something happens during read-event
+ ;; that clobbers the match data.
+ (set-match-data real-match-data)
+ (setq key (vector key))
+ (setq def (lookup-key map key))
+ ;; Restore the match data while we process the command.
+ (cond ((eq def 'help)
+ (with-output-to-temp-buffer "*Help*"
+ (princ
+ (concat "Query replacing "
+ (if regexp-flag "regexp " "")
+ from-string " with "
+ next-replacement ".\n\n"
+ (substitute-command-keys
+ query-replace-help)))
+ (with-current-buffer standard-output
+ (help-mode))))
+ ((eq def 'exit)
+ (setq keep-going nil)
+ (setq done t))
+ ((eq def 'backup)
+ (if stack
+ (let ((elt (car stack)))
+ (goto-char (car elt))
+ (setq replaced (eq t (cdr elt)))
+ (or replaced
+ (set-match-data (cdr elt)))
+ (setq stack (cdr stack)))
+ (message "No previous match")
+ (ding 'no-terminate)
+ (sit-for 1)))
+ ((eq def 'act)
+ (or replaced
+ (progn
+ (replace-match next-replacement nocasify literal)
+ (setq replace-count (1+ replace-count))))
+ (setq done t replaced t))
+ ((eq def 'act-and-exit)
+ (or replaced
+ (progn
+ (replace-match next-replacement nocasify literal)
+ (setq replace-count (1+ replace-count))))
+ (setq keep-going nil)
+ (setq done t replaced t))
+ ((eq def 'act-and-show)
+ (if (not replaced)
+ (progn
+ (replace-match next-replacement nocasify literal)
+ (setq replace-count (1+ replace-count))
+ (setq replaced t))))
+ ((eq def 'automatic)
+ (or replaced
+ (progn
+ (replace-match next-replacement nocasify literal)
+ (setq replace-count (1+ replace-count))))
+ (setq done t query-flag nil replaced t))
+ ((eq def 'skip)
+ (setq done t))
+ ((eq def 'recenter)
+ (recenter nil))
+ ((eq def 'edit)
+ (let ((opos (point-marker)))
+ (goto-char (match-beginning 0))
+ (save-excursion
+ (funcall search-function search-string limit t)
+ (setq real-match-data (match-data)))
+ (save-excursion (recursive-edit))
+ (goto-char opos))
+ (set-match-data real-match-data)
+ ;; Before we make the replacement,
+ ;; decide whether the search string
+ ;; can match again just after this match.
+ (if (and regexp-flag nonempty-match)
+ (setq match-again (and (looking-at search-string)
+ (match-data)))))
- ;; Edit replacement.
- ((eq def 'edit-replacement)
- (setq next-replacement
- (read-input "Edit replacement string: "
- next-replacement))
- (or replaced
- (replace-match next-replacement nocasify literal))
- (setq done t))
+ ;; Edit replacement.
+ ((eq def 'edit-replacement)
+ (setq next-replacement
+ (read-input "Edit replacement string: "
+ next-replacement))
+ (or replaced
+ (replace-match next-replacement nocasify literal))
+ (setq done t))
- ((eq def 'delete-and-edit)
- (delete-region (match-beginning 0) (match-end 0))
- (set-match-data
- (prog1 (match-data)
- (save-excursion (recursive-edit))))
- (setq replaced t))
- ;; Note: we do not need to treat `exit-prefix'
- ;; specially here, since we reread
- ;; any unrecognized character.
- (t
- (setq this-command 'mode-exited)
- (setq keep-going nil)
- (setq unread-command-events
- (append (listify-key-sequence key)
- unread-command-events))
- (setq done t))))
- ;; Record previous position for ^ when we move on.
- ;; Change markers to numbers in the match data
- ;; since lots of markers slow down editing.
- (setq stack
- (cons (cons (point)
- (or replaced (match-data t)))
- stack)))))
+ ((eq def 'delete-and-edit)
+ (delete-region (match-beginning 0) (match-end 0))
+ (set-match-data
+ (prog1 (match-data)
+ (save-excursion (recursive-edit))))
+ (setq replaced t))
+ ;; Note: we do not need to treat `exit-prefix'
+ ;; specially here, since we reread
+ ;; any unrecognized character.
+ (t
+ (setq this-command 'mode-exited)
+ (setq keep-going nil)
+ (setq unread-command-events
+ (append (listify-key-sequence key)
+ unread-command-events))
+ (setq done t))))
+ ;; Record previous position for ^ when we move on.
+ ;; Change markers to numbers in the match data
+ ;; since lots of markers slow down editing.
+ (setq stack
+ (cons (cons (point)
+ (or replaced (match-data t)))
+ stack))))))
;; The code preventing adjacent regexp matches in the condition
;; of the while-loop above will haven taken us one character