(isearch-edit-string): In the isearch-recursive-edit case,
[bpt/emacs.git] / lisp / replace.el
CommitLineData
c88ab9ce
ER
1;;; replace.el --- replace commands for Emacs.
2
eab69997 3;; Copyright (C) 1985, 1986, 1987, 1992, 1994 Free Software Foundation, Inc.
3a801d0c 4
698e1804
RS
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs is free software; you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
e5d77022 9;; the Free Software Foundation; either version 2, or (at your option)
698e1804
RS
10;; any later version.
11
12;; GNU Emacs is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GNU Emacs; see the file COPYING. If not, write to
19;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
20
d9ecc911
ER
21;;; Commentary:
22
23;; This package supplies the string and regular-expression replace functions
24;; documented in the Emacs user's manual.
25
4f4b8eff 26;;; Code:
698e1804 27
73fa8346
BP
28(defconst case-replace t "\
29*Non-nil means query-replace should preserve case in replacements.")
77176e73 30
770970cb
RS
31(defvar query-replace-history nil)
32
33(defun query-replace-read-args (string)
34 (let (from to)
35 (setq from (read-from-minibuffer (format "%s: " string)
36 nil nil nil
37 'query-replace-history))
38 (setq to (read-from-minibuffer (format "%s %s with: " string from)
39 nil nil nil
40 'query-replace-history))
41 (list from to current-prefix-arg)))
42
da44e784
RM
43(defun query-replace (from-string to-string &optional arg)
44 "Replace some occurrences of FROM-STRING with TO-STRING.
45As each match is found, the user must type a character saying
46what to do with it. For directions, type \\[help-command] at that time.
47
118a01c9 48Preserves case in each replacement if `case-replace' and `case-fold-search'
da44e784 49are non-nil and FROM-STRING has no uppercase letters.
118a01c9 50Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
81bdc14d
RS
51only matches surrounded by word boundaries.
52
53To customize possible responses, change the \"bindings\" in `query-replace-map'."
770970cb 54 (interactive (query-replace-read-args "Query replace"))
da44e784 55 (perform-replace from-string to-string t nil arg)
81bdc14d 56 (or unread-command-events (message "Done")))
73fa8346 57(define-key esc-map "%" 'query-replace)
da44e784 58
da44e784
RM
59(defun query-replace-regexp (regexp to-string &optional arg)
60 "Replace some things after point matching REGEXP with TO-STRING.
61As each match is found, the user must type a character saying
62what to do with it. For directions, type \\[help-command] at that time.
63
118a01c9 64Preserves case in each replacement if `case-replace' and `case-fold-search'
da44e784 65are non-nil and REGEXP has no uppercase letters.
118a01c9 66Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
da44e784 67only matches surrounded by word boundaries.
118a01c9
RS
68In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
69and `\\=\\N' (where N is a digit) stands for
70 whatever what matched the Nth `\\(...\\)' in REGEXP."
770970cb 71 (interactive (query-replace-read-args "Query replace regexp"))
da44e784 72 (perform-replace regexp to-string t t arg)
81bdc14d 73 (or unread-command-events (message "Done")))
da44e784 74
da44e784
RM
75(defun map-query-replace-regexp (regexp to-strings &optional arg)
76 "Replace some matches for REGEXP with various strings, in rotation.
77The second argument TO-STRINGS contains the replacement strings, separated
78by spaces. This command works like `query-replace-regexp' except
79that each successive replacement uses the next successive replacement string,
80wrapping around from the last such string to the first.
81
82Non-interactively, TO-STRINGS may be a list of replacement strings.
83
84A prefix argument N says to use each replacement string N times
85before rotating to the next."
770970cb
RS
86 (interactive
87 (let (from to)
88 (setq from (read-from-minibuffer "Map query replace (regexp): "
89 nil nil nil
90 'query-replace-history))
91 (setq to (read-from-minibuffer
92 (format "Query replace %s with (space-separated strings): "
93 from)
94 nil nil nil
95 'query-replace-history))
96 (list from to current-prefix-arg)))
da44e784
RM
97 (let (replacements)
98 (if (listp to-strings)
99 (setq replacements to-strings)
100 (while (/= (length to-strings) 0)
101 (if (string-match " " to-strings)
102 (setq replacements
103 (append replacements
104 (list (substring to-strings 0
105 (string-match " " to-strings))))
106 to-strings (substring to-strings
107 (1+ (string-match " " to-strings))))
108 (setq replacements (append replacements (list to-strings))
109 to-strings ""))))
110 (perform-replace regexp replacements t t nil arg))
81bdc14d 111 (or unread-command-events (message "Done")))
da44e784 112
da44e784
RM
113(defun replace-string (from-string to-string &optional delimited)
114 "Replace occurrences of FROM-STRING with TO-STRING.
115Preserve case in each match if `case-replace' and `case-fold-search'
116are non-nil and FROM-STRING has no uppercase letters.
118a01c9 117Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
da44e784
RM
118only matches surrounded by word boundaries.
119
120This function is usually the wrong thing to use in a Lisp program.
121What you probably want is a loop like this:
118a01c9
RS
122 (while (search-forward FROM-STRING nil t)
123 (replace-match TO-STRING nil t))
da44e784 124which will run faster and will not set the mark or print anything."
770970cb 125 (interactive (query-replace-read-args "Replace string"))
da44e784 126 (perform-replace from-string to-string nil nil delimited)
81bdc14d 127 (or unread-command-events (message "Done")))
da44e784 128
da44e784
RM
129(defun replace-regexp (regexp to-string &optional delimited)
130 "Replace things after point matching REGEXP with TO-STRING.
118a01c9 131Preserve case in each match if `case-replace' and `case-fold-search'
da44e784 132are non-nil and REGEXP has no uppercase letters.
118a01c9 133Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
da44e784 134only matches surrounded by word boundaries.
118a01c9
RS
135In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
136and `\\=\\N' (where N is a digit) stands for
880f22a1 137 whatever what matched the Nth `\\(...\\)' in REGEXP.
da44e784
RM
138
139This function is usually the wrong thing to use in a Lisp program.
140What you probably want is a loop like this:
141 (while (re-search-forward REGEXP nil t)
118a01c9 142 (replace-match TO-STRING nil nil))
da44e784 143which will run faster and will not set the mark or print anything."
770970cb 144 (interactive (query-replace-read-args "Replace regexp"))
da44e784 145 (perform-replace regexp to-string nil t delimited)
81bdc14d 146 (or unread-command-events (message "Done")))
4c53bd2b
RS
147\f
148(defvar regexp-history nil
149 "History list for some commands that read regular expressions.")
da44e784 150
31e1d920 151(defalias 'delete-non-matching-lines 'keep-lines)
698e1804
RS
152(defun keep-lines (regexp)
153 "Delete all lines except those containing matches for REGEXP.
154A match split across lines preserves all the lines it lies in.
155Applies to all lines after point."
4c53bd2b 156 (interactive (list (read-from-minibuffer
72f21cdf 157 "Keep lines (containing match for regexp): "
4c53bd2b 158 nil nil nil 'regexp-history)))
698e1804
RS
159 (save-excursion
160 (or (bolp) (forward-line 1))
161 (let ((start (point)))
162 (while (not (eobp))
163 ;; Start is first char not preserved by previous match.
164 (if (not (re-search-forward regexp nil 'move))
165 (delete-region start (point-max))
166 (let ((end (save-excursion (goto-char (match-beginning 0))
167 (beginning-of-line)
168 (point))))
169 ;; Now end is first char preserved by the new match.
170 (if (< start end)
171 (delete-region start end))))
172 (setq start (save-excursion (forward-line 1)
173 (point)))
174 ;; If the match was empty, avoid matching again at same place.
175 (and (not (eobp)) (= (match-beginning 0) (match-end 0))
176 (forward-char 1))))))
177
31e1d920 178(defalias 'delete-matching-lines 'flush-lines)
698e1804
RS
179(defun flush-lines (regexp)
180 "Delete lines containing matches for REGEXP.
181If a match is split across lines, all the lines it lies in are deleted.
182Applies to lines after point."
4c53bd2b 183 (interactive (list (read-from-minibuffer
72f21cdf 184 "Flush lines (containing match for regexp): "
4c53bd2b 185 nil nil nil 'regexp-history)))
698e1804
RS
186 (save-excursion
187 (while (and (not (eobp))
188 (re-search-forward regexp nil t))
189 (delete-region (save-excursion (goto-char (match-beginning 0))
190 (beginning-of-line)
191 (point))
192 (progn (forward-line 1) (point))))))
193
31e1d920 194(defalias 'count-matches 'how-many)
698e1804
RS
195(defun how-many (regexp)
196 "Print number of matches for REGEXP following point."
4c53bd2b 197 (interactive (list (read-from-minibuffer
72f21cdf 198 "How many matches for (regexp): "
4c53bd2b 199 nil nil nil 'regexp-history)))
698e1804
RS
200 (let ((count 0) opoint)
201 (save-excursion
202 (while (and (not (eobp))
203 (progn (setq opoint (point))
204 (re-search-forward regexp nil t)))
205 (if (= opoint (point))
206 (forward-char 1)
207 (setq count (1+ count))))
208 (message "%d occurrences" count))))
4c53bd2b 209\f
698e1804
RS
210(defvar occur-mode-map ())
211(if occur-mode-map
212 ()
213 (setq occur-mode-map (make-sparse-keymap))
78bead73 214 (define-key occur-mode-map [mouse-2] 'occur-mode-mouse-goto)
698e1804
RS
215 (define-key occur-mode-map "\C-c\C-c" 'occur-mode-goto-occurrence))
216
217(defvar occur-buffer nil)
218(defvar occur-nlines nil)
219(defvar occur-pos-list nil)
220
221(defun occur-mode ()
222 "Major mode for output from \\[occur].
223Move point to one of the occurrences in this buffer,
224then use \\[occur-mode-goto-occurrence] to go to the same occurrence
225in the buffer that the occurrences were found in.
26649bdf 226Or click \\<occur-mode-map>\\[occur-mode-mouse-goto] on an occurrence line.
698e1804
RS
227\\{occur-mode-map}"
228 (kill-all-local-variables)
229 (use-local-map occur-mode-map)
230 (setq major-mode 'occur-mode)
231 (setq mode-name "Occur")
232 (make-local-variable 'occur-buffer)
233 (make-local-variable 'occur-nlines)
4baf5620
RS
234 (make-local-variable 'occur-pos-list)
235 (run-hooks 'occur-mode-hook))
698e1804 236
78bead73
RS
237(defun occur-mode-mouse-goto (event)
238 "In Occur mode, go to the occurrence whose line you click on."
239 (interactive "e")
240 (let (buffer pos)
241 (save-excursion
242 (set-buffer (window-buffer (posn-window (event-end event))))
243 (save-excursion
244 (goto-char (posn-point (event-end event)))
245 (setq pos (occur-mode-find-occurrence))
246 (setq buffer occur-buffer)))
247 (pop-to-buffer buffer)
248 (goto-char (marker-position pos))))
249
250(defun occur-mode-find-occurrence ()
698e1804
RS
251 (if (or (null occur-buffer)
252 (null (buffer-name occur-buffer)))
253 (progn
254 (setq occur-buffer nil
255 occur-pos-list nil)
256 (error "Buffer in which occurrences were found is deleted")))
78bead73
RS
257 (let* ((line-count
258 (count-lines (point-min)
259 (save-excursion
260 (beginning-of-line)
261 (point))))
262 (occur-number (save-excursion
698e1804 263 (beginning-of-line)
78bead73 264 (/ (1- line-count)
698e1804
RS
265 (cond ((< occur-nlines 0)
266 (- 2 occur-nlines))
267 ((> occur-nlines 0)
268 (+ 2 (* 2 occur-nlines)))
269 (t 1)))))
270 (pos (nth occur-number occur-pos-list)))
78bead73
RS
271 (if (< line-count 1)
272 (error "No occurrence on this line"))
43549f18
RS
273 (or pos
274 (error "No occurrence on this line"))
78bead73
RS
275 pos))
276
277(defun occur-mode-goto-occurrence ()
278 "Go to the occurrence the current line describes."
279 (interactive)
280 (let ((pos (occur-mode-find-occurrence)))
698e1804 281 (pop-to-buffer occur-buffer)
121e2227 282 (goto-char (marker-position pos))))
4c53bd2b 283\f
698e1804 284(defvar list-matching-lines-default-context-lines 0
da44e784 285 "*Default number of context lines to include around a `list-matching-lines'
698e1804
RS
286match. A negative number means to include that many lines before the match.
287A positive number means to include that many lines both before and after.")
288
31e1d920 289(defalias 'list-matching-lines 'occur)
698e1804
RS
290
291(defun occur (regexp &optional nlines)
99976f85 292 "Show all lines in the current buffer containing a match for REGEXP.
da44e784
RM
293
294If a match spreads across multiple lines, all those lines are shown.
698e1804 295
da44e784
RM
296Each line is displayed with NLINES lines before and after, or -NLINES
297before if NLINES is negative.
298NLINES defaults to `list-matching-lines-default-context-lines'.
698e1804
RS
299Interactively it is the prefix arg.
300
4c53bd2b 301The lines are shown in a buffer named `*Occur*'.
698e1804
RS
302It serves as a menu to find any of the occurrences in this buffer.
303\\[describe-mode] in that buffer will explain how."
4c53bd2b
RS
304 (interactive (list (let* ((default (car regexp-history))
305 (input
306 (read-from-minibuffer
166aaf6f
RS
307 (if default
308 (format "List lines matching regexp (default `%s'): " default)
309 "List lines matching regexp: ")
4c53bd2b
RS
310 nil nil nil
311 'regexp-history)))
312 (if (> (length input) 0) input
313 (setcar regexp-history default)))
f1c9e147 314 current-prefix-arg))
698e1804
RS
315 (setq nlines (if nlines (prefix-numeric-value nlines)
316 list-matching-lines-default-context-lines))
317 (let ((first t)
318 (buffer (current-buffer))
319 (linenum 1)
79c2e52b
JB
320 (prevpos (point-min))
321 (final-context-start (make-marker)))
99976f85
RS
322;;; (save-excursion
323;;; (beginning-of-line)
324;;; (setq linenum (1+ (count-lines (point-min) (point))))
325;;; (setq prevpos (point)))
698e1804
RS
326 (with-output-to-temp-buffer "*Occur*"
327 (save-excursion
328 (set-buffer standard-output)
329 (insert "Lines matching ")
330 (prin1 regexp)
331 (insert " in buffer " (buffer-name buffer) ?. ?\n)
332 (occur-mode)
333 (setq occur-buffer buffer)
334 (setq occur-nlines nlines)
335 (setq occur-pos-list ()))
336 (if (eq buffer standard-output)
337 (goto-char (point-max)))
338 (save-excursion
99976f85 339 (beginning-of-buffer)
698e1804
RS
340 ;; Find next match, but give up if prev match was at end of buffer.
341 (while (and (not (= prevpos (point-max)))
342 (re-search-forward regexp nil t))
da44e784 343 (goto-char (match-beginning 0))
698e1804 344 (beginning-of-line)
4c53bd2b
RS
345 (save-match-data
346 (setq linenum (+ linenum (count-lines prevpos (point)))))
698e1804 347 (setq prevpos (point))
da44e784 348 (goto-char (match-end 0))
698e1804 349 (let* ((start (save-excursion
da44e784 350 (goto-char (match-beginning 0))
698e1804
RS
351 (forward-line (if (< nlines 0) nlines (- nlines)))
352 (point)))
353 (end (save-excursion
da44e784 354 (goto-char (match-end 0))
698e1804
RS
355 (if (> nlines 0)
356 (forward-line (1+ nlines))
357 (forward-line 1))
358 (point)))
359 (tag (format "%3d" linenum))
360 (empty (make-string (length tag) ?\ ))
361 tem)
362 (save-excursion
79c2e52b
JB
363 (setq tem (make-marker))
364 (set-marker tem (point))
698e1804
RS
365 (set-buffer standard-output)
366 (setq occur-pos-list (cons tem occur-pos-list))
367 (or first (zerop nlines)
368 (insert "--------\n"))
369 (setq first nil)
370 (insert-buffer-substring buffer start end)
371 (backward-char (- end start))
da44e784 372 (setq tem nlines)
698e1804
RS
373 (while (> tem 0)
374 (insert empty ?:)
375 (forward-line 1)
376 (setq tem (1- tem)))
79c2e52b 377 (let ((this-linenum linenum))
da44e784
RM
378 (set-marker final-context-start
379 (+ (point) (- (match-end 0) (match-beginning 0))))
380 (while (< (point) final-context-start)
381 (if (null tag)
382 (setq tag (format "%3d" this-linenum)))
383 (insert tag ?:)
f81ed6cf
RS
384 (put-text-property (save-excursion
385 (beginning-of-line)
386 (point))
387 (save-excursion
388 (end-of-line)
389 (point))
390 'mouse-face 'highlight)
da44e784
RM
391 (setq tag nil)
392 (forward-line 1)
393 (setq this-linenum (1+ this-linenum))))
698e1804
RS
394 (while (< tem nlines)
395 (insert empty ?:)
396 (forward-line 1)
397 (setq tem (1+ tem))))
398 (forward-line 1)))
399 (set-buffer standard-output)
400 ;; Put positions in increasing order to go with buffer.
401 (setq occur-pos-list (nreverse occur-pos-list))
402 (if (interactive-p)
403 (message "%d matching lines." (length occur-pos-list)))))))
404\f
81bdc14d
RS
405;; It would be nice to use \\[...], but there is no reasonable way
406;; to make that display both SPC and Y.
698e1804
RS
407(defconst query-replace-help
408 "Type Space or `y' to replace one match, Delete or `n' to skip to next,
be44f62c 409RET or `q' to exit, Period to replace one match and exit,
698e1804
RS
410Comma to replace but not move point immediately,
411C-r to enter recursive edit (\\[exit-recursive-edit] to get out again),
412C-w to delete match and recursive edit,
413C-l to clear the screen, redisplay, and offer same replacement again,
414! to replace all remaining matches with no more questions,
415^ to move point back to previous match."
416 "Help message while in query-replace")
417
81bdc14d
RS
418(defvar query-replace-map (make-sparse-keymap)
419 "Keymap that defines the responses to questions in `query-replace'.
420The \"bindings\" in this map are not commands; they are answers.
421The valid answers include `act', `skip', `act-and-show',
422`exit', `act-and-exit', `edit', `delete-and-edit', `recenter',
423`automatic', `backup', and `help'.")
424
425(define-key query-replace-map " " 'act)
426(define-key query-replace-map "\d" 'skip)
427(define-key query-replace-map [delete] 'skip)
9275e5e3 428(define-key query-replace-map [backspace] 'skip)
81bdc14d
RS
429(define-key query-replace-map "y" 'act)
430(define-key query-replace-map "n" 'skip)
431(define-key query-replace-map "," 'act-and-show)
81bdc14d 432(define-key query-replace-map "q" 'exit)
919592c0 433(define-key query-replace-map "\r" 'exit)
384c7da4 434(define-key query-replace-map [return] 'exit)
81bdc14d
RS
435(define-key query-replace-map "." 'act-and-exit)
436(define-key query-replace-map "\C-r" 'edit)
437(define-key query-replace-map "\C-w" 'delete-and-edit)
438(define-key query-replace-map "\C-l" 'recenter)
439(define-key query-replace-map "!" 'automatic)
440(define-key query-replace-map "^" 'backup)
441(define-key query-replace-map "\C-h" 'help)
442(define-key query-replace-map "?" 'help)
bc6312e1
RS
443(define-key query-replace-map "\C-g" 'quit)
444(define-key query-replace-map "\C-]" 'quit)
81bdc14d 445
698e1804
RS
446(defun perform-replace (from-string replacements
447 query-flag regexp-flag delimited-flag
81bdc14d 448 &optional repeat-count map)
698e1804
RS
449 "Subroutine of `query-replace'. Its complexity handles interactive queries.
450Don't use this in your own program unless you want to query and set the mark
451just as `query-replace' does. Instead, write a simple loop like this:
452 (while (re-search-forward \"foo[ \t]+bar\" nil t)
453 (replace-match \"foobar\" nil nil))
e782e9f2 454which will run faster and probably do exactly what you want."
81bdc14d 455 (or map (setq map query-replace-map))
698e1804
RS
456 (let ((nocasify (not (and case-fold-search case-replace
457 (string-equal from-string
458 (downcase from-string)))))
459 (literal (not regexp-flag))
460 (search-function (if regexp-flag 're-search-forward 'search-forward))
461 (search-string from-string)
e5d77022 462 (real-match-data nil) ; the match data for the current match
698e1804
RS
463 (next-replacement nil)
464 (replacement-index 0)
465 (keep-going t)
466 (stack nil)
467 (next-rotate-count 0)
468 (replace-count 0)
da44e784 469 (lastrepl nil) ;Position after last match considered.
02d95a27
RS
470 (match-again t)
471 (message
472 (if query-flag
473 (substitute-command-keys
474 "Query replacing %s with %s: (\\<query-replace-map>\\[help] for help) "))))
698e1804
RS
475 (if (stringp replacements)
476 (setq next-replacement replacements)
477 (or repeat-count (setq repeat-count 1)))
478 (if delimited-flag
479 (setq search-function 're-search-forward
480 search-string (concat "\\b"
481 (if regexp-flag from-string
482 (regexp-quote from-string))
483 "\\b")))
484 (push-mark)
485 (undo-boundary)
e782e9f2
RS
486 (unwind-protect
487 ;; Loop finding occurrences that perhaps should be replaced.
488 (while (and keep-going
489 (not (eobp))
490 (funcall search-function search-string nil t)
491 ;; If the search string matches immediately after
492 ;; the previous match, but it did not match there
493 ;; before the replacement was done, ignore the match.
494 (if (or (eq lastrepl (point))
495 (and regexp-flag
496 (eq lastrepl (match-beginning 0))
497 (not match-again)))
498 (if (eobp)
499 nil
500 ;; Don't replace the null string
501 ;; right after end of previous replacement.
502 (forward-char 1)
503 (funcall search-function search-string nil t))
504 t))
505
506 ;; Save the data associated with the real match.
507 (setq real-match-data (match-data))
508
509 ;; Before we make the replacement, decide whether the search string
510 ;; can match again just after this match.
511 (if regexp-flag
512 (setq match-again (looking-at search-string)))
513 ;; If time for a change, advance to next replacement string.
514 (if (and (listp replacements)
515 (= next-rotate-count replace-count))
516 (progn
517 (setq next-rotate-count
518 (+ next-rotate-count repeat-count))
519 (setq next-replacement (nth replacement-index replacements))
520 (setq replacement-index (% (1+ replacement-index) (length replacements)))))
521 (if (not query-flag)
522 (progn
523 (store-match-data real-match-data)
524 (replace-match next-replacement nocasify literal)
525 (setq replace-count (1+ replace-count)))
526 (undo-boundary)
527 (let (done replaced key def)
528 ;; Loop reading commands until one of them sets done,
529 ;; which means it has finished handling this occurrence.
530 (while (not done)
531 (replace-highlight (match-beginning 0) (match-end 0))
02d95a27 532 (message message from-string next-replacement)
e782e9f2
RS
533 (setq key (read-event))
534 (setq key (vector key))
535 (setq def (lookup-key map key))
536 ;; Restore the match data while we process the command.
537 (store-match-data real-match-data)
538 (cond ((eq def 'help)
539 (with-output-to-temp-buffer "*Help*"
540 (princ
541 (concat "Query replacing "
542 (if regexp-flag "regexp " "")
543 from-string " with "
544 next-replacement ".\n\n"
545 (substitute-command-keys
546 query-replace-help)))))
547 ((eq def 'exit)
548 (setq keep-going nil)
549 (setq done t))
550 ((eq def 'backup)
237e6ab0
KH
551 (if stack
552 (let ((elt (car stack)))
553 (goto-char (car elt))
554 (setq replaced (eq t (cdr elt)))
555 (or replaced
556 (store-match-data (cdr elt)))
557 (setq stack (cdr stack)))
558 (message "No previous match")
559 (ding 'no-terminate)
560 (sit-for 1)))
e782e9f2
RS
561 ((eq def 'act)
562 (or replaced
563 (replace-match next-replacement nocasify literal))
564 (setq done t replaced t))
565 ((eq def 'act-and-exit)
566 (or replaced
567 (replace-match next-replacement nocasify literal))
568 (setq keep-going nil)
569 (setq done t replaced t))
570 ((eq def 'act-and-show)
571 (if (not replaced)
572 (progn
573 (replace-match next-replacement nocasify literal)
574 (setq replaced t))))
575 ((eq def 'automatic)
576 (or replaced
577 (replace-match next-replacement nocasify literal))
578 (setq done t query-flag nil replaced t))
579 ((eq def 'skip)
580 (setq done t))
581 ((eq def 'recenter)
582 (recenter nil))
583 ((eq def 'edit)
584 (store-match-data
585 (prog1 (match-data)
586 (save-excursion (recursive-edit))))
587 ;; Before we make the replacement,
588 ;; decide whether the search string
589 ;; can match again just after this match.
590 (if regexp-flag
591 (setq match-again (looking-at search-string))))
592 ((eq def 'delete-and-edit)
593 (delete-region (match-beginning 0) (match-end 0))
594 (store-match-data
595 (prog1 (match-data)
596 (save-excursion (recursive-edit))))
597 (setq replaced t))
598 (t
599 (setq keep-going nil)
600 (setq unread-command-events
601 (append (listify-key-sequence key)
602 unread-command-events))
603 (setq done t))))
604 ;; Record previous position for ^ when we move on.
605 ;; Change markers to numbers in the match data
606 ;; since lots of markers slow down editing.
607 (setq stack
608 (cons (cons (point)
609 (or replaced
eab69997
RM
610 (mapcar (lambda (elt)
611 (and elt
612 (prog1 (marker-position elt)
613 (set-marker elt nil))))
e782e9f2
RS
614 (match-data))))
615 stack))
616 (if replaced (setq replace-count (1+ replace-count)))))
617 (setq lastrepl (point)))
618 (replace-dehighlight))
81bdc14d 619 (and keep-going stack)))
698e1804 620
e782e9f2
RS
621(defvar query-replace-highlight nil
622 "*Non-nil means to highlight words during query replacement.")
623
624(defvar replace-overlay nil)
625
626(defun replace-dehighlight ()
627 (and replace-overlay
628 (progn
629 (delete-overlay replace-overlay)
630 (setq replace-overlay nil))))
631
632(defun replace-highlight (start end)
633 (and query-replace-highlight
634 (progn
635 (or replace-overlay
636 (progn
637 (setq replace-overlay (make-overlay start end))
638 (overlay-put replace-overlay 'face
639 (if (internal-find-face 'query-replace)
640 'query-replace 'region))))
641 (move-overlay replace-overlay start end (current-buffer)))))
642
c88ab9ce 643;;; replace.el ends here