(isearch-query-replace, isearch-query-replace-regexp):
[bpt/emacs.git] / lisp / replace.el
CommitLineData
60370d40 1;;; replace.el --- replace commands for Emacs
c88ab9ce 2
2f57bf85
DK
3;; Copyright (C) 1985, 86, 87, 92, 94, 96, 1997, 2000, 2001, 2002,
4;; 2003, 2004 Free Software Foundation, Inc.
3a801d0c 5
30764597
PJ
6;; Maintainer: FSF
7
698e1804
RS
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
e5d77022 12;; the Free Software Foundation; either version 2, or (at your option)
698e1804
RS
13;; any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
b578f267
EN
21;; along with GNU Emacs; see the file COPYING. If not, write to the
22;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23;; Boston, MA 02111-1307, USA.
698e1804 24
d9ecc911
ER
25;;; Commentary:
26
27;; This package supplies the string and regular-expression replace functions
28;; documented in the Emacs user's manual.
29
4f4b8eff 30;;; Code:
698e1804 31
9d325ebf 32(defcustom case-replace t
f54701d1 33 "*Non-nil means `query-replace' should preserve case in replacements."
9d325ebf
RS
34 :type 'boolean
35 :group 'matching)
77176e73 36
770970cb
RS
37(defvar query-replace-history nil)
38
1f3ade4f 39(defcustom query-replace-interactive nil
151270f3 40 "Non-nil means `query-replace' uses the last search string.
0ec4febd
JL
41That becomes the \"string to replace\".
42If value is `initial', the last search string is inserted into
43the minibuffer as an initial value for \"string to replace\"."
44 :type '(choice (const :tag "Off" nil)
45 (const :tag "Initial content" initial)
46 (other :tag "Use default value" t))
1f3ade4f 47 :group 'matching)
151270f3 48
bdb1c08f 49(defcustom query-replace-from-history-variable 'query-replace-history
f54701d1 50 "History list to use for the FROM argument of `query-replace' commands.
bdb1c08f
RS
51The value of this variable should be a symbol; that symbol
52is used as a variable to hold a history list for the strings
53or patterns to be replaced."
54 :group 'matching
cd32a7ba
DN
55 :type 'symbol
56 :version "20.3")
bdb1c08f
RS
57
58(defcustom query-replace-to-history-variable 'query-replace-history
f54701d1 59 "History list to use for the TO argument of `query-replace' commands.
bdb1c08f
RS
60The value of this variable should be a symbol; that symbol
61is used as a variable to hold a history list for replacement
62strings or patterns."
63 :group 'matching
cd32a7ba
DN
64 :type 'symbol
65 :version "20.3")
bdb1c08f 66
1c4fe319
RS
67(defcustom query-replace-skip-read-only nil
68 "*Non-nil means `query-replace' and friends ignore read-only matches."
69 :type 'boolean
70 :group 'matching
89e7ad59 71 :version "21.4")
1c4fe319 72
86914dcc
RS
73(defun query-replace-read-args (string regexp-flag &optional noerror)
74 (unless noerror
75 (barf-if-buffer-read-only))
770970cb 76 (let (from to)
0ec4febd
JL
77 (if (and query-replace-interactive
78 (not (eq query-replace-interactive 'initial)))
79 (setq from (car (if regexp-flag regexp-search-ring search-ring)))
2f2f7e58
RS
80 ;; The save-excursion here is in case the user marks and copies
81 ;; a region in order to specify the minibuffer input.
82 ;; That should not clobber the region for the query-replace itself.
83 (save-excursion
0ec4febd
JL
84 (setq from (read-from-minibuffer
85 (format "%s: " string)
86 (if (eq query-replace-interactive 'initial)
87 (car (if regexp-flag regexp-search-ring search-ring)))
88 nil nil
89 query-replace-from-history-variable
90 nil t)))
d9291fa3 91 ;; Warn if user types \n or \t, but don't reject the input.
2f57bf85
DK
92 (and regexp-flag
93 (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\(\\\\[nt]\\)" from)
94 (let ((match (match-string 3 from)))
95 (cond
96 ((string= match "\\n")
97 (message "Note: `\\n' here doesn't match a newline; to do that, type C-q C-j instead"))
98 ((string= match "\\t")
99 (message "Note: `\\t' here doesn't match a tab; to do that, just type TAB")))
100 (sit-for 2))))
d9291fa3 101
2f2f7e58 102 (save-excursion
0ec4febd
JL
103 (setq to (read-from-minibuffer
104 (format "%s %s with: " string from)
105 nil nil nil
106 query-replace-to-history-variable from t)))
7c1c02ac
DK
107 (when (and regexp-flag
108 (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" to))
109 (let (pos list char)
110 (while
111 (progn
112 (setq pos (match-end 0))
113 (push (substring to 0 (- pos 2)) list)
114 (setq char (aref to (1- pos))
115 to (substring to pos))
116 (cond ((eq char ?\#)
117 (push '(number-to-string replace-count) list))
118 ((eq char ?\,)
119 (setq pos (read-from-string to))
120 (push `(replace-quote ,(car pos)) list)
9e5d1b63
RS
121 (let ((end
122 ;; Swallow a space after a symbol
123 ;; if there is a space.
124 (if (and (or (symbolp (car pos))
125 ;; Swallow a space after 'foo
126 ;; but not after (quote foo).
127 (and (eq (car-safe (car pos)) 'quote)
f1f6079c
JL
128 (not (= ?\( (aref to 0)))))
129 (eq (string-match " " to (cdr pos))
130 (cdr pos)))
9e5d1b63
RS
131 (1+ (cdr pos))
132 (cdr pos))))
133 (setq to (substring to end)))))
7c1c02ac
DK
134 (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" to)))
135 (setq to (nreverse (delete "" (cons to list)))))
136 (replace-match-string-symbols to)
da6eb51c 137 (setq to (cons 'replace-eval-replacement
7c1c02ac
DK
138 (if (> (length to) 1)
139 (cons 'concat to)
140 (car to)))))
10784bac 141 (list from to current-prefix-arg)))
770970cb 142
47d72254 143(defun query-replace (from-string to-string &optional delimited start end)
da44e784
RM
144 "Replace some occurrences of FROM-STRING with TO-STRING.
145As each match is found, the user must type a character saying
146what to do with it. For directions, type \\[help-command] at that time.
147
7ef5c431
KH
148In Transient Mark mode, if the mark is active, operate on the contents
149of the region. Otherwise, operate from point to the end of the buffer.
150
151270f3
RS
151If `query-replace-interactive' is non-nil, the last incremental search
152string is used as FROM-STRING--you don't have to specify it with the
153minibuffer.
154
446d9629
RS
155Matching is independent of case if `case-fold-search' is non-nil and
156FROM-STRING has no uppercase letters. Replacement transfers the case
157pattern of the old text to the new text, if `case-replace' and
158`case-fold-search' are non-nil and FROM-STRING has no uppercase
159letters. \(Transferring the case pattern means that if the old text
160matched is all caps, or capitalized, then its replacement is upcased
161or capitalized.)
9b0bf2b6 162
118a01c9 163Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
81bdc14d 164only matches surrounded by word boundaries.
47d72254 165Fourth and fifth arg START and END specify the region to operate on.
81bdc14d
RS
166
167To customize possible responses, change the \"bindings\" in `query-replace-map'."
10784bac
RS
168 (interactive (let ((common
169 (query-replace-read-args "Query replace" nil)))
170 (list (nth 0 common) (nth 1 common) (nth 2 common)
171 ;; These are done separately here
172 ;; so that command-history will record these expressions
173 ;; rather than the values they had this time.
174 (if (and transient-mark-mode mark-active)
175 (region-beginning))
176 (if (and transient-mark-mode mark-active)
177 (region-end)))))
99a7559f 178 (perform-replace from-string to-string t nil delimited nil nil start end))
7ef5c431 179
73fa8346 180(define-key esc-map "%" 'query-replace)
da44e784 181
47d72254 182(defun query-replace-regexp (regexp to-string &optional delimited start end)
da44e784
RM
183 "Replace some things after point matching REGEXP with TO-STRING.
184As each match is found, the user must type a character saying
185what to do with it. For directions, type \\[help-command] at that time.
186
7ef5c431
KH
187In Transient Mark mode, if the mark is active, operate on the contents
188of the region. Otherwise, operate from point to the end of the buffer.
189
151270f3
RS
190If `query-replace-interactive' is non-nil, the last incremental search
191regexp is used as REGEXP--you don't have to specify it with the
192minibuffer.
193
446d9629
RS
194Matching is independent of case if `case-fold-search' is non-nil and
195REGEXP has no uppercase letters. Replacement transfers the case
196pattern of the old text to the new text, if `case-replace' and
197`case-fold-search' are non-nil and REGEXP has no uppercase letters.
198\(Transferring the case pattern means that if the old text matched is
199all caps, or capitalized, then its replacement is upcased or
200capitalized.)
47d72254 201
118a01c9 202Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
da44e784 203only matches surrounded by word boundaries.
47d72254
GM
204Fourth and fifth arg START and END specify the region to operate on.
205
118a01c9
RS
206In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
207and `\\=\\N' (where N is a digit) stands for
2f57bf85 208whatever what matched the Nth `\\(...\\)' in REGEXP.
7c1c02ac
DK
209`\\?' lets you edit the replacement text in the minibuffer
210at the given position for each replacement.
211
ba8d15f9
RS
212In interactive calls, the replacement text can contain `\\,'
213followed by a Lisp expression. Each
214replacement evaluates that expression to compute the replacement
215string. Inside of that expression, `\\&' is a string denoting the
f1f6079c 216whole match as a string, `\\N' for a partial match, `\\#&' and `\\#N'
ba8d15f9
RS
217for the whole or a partial match converted to a number with
218`string-to-number', and `\\#' itself for the number of replacements
219done so far (starting with zero).
7c1c02ac 220
ba8d15f9
RS
221If the replacement expression is a symbol, write a space after it
222to terminate it. One space there, if any, will be discarded.
7c1c02ac
DK
223
224When using those Lisp features interactively in the replacement
225text, TO-STRING is actually made a list instead of a string.
226Use \\[repeat-complex-command] after this command for details."
10784bac
RS
227 (interactive
228 (let ((common
229 (query-replace-read-args "Query replace regexp" t)))
7c1c02ac
DK
230 (list (nth 0 common) (nth 1 common) (nth 2 common)
231 ;; These are done separately here
232 ;; so that command-history will record these expressions
233 ;; rather than the values they had this time.
234 (if (and transient-mark-mode mark-active)
235 (region-beginning))
236 (if (and transient-mark-mode mark-active)
237 (region-end)))))
99a7559f 238 (perform-replace regexp to-string t t delimited nil nil start end))
2f57bf85 239
cbc127de 240(define-key esc-map [?\C-%] 'query-replace-regexp)
da44e784 241
47d72254 242(defun query-replace-regexp-eval (regexp to-expr &optional delimited start end)
84482eb3
RS
243 "Replace some things after point matching REGEXP with the result of TO-EXPR.
244As each match is found, the user must type a character saying
245what to do with it. For directions, type \\[help-command] at that time.
246
247TO-EXPR is a Lisp expression evaluated to compute each replacement. It may
248reference `replace-count' to get the number of replacements already made.
249If the result of TO-EXPR is not a string, it is converted to one using
250`prin1-to-string' with the NOESCAPE argument (which see).
251
252For convenience, when entering TO-EXPR interactively, you can use `\\&' or
653479ad
AS
253`\\0' to stand for whatever matched the whole of REGEXP, and `\\N' (where
254N is a digit) to stand for whatever matched the Nth `\\(...\\)' in REGEXP.
84482eb3 255Use `\\#&' or `\\#N' if you want a number instead of a string.
2f57bf85 256In interactive use, `\\#' in itself stands for `replace-count'.
84482eb3
RS
257
258In Transient Mark mode, if the mark is active, operate on the contents
259of the region. Otherwise, operate from point to the end of the buffer.
260
261If `query-replace-interactive' is non-nil, the last incremental search
262regexp is used as REGEXP--you don't have to specify it with the
263minibuffer.
264
265Preserves case in each replacement if `case-replace' and `case-fold-search'
266are non-nil and REGEXP has no uppercase letters.
47d72254 267
84482eb3 268Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
470bbe9b 269only matches that are surrounded by word boundaries.
47d72254 270Fourth and fifth arg START and END specify the region to operate on."
84482eb3 271 (interactive
10784bac 272 (let (from to)
84482eb3
RS
273 (if query-replace-interactive
274 (setq from (car regexp-search-ring))
275 (setq from (read-from-minibuffer "Query replace regexp: "
276 nil nil nil
277 query-replace-from-history-variable
278 nil t)))
279 (setq to (list (read-from-minibuffer
280 (format "Query replace regexp %s with eval: " from)
281 nil nil t query-replace-to-history-variable from t)))
282 ;; We make TO a list because replace-match-string-symbols requires one,
283 ;; and the user might enter a single token.
284 (replace-match-string-symbols to)
10784bac
RS
285 (list from (car to) current-prefix-arg
286 (if (and transient-mark-mode mark-active)
287 (region-beginning))
288 (if (and transient-mark-mode mark-active)
289 (region-end)))))
d2ce3151 290 (perform-replace regexp (cons 'replace-eval-replacement to-expr)
d83a97ab 291 t 'literal delimited nil nil start end))
84482eb3 292
47d72254 293(defun map-query-replace-regexp (regexp to-strings &optional n start end)
da44e784 294 "Replace some matches for REGEXP with various strings, in rotation.
e730be7f
DL
295The second argument TO-STRINGS contains the replacement strings,
296separated by spaces. Third arg DELIMITED (prefix arg if interactive),
297if non-nil, means replace only matches surrounded by word boundaries.
298This command works like `query-replace-regexp' except that each
299successive replacement uses the next successive replacement string,
da44e784
RM
300wrapping around from the last such string to the first.
301
7ef5c431
KH
302In Transient Mark mode, if the mark is active, operate on the contents
303of the region. Otherwise, operate from point to the end of the buffer.
304
da44e784
RM
305Non-interactively, TO-STRINGS may be a list of replacement strings.
306
151270f3
RS
307If `query-replace-interactive' is non-nil, the last incremental search
308regexp is used as REGEXP--you don't have to specify it with the minibuffer.
309
da44e784 310A prefix argument N says to use each replacement string N times
47d72254
GM
311before rotating to the next.
312Fourth and fifth arg START and END specify the region to operate on."
770970cb 313 (interactive
10784bac 314 (let (from to)
151270f3
RS
315 (setq from (if query-replace-interactive
316 (car regexp-search-ring)
317 (read-from-minibuffer "Map query replace (regexp): "
318 nil nil nil
fce31d51 319 'query-replace-history nil t)))
770970cb
RS
320 (setq to (read-from-minibuffer
321 (format "Query replace %s with (space-separated strings): "
322 from)
323 nil nil nil
4a8f3b3d 324 'query-replace-history from t))
2f2f7e58
RS
325 (list from to
326 (and current-prefix-arg
327 (prefix-numeric-value current-prefix-arg))
10784bac
RS
328 (if (and transient-mark-mode mark-active)
329 (region-beginning))
330 (if (and transient-mark-mode mark-active)
331 (region-end)))))
da44e784
RM
332 (let (replacements)
333 (if (listp to-strings)
334 (setq replacements to-strings)
335 (while (/= (length to-strings) 0)
336 (if (string-match " " to-strings)
337 (setq replacements
338 (append replacements
339 (list (substring to-strings 0
340 (string-match " " to-strings))))
341 to-strings (substring to-strings
342 (1+ (string-match " " to-strings))))
343 (setq replacements (append replacements (list to-strings))
344 to-strings ""))))
99a7559f 345 (perform-replace regexp replacements t t nil n nil start end)))
da44e784 346
47d72254 347(defun replace-string (from-string to-string &optional delimited start end)
da44e784
RM
348 "Replace occurrences of FROM-STRING with TO-STRING.
349Preserve case in each match if `case-replace' and `case-fold-search'
350are non-nil and FROM-STRING has no uppercase letters.
9b0bf2b6
RS
351\(Preserving case means that if the string matched is all caps, or capitalized,
352then its replacement is upcased or capitalized.)
353
7ef5c431
KH
354In Transient Mark mode, if the mark is active, operate on the contents
355of the region. Otherwise, operate from point to the end of the buffer.
356
118a01c9 357Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
da44e784 358only matches surrounded by word boundaries.
47d72254 359Fourth and fifth arg START and END specify the region to operate on.
da44e784 360
151270f3
RS
361If `query-replace-interactive' is non-nil, the last incremental search
362string is used as FROM-STRING--you don't have to specify it with the
363minibuffer.
364
da44e784
RM
365This function is usually the wrong thing to use in a Lisp program.
366What you probably want is a loop like this:
118a01c9
RS
367 (while (search-forward FROM-STRING nil t)
368 (replace-match TO-STRING nil t))
87532fbe
RS
369which will run faster and will not set the mark or print anything.
370\(You may need a more complex loop if FROM-STRING can match the null string
371and TO-STRING is also null.)"
10784bac
RS
372 (interactive
373 (let ((common
374 (query-replace-read-args "Replace string" nil)))
375 (list (nth 0 common) (nth 1 common) (nth 2 common)
376 (if (and transient-mark-mode mark-active)
377 (region-beginning))
378 (if (and transient-mark-mode mark-active)
379 (region-end)))))
99a7559f 380 (perform-replace from-string to-string nil nil delimited nil nil start end))
da44e784 381
47d72254 382(defun replace-regexp (regexp to-string &optional delimited start end)
da44e784 383 "Replace things after point matching REGEXP with TO-STRING.
118a01c9 384Preserve case in each match if `case-replace' and `case-fold-search'
da44e784 385are non-nil and REGEXP has no uppercase letters.
47d72254
GM
386
387In Transient Mark mode, if the mark is active, operate on the contents
388of the region. Otherwise, operate from point to the end of the buffer.
389
118a01c9 390Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
da44e784 391only matches surrounded by word boundaries.
47d72254
GM
392Fourth and fifth arg START and END specify the region to operate on.
393
118a01c9
RS
394In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
395and `\\=\\N' (where N is a digit) stands for
7c1c02ac
DK
396whatever what matched the Nth `\\(...\\)' in REGEXP.
397`\\?' lets you edit the replacement text in the minibuffer
398at the given position for each replacement.
399
400In interactive calls, the replacement text may contain `\\,'
401followed by a Lisp expression used as part of the replacement
402text. Inside of that expression, `\\&' is a string denoting the
403whole match, `\\N' a partial matches, `\\#&' and `\\#N' the
404respective numeric values from `string-to-number', and `\\#'
405itself for `replace-count', the number of replacements occured so
406far.
407
408If your Lisp expression is an identifier and the next letter in
409the replacement string would be interpreted as part of it, you
410can wrap it with an expression like `\\,(or \\#)'. Incidentally,
411for this particular case you may also enter `\\#' in the
412replacement text directly.
413
414When using those Lisp features interactively in the replacement
415text, TO-STRING is actually made a list instead of a string.
416Use \\[repeat-complex-command] after this command for details.
da44e784 417
151270f3
RS
418If `query-replace-interactive' is non-nil, the last incremental search
419regexp is used as REGEXP--you don't have to specify it with the minibuffer.
420
da44e784
RM
421This function is usually the wrong thing to use in a Lisp program.
422What you probably want is a loop like this:
423 (while (re-search-forward REGEXP nil t)
118a01c9 424 (replace-match TO-STRING nil nil))
da44e784 425which will run faster and will not set the mark or print anything."
10784bac
RS
426 (interactive
427 (let ((common
428 (query-replace-read-args "Replace regexp" t)))
429 (list (nth 0 common) (nth 1 common) (nth 2 common)
430 (if (and transient-mark-mode mark-active)
431 (region-beginning))
432 (if (and transient-mark-mode mark-active)
433 (region-end)))))
99a7559f 434 (perform-replace regexp to-string nil t delimited nil nil start end))
e32eb3e6 435
4c53bd2b
RS
436\f
437(defvar regexp-history nil
438 "History list for some commands that read regular expressions.")
da44e784 439
e32eb3e6 440
31e1d920 441(defalias 'delete-non-matching-lines 'keep-lines)
e32eb3e6
GM
442(defalias 'delete-matching-lines 'flush-lines)
443(defalias 'count-matches 'how-many)
444
445
446(defun keep-lines-read-args (prompt)
447 "Read arguments for `keep-lines' and friends.
448Prompt for a regexp with PROMPT.
2ced751f
RS
449Value is a list, (REGEXP)."
450 (list (read-from-minibuffer prompt nil nil nil
451 'regexp-history nil t)))
e32eb3e6
GM
452
453(defun keep-lines (regexp &optional rstart rend)
698e1804
RS
454 "Delete all lines except those containing matches for REGEXP.
455A match split across lines preserves all the lines it lies in.
d2a0ee8b
RS
456Applies to all lines after point.
457
458If REGEXP contains upper case characters (excluding those preceded by `\\'),
e32eb3e6
GM
459the matching is case-sensitive.
460
461Second and third arg RSTART and REND specify the region to operate on.
462
2ced751f
RS
463Interactively, in Transient Mark mode when the mark is active, operate
464on the contents of the region. Otherwise, operate from point to the
465end of the buffer."
466
e32eb3e6 467 (interactive
98faf1bb
RS
468 (progn
469 (barf-if-buffer-read-only)
470 (keep-lines-read-args "Keep lines (containing match for regexp): ")))
e32eb3e6 471 (if rstart
119831da
RS
472 (progn
473 (goto-char (min rstart rend))
474 (setq rend (copy-marker (max rstart rend))))
2ced751f
RS
475 (if (and transient-mark-mode mark-active)
476 (setq rstart (region-beginning)
477 rend (copy-marker (region-end)))
478 (setq rstart (point)
479 rend (point-max-marker)))
480 (goto-char rstart))
698e1804
RS
481 (save-excursion
482 (or (bolp) (forward-line 1))
d2a0ee8b
RS
483 (let ((start (point))
484 (case-fold-search (and case-fold-search
485 (isearch-no-upper-case-p regexp t))))
e32eb3e6 486 (while (< (point) rend)
698e1804 487 ;; Start is first char not preserved by previous match.
e32eb3e6
GM
488 (if (not (re-search-forward regexp rend 'move))
489 (delete-region start rend)
698e1804
RS
490 (let ((end (save-excursion (goto-char (match-beginning 0))
491 (beginning-of-line)
492 (point))))
493 ;; Now end is first char preserved by the new match.
494 (if (< start end)
495 (delete-region start end))))
d99118b0 496
e32eb3e6 497 (setq start (save-excursion (forward-line 1) (point)))
698e1804 498 ;; If the match was empty, avoid matching again at same place.
e32eb3e6
GM
499 (and (< (point) rend)
500 (= (match-beginning 0) (match-end 0))
698e1804
RS
501 (forward-char 1))))))
502
e32eb3e6
GM
503
504(defun flush-lines (regexp &optional rstart rend)
698e1804
RS
505 "Delete lines containing matches for REGEXP.
506If a match is split across lines, all the lines it lies in are deleted.
d2a0ee8b
RS
507Applies to lines after point.
508
509If REGEXP contains upper case characters (excluding those preceded by `\\'),
e32eb3e6
GM
510the matching is case-sensitive.
511
512Second and third arg RSTART and REND specify the region to operate on.
513
2ced751f
RS
514Interactively, in Transient Mark mode when the mark is active, operate
515on the contents of the region. Otherwise, operate from point to the
516end of the buffer."
517
e32eb3e6 518 (interactive
98faf1bb
RS
519 (progn
520 (barf-if-buffer-read-only)
521 (keep-lines-read-args "Flush lines (containing match for regexp): ")))
e32eb3e6 522 (if rstart
119831da
RS
523 (progn
524 (goto-char (min rstart rend))
525 (setq rend (copy-marker (max rstart rend))))
2ced751f
RS
526 (if (and transient-mark-mode mark-active)
527 (setq rstart (region-beginning)
528 rend (copy-marker (region-end)))
529 (setq rstart (point)
530 rend (point-max-marker)))
531 (goto-char rstart))
d2a0ee8b
RS
532 (let ((case-fold-search (and case-fold-search
533 (isearch-no-upper-case-p regexp t))))
534 (save-excursion
e32eb3e6
GM
535 (while (and (< (point) rend)
536 (re-search-forward regexp rend t))
d2a0ee8b
RS
537 (delete-region (save-excursion (goto-char (match-beginning 0))
538 (beginning-of-line)
539 (point))
540 (progn (forward-line 1) (point)))))))
698e1804 541
e32eb3e6
GM
542
543(defun how-many (regexp &optional rstart rend)
d2a0ee8b
RS
544 "Print number of matches for REGEXP following point.
545
546If REGEXP contains upper case characters (excluding those preceded by `\\'),
e32eb3e6
GM
547the matching is case-sensitive.
548
549Second and third arg RSTART and REND specify the region to operate on.
550
2ced751f
RS
551Interactively, in Transient Mark mode when the mark is active, operate
552on the contents of the region. Otherwise, operate from point to the
553end of the buffer."
554
e32eb3e6
GM
555 (interactive
556 (keep-lines-read-args "How many matches for (regexp): "))
f601efb0
SM
557 (save-excursion
558 (if rstart
559 (goto-char (min rstart rend))
2ced751f
RS
560 (if (and transient-mark-mode mark-active)
561 (setq rstart (region-beginning)
562 rend (copy-marker (region-end)))
563 (setq rstart (point)
564 rend (point-max-marker)))
565 (goto-char rstart))
f601efb0
SM
566 (let ((count 0)
567 opoint
568 (case-fold-search (and case-fold-search
569 (isearch-no-upper-case-p regexp t))))
570 (while (and (< (point) rend)
571 (progn (setq opoint (point))
572 (re-search-forward regexp rend t)))
573 (if (= opoint (point))
574 (forward-char 1)
575 (setq count (1+ count))))
576 (message "%d occurrences" count))))
e32eb3e6 577
4c53bd2b 578\f
f601efb0
SM
579(defvar occur-mode-map
580 (let ((map (make-sparse-keymap)))
581 (define-key map [mouse-2] 'occur-mode-mouse-goto)
582 (define-key map "\C-c\C-c" 'occur-mode-goto-occurrence)
583 (define-key map "\C-m" 'occur-mode-goto-occurrence)
daae70bf 584 (define-key map "o" 'occur-mode-goto-occurrence-other-window)
365486d6 585 (define-key map "\C-o" 'occur-mode-display-occurrence)
f601efb0
SM
586 (define-key map "\M-n" 'occur-next)
587 (define-key map "\M-p" 'occur-prev)
d99118b0
SS
588 (define-key map "r" 'occur-rename-buffer)
589 (define-key map "c" 'clone-buffer)
f601efb0 590 (define-key map "g" 'revert-buffer)
d99118b0
SS
591 (define-key map "q" 'quit-window)
592 (define-key map "z" 'kill-this-buffer)
f601efb0
SM
593 map)
594 "Keymap for `occur-mode'.")
698e1804 595
46b3d18e
RS
596(defvar occur-revert-arguments nil
597 "Arguments to pass to `occur-1' to revert an Occur mode buffer.
598See `occur-revert-function'.")
698e1804 599
c9ae8cbb
JB
600(defcustom occur-mode-hook '(turn-on-font-lock)
601 "Hook run when entering Occur mode."
602 :type 'hook
603 :group 'matching)
604
605(defcustom occur-hook nil
606 "Hook run when `occur' is called."
daae70bf
CW
607 :type 'hook
608 :group 'matching)
609
de3c9b09 610(put 'occur-mode 'mode-class 'special)
505847d4 611(defun occur-mode ()
698e1804 612 "Major mode for output from \\[occur].
0081c8a1
RS
613\\<occur-mode-map>Move point to one of the items in this buffer, then use
614\\[occur-mode-goto-occurrence] to go to the occurrence that the item refers to.
615Alternatively, click \\[occur-mode-mouse-goto] on an item to go to it.
616
698e1804 617\\{occur-mode-map}"
ce8b7b9f 618 (interactive)
505847d4
RS
619 (kill-all-local-variables)
620 (use-local-map occur-mode-map)
621 (setq major-mode 'occur-mode)
622 (setq mode-name "Occur")
f601efb0 623 (set (make-local-variable 'revert-buffer-function) 'occur-revert-function)
c9ae8cbb 624 (make-local-variable 'occur-revert-arguments)
fbefbe33 625 (add-hook 'change-major-mode-hook 'font-lock-defontify nil t)
423e4de7 626 (setq next-error-function 'occur-next-error)
c9ae8cbb 627 (run-hooks 'occur-mode-hook))
698e1804 628
a41284da 629(defun occur-revert-function (ignore1 ignore2)
46b3d18e 630 "Handle `revert-buffer' for Occur mode buffers."
e1690783 631 (apply 'occur-1 (append occur-revert-arguments (list (buffer-name)))))
a41284da 632
78bead73
RS
633(defun occur-mode-mouse-goto (event)
634 "In Occur mode, go to the occurrence whose line you click on."
635 (interactive "e")
46b3d18e 636 (let (pos)
78bead73
RS
637 (save-excursion
638 (set-buffer (window-buffer (posn-window (event-end event))))
639 (save-excursion
640 (goto-char (posn-point (event-end event)))
46b3d18e
RS
641 (setq pos (occur-mode-find-occurrence))))
642 (pop-to-buffer (marker-buffer pos))
643 (goto-char pos)))
78bead73
RS
644
645(defun occur-mode-find-occurrence ()
46b3d18e
RS
646 (let ((pos (get-text-property (point) 'occur-target)))
647 (unless pos
68608d9c 648 (error "No occurrence on this line"))
46b3d18e
RS
649 (unless (buffer-live-p (marker-buffer pos))
650 (error "Buffer for this occurrence was killed"))
651 pos))
78bead73
RS
652
653(defun occur-mode-goto-occurrence ()
654 "Go to the occurrence the current line describes."
655 (interactive)
46b3d18e
RS
656 (let ((pos (occur-mode-find-occurrence)))
657 (pop-to-buffer (marker-buffer pos))
658 (goto-char pos)))
8d15583f 659
029024e2
RS
660(defun occur-mode-goto-occurrence-other-window ()
661 "Go to the occurrence the current line describes, in another window."
662 (interactive)
46b3d18e
RS
663 (let ((pos (occur-mode-find-occurrence)))
664 (switch-to-buffer-other-window (marker-buffer pos))
665 (goto-char pos)))
029024e2 666
365486d6
RS
667(defun occur-mode-display-occurrence ()
668 "Display in another window the occurrence the current line describes."
669 (interactive)
46b3d18e
RS
670 (let ((pos (occur-mode-find-occurrence))
671 window
672 ;; Bind these to ensure `display-buffer' puts it in another window.
365486d6 673 same-window-buffer-names
46b3d18e
RS
674 same-window-regexps)
675 (setq window (display-buffer (marker-buffer pos)))
365486d6
RS
676 ;; This is the way to set point in the proper window.
677 (save-selected-window
678 (select-window window)
46b3d18e 679 (goto-char pos))))
365486d6 680
123d5548 681(defun occur-find-match (n search message)
8d15583f
RS
682 (if (not n) (setq n 1))
683 (let ((r))
684 (while (> n 0)
123d5548
JB
685 (setq r (funcall search (point) 'occur-match))
686 (and r
687 (get-text-property r 'occur-match)
688 (setq r (funcall search r 'occur-match)))
8d15583f 689 (if r
123d5548
JB
690 (goto-char r)
691 (error message))
8d15583f
RS
692 (setq n (1- n)))))
693
123d5548
JB
694(defun occur-next (&optional n)
695 "Move to the Nth (default 1) next match in an Occur mode buffer."
696 (interactive "p")
697 (occur-find-match n #'next-single-property-change "No more matches"))
698
8d15583f 699(defun occur-prev (&optional n)
46b3d18e 700 "Move to the Nth (default 1) previous match in an Occur mode buffer."
8d15583f 701 (interactive "p")
123d5548 702 (occur-find-match n #'previous-single-property-change "No earlier matches"))
423e4de7
KS
703
704(defun occur-next-error (&optional argp reset)
705 "Move to the Nth (default 1) next match in an Occur mode buffer.
706Compatibility function for \\[next-error] invocations."
707 (interactive "p")
708 (when reset
709 (occur-find-match 0 #'next-single-property-change "No first match"))
710 (occur-find-match
711 (prefix-numeric-value argp)
712 (if (> 0 (prefix-numeric-value argp))
713 #'previous-single-property-change
714 #'next-single-property-change)
715 "No more matches")
716 (occur-mode-goto-occurrence))
717
4c53bd2b 718\f
9d325ebf 719(defcustom list-matching-lines-default-context-lines 0
e730be7f
DL
720 "*Default number of context lines included around `list-matching-lines' matches.
721A negative number means to include that many lines before the match.
9d325ebf
RS
722A positive number means to include that many lines both before and after."
723 :type 'integer
724 :group 'matching)
698e1804 725
31e1d920 726(defalias 'list-matching-lines 'occur)
698e1804 727
68608d9c 728(defcustom list-matching-lines-face 'bold
e730be7f 729 "*Face used by \\[list-matching-lines] to show the text that matches.
68608d9c
CW
730If the value is nil, don't highlight the matching portions specially."
731 :type 'face
732 :group 'matching)
733
734(defcustom list-matching-lines-buffer-name-face 'underline
735 "*Face used by \\[list-matching-lines] to show the names of buffers.
736If the value is nil, don't highlight the buffer names specially."
737 :type 'face
738 :group 'matching)
739
9e2b2e30 740(defun occur-accumulate-lines (count &optional no-props)
68608d9c
CW
741 (save-excursion
742 (let ((forwardp (> count 0))
743 (result nil))
744 (while (not (or (zerop count)
745 (if forwardp
746 (eobp)
747 (bobp))))
b0523087 748 (setq count (+ count (if forwardp -1 1)))
68608d9c 749 (push
9e2b2e30
CW
750 (funcall (if no-props
751 #'buffer-substring-no-properties
752 #'buffer-substring)
68608d9c
CW
753 (line-beginning-position)
754 (line-end-position))
755 result)
756 (forward-line (if forwardp 1 -1)))
757 (nreverse result))))
758
759(defun occur-read-primary-args ()
760 (list (let* ((default (car regexp-history))
761 (input
762 (read-from-minibuffer
763 (if default
764 (format "List lines matching regexp (default `%s'): "
765 default)
766 "List lines matching regexp: ")
767 nil
768 nil
769 nil
770 'regexp-history)))
771 (if (equal input "")
772 default
773 input))
bda1925e
CW
774 (when current-prefix-arg
775 (prefix-numeric-value current-prefix-arg))))
c9daced0 776
d99118b0
SS
777(defun occur-rename-buffer (&optional unique-p)
778 "Rename the current *Occur* buffer to *Occur: original-buffer-name*.
779Here `original-buffer-name' is the buffer name were occur was originally run.
780When given the prefix argument, the renaming will not clobber the existing
781buffer(s) of that name, but use `generate-new-buffer-name' instead.
2fb79329 782You can add this to `occur-hook' if you always want a separate *Occur*
d99118b0
SS
783buffer for each buffer where you invoke `occur'."
784 (interactive "P")
785 (with-current-buffer
786 (if (eq major-mode 'occur-mode) (current-buffer) (get-buffer "*Occur*"))
787 (rename-buffer (concat "*Occur: "
788 (mapconcat #'buffer-name
789 (car (cddr occur-revert-arguments)) "/")
790 "*")
791 unique-p)))
792
698e1804 793(defun occur (regexp &optional nlines)
99976f85 794 "Show all lines in the current buffer containing a match for REGEXP.
da44e784
RM
795
796If a match spreads across multiple lines, all those lines are shown.
698e1804 797
da44e784
RM
798Each line is displayed with NLINES lines before and after, or -NLINES
799before if NLINES is negative.
800NLINES defaults to `list-matching-lines-default-context-lines'.
698e1804
RS
801Interactively it is the prefix arg.
802
4c53bd2b 803The lines are shown in a buffer named `*Occur*'.
698e1804 804It serves as a menu to find any of the occurrences in this buffer.
de3c9b09 805\\<occur-mode-map>\\[describe-mode] in that buffer will explain how.
9483d601 806
de3c9b09
RS
807If REGEXP contains upper case characters (excluding those preceded by `\\'),
808the matching is case-sensitive."
68608d9c
CW
809 (interactive (occur-read-primary-args))
810 (occur-1 regexp nlines (list (current-buffer))))
811
812(defun multi-occur (bufs regexp &optional nlines)
813 "Show all lines in buffers BUFS containing a match for REGEXP.
814This function acts on multiple buffers; otherwise, it is exactly like
815`occur'."
a5dfed3e 816 (interactive
68608d9c 817 (cons
52698d45
KS
818 (let* ((bufs (list (read-buffer "First buffer to search: "
819 (current-buffer) t)))
820 (buf nil)
821 (ido-ignore-item-temp-list bufs))
68608d9c 822 (while (not (string-equal
f1180544 823 (setq buf (read-buffer
52698d45
KS
824 (if (eq read-buffer-function 'ido-read-buffer)
825 "Next buffer to search (C-j to end): "
826 "Next buffer to search (RET to end): ")
827 nil t))
68608d9c 828 ""))
52698d45
KS
829 (add-to-list 'bufs buf)
830 (setq ido-ignore-item-temp-list bufs))
68608d9c
CW
831 (nreverse (mapcar #'get-buffer bufs)))
832 (occur-read-primary-args)))
833 (occur-1 regexp nlines bufs))
834
835(defun multi-occur-by-filename-regexp (bufregexp regexp &optional nlines)
04fe158a 836 "Show all lines matching REGEXP in buffers named by BUFREGEXP.
68608d9c
CW
837See also `multi-occur'."
838 (interactive
839 (cons
840 (let* ((default (car regexp-history))
841 (input
842 (read-from-minibuffer
843 "List lines in buffers whose filename matches regexp: "
844 nil
845 nil
846 nil
847 'regexp-history)))
848 (if (equal input "")
849 default
850 input))
851 (occur-read-primary-args)))
852 (when bufregexp
853 (occur-1 regexp nlines
854 (delq nil
855 (mapcar (lambda (buf)
856 (when (and (buffer-file-name buf)
857 (string-match bufregexp
858 (buffer-file-name buf)))
859 buf))
860 (buffer-list))))))
861
e1690783
CW
862(defun occur-1 (regexp nlines bufs &optional buf-name)
863 (unless buf-name
864 (setq buf-name "*Occur*"))
865 (let ((occur-buf (get-buffer-create buf-name))
70ed2a76
CW
866 (made-temp-buf nil)
867 (active-bufs (delq nil (mapcar #'(lambda (buf)
868 (when (buffer-live-p buf) buf))
869 bufs))))
870 ;; Handle the case where one of the buffers we're searching is the
871 ;; *Occur* buffer itself.
872 (when (memq occur-buf bufs)
873 (setq occur-buf (with-current-buffer occur-buf
874 (clone-buffer "*Occur-temp*"))
875 made-temp-buf t))
68608d9c
CW
876 (with-current-buffer occur-buf
877 (setq buffer-read-only nil)
878 (occur-mode)
879 (erase-buffer)
880 (let ((count (occur-engine
70ed2a76 881 regexp active-bufs occur-buf
68608d9c
CW
882 (or nlines list-matching-lines-default-context-lines)
883 (and case-fold-search
884 (isearch-no-upper-case-p regexp t))
506a6d7e
CW
885 list-matching-lines-buffer-name-face
886 nil list-matching-lines-face nil)))
b2043e7b
AS
887 (let* ((bufcount (length active-bufs))
888 (diff (- (length bufs) bufcount)))
889 (message "Searched %d buffer%s%s; %s match%s for `%s'"
890 bufcount (if (= bufcount 1) "" "s")
891 (if (zerop diff) "" (format " (%d killed)" diff))
892 (if (zerop count) "no" (format "%d" count))
893 (if (= count 1) "" "es")
894 regexp))
70ed2a76
CW
895 ;; If we had to make a temporary buffer, make it the *Occur*
896 ;; buffer now.
897 (when made-temp-buf
e1690783
CW
898 (with-current-buffer (get-buffer buf-name)
899 (kill-buffer (current-buffer)))
900 (rename-buffer buf-name))
70ed2a76
CW
901 (setq occur-revert-arguments (list regexp nlines bufs)
902 buffer-read-only t)
68608d9c 903 (if (> count 0)
423e4de7
KS
904 (progn
905 (display-buffer occur-buf)
906 (setq next-error-last-buffer occur-buf))
2fb79329
JB
907 (kill-buffer occur-buf)))
908 (run-hooks 'occur-hook))))
68608d9c 909
46b3d18e
RS
910(defun occur-engine-add-prefix (lines)
911 (mapcar
912 #'(lambda (line)
261cca88 913 (concat " :" line "\n"))
46b3d18e
RS
914 lines))
915
916(defun occur-engine (regexp buffers out-buf nlines case-fold-search
917 title-face prefix-face match-face keep-props)
918 (with-current-buffer out-buf
919 (setq buffer-read-only nil)
5cb4031d
KH
920 (let ((globalcount 0)
921 (coding nil))
46b3d18e
RS
922 ;; Map over all the buffers
923 (dolist (buf buffers)
924 (when (buffer-live-p buf)
925 (let ((matches 0) ;; count of matched lines
926 (lines 1) ;; line count
927 (matchbeg 0)
928 (matchend 0)
929 (origpt nil)
930 (begpt nil)
931 (endpt nil)
932 (marker nil)
933 (curstring "")
934 (headerpt (with-current-buffer out-buf (point))))
935 (save-excursion
936 (set-buffer buf)
5cb4031d
KH
937 (or coding
938 ;; Set CODING only if the current buffer locally
939 ;; binds buffer-file-coding-system.
940 (not (local-variable-p 'buffer-file-coding-system))
941 (setq coding buffer-file-coding-system))
68608d9c 942 (save-excursion
46b3d18e
RS
943 (goto-char (point-min)) ;; begin searching in the buffer
944 (while (not (eobp))
945 (setq origpt (point))
946 (when (setq endpt (re-search-forward regexp nil t))
947 (setq matches (1+ matches)) ;; increment match count
46b3d18e
RS
948 (setq matchbeg (match-beginning 0)
949 matchend (match-end 0))
950 (setq begpt (save-excursion
951 (goto-char matchbeg)
952 (line-beginning-position)))
953 (setq lines (+ lines (1- (count-lines origpt endpt))))
954 (setq marker (make-marker))
955 (set-marker marker matchbeg)
956 (setq curstring (buffer-substring begpt
957 (line-end-position)))
958 ;; Depropertize the string, and maybe
959 ;; highlight the matches
960 (let ((len (length curstring))
961 (start 0))
962 (unless keep-props
963 (set-text-properties 0 len nil curstring))
964 (while (and (< start len)
965 (string-match regexp curstring start))
966 (add-text-properties (match-beginning 0)
967 (match-end 0)
968 (append
506a6d7e 969 `(occur-match t)
46b3d18e 970 (when match-face
506a6d7e 971 `(font-lock-face ,match-face)))
46b3d18e
RS
972 curstring)
973 (setq start (match-end 0))))
974 ;; Generate the string to insert for this match
975 (let* ((out-line
976 (concat
261cca88
RS
977 ;; Using 7 digits aligns tabs properly.
978 (apply #'propertize (format "%7d:" lines)
46b3d18e
RS
979 (append
980 (when prefix-face
506a6d7e 981 `(font-lock-face prefix-face))
46b3d18e
RS
982 '(occur-prefix t)))
983 curstring
984 "\n"))
985 (data
986 (if (= nlines 0)
987 ;; The simple display style
988 out-line
989 ;; The complex multi-line display
990 ;; style. Generate a list of lines,
991 ;; concatenate them all together.
992 (apply #'concat
993 (nconc
b0523087 994 (occur-engine-add-prefix (nreverse (cdr (occur-accumulate-lines (- (1+ nlines)) keep-props))))
46b3d18e 995 (list out-line)
b0523087 996 (occur-engine-add-prefix (cdr (occur-accumulate-lines (1+ nlines) keep-props))))))))
46b3d18e
RS
997 ;; Actually insert the match display data
998 (with-current-buffer out-buf
999 (let ((beg (point))
1000 (end (progn (insert data) (point))))
1001 (unless (= nlines 0)
1002 (insert "-------\n"))
1003 (add-text-properties
e8e2a88c
CW
1004 beg end
1005 `(occur-target ,marker help-echo "mouse-2: go to this occurrence"))
1006 ;; We don't put `mouse-face' on the newline,
1007 ;; because that loses.
1008 (add-text-properties beg (1- end) '(mouse-face highlight)))))
46b3d18e 1009 (goto-char endpt))
e1690783
CW
1010 (if endpt
1011 (progn
1012 (setq lines (1+ lines))
1013 ;; On to the next match...
1014 (forward-line 1))
1015 (goto-char (point-max))))))
46b3d18e 1016 (when (not (zerop matches)) ;; is the count zero?
daae70bf 1017 (setq globalcount (+ globalcount matches))
46b3d18e
RS
1018 (with-current-buffer out-buf
1019 (goto-char headerpt)
1020 (let ((beg (point))
1021 end)
dbed3cd3
JPW
1022 (insert (format "%d match%s for \"%s\" in buffer: %s\n"
1023 matches (if (= matches 1) "" "es")
1024 regexp (buffer-name buf)))
46b3d18e
RS
1025 (setq end (point))
1026 (add-text-properties beg end
1027 (append
1028 (when title-face
506a6d7e
CW
1029 `(font-lock-face ,title-face))
1030 `(occur-title ,buf))))
46b3d18e 1031 (goto-char (point-min)))))))
5cb4031d
KH
1032 (if coding
1033 ;; CODING is buffer-file-coding-system of the first buffer
1034 ;; that locally binds it. Let's use it also for the output
1035 ;; buffer.
1036 (set-buffer-file-coding-system coding))
46b3d18e
RS
1037 ;; Return the number of matches
1038 globalcount)))
68608d9c 1039
698e1804 1040\f
81bdc14d
RS
1041;; It would be nice to use \\[...], but there is no reasonable way
1042;; to make that display both SPC and Y.
698e1804
RS
1043(defconst query-replace-help
1044 "Type Space or `y' to replace one match, Delete or `n' to skip to next,
be44f62c 1045RET or `q' to exit, Period to replace one match and exit,
698e1804
RS
1046Comma to replace but not move point immediately,
1047C-r to enter recursive edit (\\[exit-recursive-edit] to get out again),
1048C-w to delete match and recursive edit,
1049C-l to clear the screen, redisplay, and offer same replacement again,
1050! to replace all remaining matches with no more questions,
7ce278f3
GM
1051^ to move point back to previous match,
1052E to edit the replacement string"
f54701d1 1053 "Help message while in `query-replace'.")
698e1804 1054
81bdc14d
RS
1055(defvar query-replace-map (make-sparse-keymap)
1056 "Keymap that defines the responses to questions in `query-replace'.
1057The \"bindings\" in this map are not commands; they are answers.
1058The valid answers include `act', `skip', `act-and-show',
1059`exit', `act-and-exit', `edit', `delete-and-edit', `recenter',
d9121bc0 1060`automatic', `backup', `exit-prefix', and `help'.")
81bdc14d
RS
1061
1062(define-key query-replace-map " " 'act)
1063(define-key query-replace-map "\d" 'skip)
1064(define-key query-replace-map [delete] 'skip)
9275e5e3 1065(define-key query-replace-map [backspace] 'skip)
81bdc14d
RS
1066(define-key query-replace-map "y" 'act)
1067(define-key query-replace-map "n" 'skip)
633a305a
RS
1068(define-key query-replace-map "Y" 'act)
1069(define-key query-replace-map "N" 'skip)
34724fcb 1070(define-key query-replace-map "e" 'edit-replacement)
7ce278f3 1071(define-key query-replace-map "E" 'edit-replacement)
81bdc14d 1072(define-key query-replace-map "," 'act-and-show)
81bdc14d 1073(define-key query-replace-map "q" 'exit)
919592c0 1074(define-key query-replace-map "\r" 'exit)
384c7da4 1075(define-key query-replace-map [return] 'exit)
81bdc14d
RS
1076(define-key query-replace-map "." 'act-and-exit)
1077(define-key query-replace-map "\C-r" 'edit)
1078(define-key query-replace-map "\C-w" 'delete-and-edit)
1079(define-key query-replace-map "\C-l" 'recenter)
1080(define-key query-replace-map "!" 'automatic)
1081(define-key query-replace-map "^" 'backup)
1082(define-key query-replace-map "\C-h" 'help)
e731045a
KH
1083(define-key query-replace-map [f1] 'help)
1084(define-key query-replace-map [help] 'help)
81bdc14d 1085(define-key query-replace-map "?" 'help)
bc6312e1
RS
1086(define-key query-replace-map "\C-g" 'quit)
1087(define-key query-replace-map "\C-]" 'quit)
d9121bc0
RS
1088(define-key query-replace-map "\e" 'exit-prefix)
1089(define-key query-replace-map [escape] 'exit-prefix)
81bdc14d 1090
84482eb3 1091(defun replace-match-string-symbols (n)
e730be7f
DL
1092 "Process a list (and any sub-lists), expanding certain symbols.
1093Symbol Expands To
1094N (match-string N) (where N is a string of digits)
1095#N (string-to-number (match-string N))
1096& (match-string 0)
1097#& (string-to-number (match-string 0))
2f57bf85 1098# replace-count
e730be7f
DL
1099
1100Note that these symbols must be preceeded by a backslash in order to
1101type them."
84482eb3
RS
1102 (while n
1103 (cond
1104 ((consp (car n))
1105 (replace-match-string-symbols (car n))) ;Process sub-list
1106 ((symbolp (car n))
1107 (let ((name (symbol-name (car n))))
1108 (cond
1109 ((string-match "^[0-9]+$" name)
1110 (setcar n (list 'match-string (string-to-number name))))
1111 ((string-match "^#[0-9]+$" name)
1112 (setcar n (list 'string-to-number
1113 (list 'match-string
1114 (string-to-number (substring name 1))))))
1115 ((string= "&" name)
1116 (setcar n '(match-string 0)))
1117 ((string= "#&" name)
2f57bf85
DK
1118 (setcar n '(string-to-number (match-string 0))))
1119 ((string= "#" name)
1120 (setcar n 'replace-count))))))
84482eb3
RS
1121 (setq n (cdr n))))
1122
1123(defun replace-eval-replacement (expression replace-count)
1124 (let ((replacement (eval expression)))
1125 (if (stringp replacement)
1126 replacement
1127 (prin1-to-string replacement t))))
1128
2f57bf85
DK
1129(defun replace-quote (replacement)
1130 "Quote a replacement string.
1131This just doubles all backslashes in REPLACEMENT and
1132returns the resulting string. If REPLACEMENT is not
1133a string, it is first passed through `prin1-to-string'
1134with the `noescape' argument set.
1135
1136`match-data' is preserved across the call."
1137 (save-match-data
1138 (replace-regexp-in-string "\\\\" "\\\\"
1139 (if (stringp replacement)
1140 replacement
1141 (prin1-to-string replacement t))
1142 t t)))
1143
84482eb3
RS
1144(defun replace-loop-through-replacements (data replace-count)
1145 ;; DATA is a vector contaning the following values:
1146 ;; 0 next-rotate-count
1147 ;; 1 repeat-count
1148 ;; 2 next-replacement
1149 ;; 3 replacements
1150 (if (= (aref data 0) replace-count)
1151 (progn
1152 (aset data 0 (+ replace-count (aref data 1)))
1153 (let ((next (cdr (aref data 2))))
1154 (aset data 2 (if (consp next) next (aref data 3))))))
1155 (car (aref data 2)))
1156
7c1c02ac
DK
1157(defun replace-match-data (integers reuse &optional new)
1158 "Like `match-data', but markers in REUSE get invalidated.
1159If NEW is non-NIL, it is set and returned instead of fresh data,
1160but coerced to the correct value of INTEGERS."
1161 (or (and new
1162 (progn
1163 (set-match-data new)
1164 (and (eq new reuse)
1165 (eq (null integers) (markerp (car reuse)))
1166 new)))
1167 (match-data integers
1168 (prog1 reuse
1169 (while reuse
1170 (if (markerp (car reuse))
1171 (set-marker (car reuse) nil))
1172 (setq reuse (cdr reuse)))))))
1173
1174(defun replace-match-maybe-edit (newtext fixedcase literal noedit match-data)
1175 "Make a replacement with `replace-match', editing `\\?'.
1176NEXTEXT, FIXEDCASE, LITERAL are just passed on. If NOEDIT is true, no
1177check for `\\?' is made to save time. MATCH-DATA is used for the
1178replacement. In case editing is done, it is changed to use markers.
1179
1180The return value is non-NIL if there has been no `\\?' or NOEDIT was
1181passed in. If LITERAL is set, no checking is done, anyway."
1182 (unless (or literal noedit)
1183 (setq noedit t)
1184 (while (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\(\\\\\\?\\)"
1185 newtext)
1186 (setq newtext
1187 (read-input "Edit replacement string: "
1188 (prog1
1189 (cons
1190 (replace-match "" t t newtext 3)
1191 (1+ (match-beginning 3)))
1192 (setq match-data
1193 (replace-match-data
1194 nil match-data match-data))))
1195 noedit nil)))
1196 (set-match-data match-data)
1197 (replace-match newtext fixedcase literal)
1198 noedit)
1199
d99118b0 1200(defun perform-replace (from-string replacements
698e1804 1201 query-flag regexp-flag delimited-flag
99a7559f 1202 &optional repeat-count map start end)
698e1804
RS
1203 "Subroutine of `query-replace'. Its complexity handles interactive queries.
1204Don't use this in your own program unless you want to query and set the mark
1205just as `query-replace' does. Instead, write a simple loop like this:
698665d1
GM
1206
1207 (while (re-search-forward \"foo[ \\t]+bar\" nil t)
698e1804 1208 (replace-match \"foobar\" nil nil))
698665d1
GM
1209
1210which will run faster and probably do exactly what you want. Please
1211see the documentation of `replace-match' to find out how to simulate
588c915a
CW
1212`case-replace'.
1213
1214This function returns nil if and only if there were no matches to
1215make, or the user didn't cancel the call."
81bdc14d 1216 (or map (setq map query-replace-map))
1c1dadab
RS
1217 (and query-flag minibuffer-auto-raise
1218 (raise-frame (window-frame (minibuffer-window))))
698e1804
RS
1219 (let ((nocasify (not (and case-fold-search case-replace
1220 (string-equal from-string
1221 (downcase from-string)))))
5a78b471
KH
1222 (case-fold-search (and case-fold-search
1223 (string-equal from-string
1224 (downcase from-string))))
d83a97ab 1225 (literal (or (not regexp-flag) (eq regexp-flag 'literal)))
698e1804
RS
1226 (search-function (if regexp-flag 're-search-forward 'search-forward))
1227 (search-string from-string)
e5d77022 1228 (real-match-data nil) ; the match data for the current match
698e1804 1229 (next-replacement nil)
7c1c02ac 1230 (noedit nil)
698e1804
RS
1231 (keep-going t)
1232 (stack nil)
698e1804 1233 (replace-count 0)
5632eb27
PE
1234 (nonempty-match nil)
1235
7ef5c431
KH
1236 ;; If non-nil, it is marker saying where in the buffer to stop.
1237 (limit nil)
1238
5632eb27
PE
1239 ;; Data for the next match. If a cons, it has the same format as
1240 ;; (match-data); otherwise it is t if a match is possible at point.
ae4eb03c 1241 (match-again t)
5632eb27 1242
02d95a27
RS
1243 (message
1244 (if query-flag
1245 (substitute-command-keys
1246 "Query replacing %s with %s: (\\<query-replace-map>\\[help] for help) "))))
7ef5c431
KH
1247
1248 ;; If region is active, in Transient Mark mode, operate on region.
47d72254
GM
1249 (when start
1250 (setq limit (copy-marker (max start end)))
1251 (goto-char (min start end))
1252 (deactivate-mark))
84482eb3
RS
1253
1254 ;; REPLACEMENTS is either a string, a list of strings, or a cons cell
1255 ;; containing a function and its first argument. The function is
1256 ;; called to generate each replacement like this:
1257 ;; (funcall (car replacements) (cdr replacements) replace-count)
1258 ;; It must return a string.
1259 (cond
1260 ((stringp replacements)
1261 (setq next-replacement replacements
1262 replacements nil))
1263 ((stringp (car replacements)) ; If it isn't a string, it must be a cons
1264 (or repeat-count (setq repeat-count 1))
1265 (setq replacements (cons 'replace-loop-through-replacements
1266 (vector repeat-count repeat-count
1267 replacements replacements)))))
1268
698e1804
RS
1269 (if delimited-flag
1270 (setq search-function 're-search-forward
1271 search-string (concat "\\b"
1272 (if regexp-flag from-string
1273 (regexp-quote from-string))
1274 "\\b")))
1275 (push-mark)
1276 (undo-boundary)
e782e9f2
RS
1277 (unwind-protect
1278 ;; Loop finding occurrences that perhaps should be replaced.
1279 (while (and keep-going
22a76778 1280 (not (or (eobp) (and limit (>= (point) limit))))
5632eb27
PE
1281 ;; Use the next match if it is already known;
1282 ;; otherwise, search for a match after moving forward
1283 ;; one char if progress is required.
1284 (setq real-match-data
1285 (if (consp match-again)
1286 (progn (goto-char (nth 1 match-again))
7c1c02ac
DK
1287 (replace-match-data t
1288 real-match-data
1289 match-again))
5632eb27 1290 (and (or match-again
889617de
GM
1291 ;; MATCH-AGAIN non-nil means we
1292 ;; accept an adjacent match. If
1293 ;; we don't, move one char to the
1294 ;; right. This takes us a
1295 ;; character too far at the end,
1296 ;; but this is undone after the
1297 ;; while-loop.
22a76778
JL
1298 (progn
1299 (forward-char 1)
1300 (not (or (eobp)
1301 (and limit (>= (point) limit))))))
7ef5c431 1302 (funcall search-function search-string limit t)
5632eb27
PE
1303 ;; For speed, use only integers and
1304 ;; reuse the list used last time.
7c1c02ac 1305 (replace-match-data t real-match-data)))))
1c4fe319
RS
1306 ;; Optionally ignore matches that have a read-only property.
1307 (unless (and query-replace-skip-read-only
1308 (text-property-not-all
1309 (match-beginning 0) (match-end 0)
1310 'read-only nil))
1311
1312 ;; Record whether the match is nonempty, to avoid an infinite loop
1313 ;; repeatedly matching the same empty string.
1314 (setq nonempty-match
1315 (/= (nth 0 real-match-data) (nth 1 real-match-data)))
1316
1317 ;; If the match is empty, record that the next one can't be
1318 ;; adjacent.
1319
1320 ;; Otherwise, if matching a regular expression, do the next
1321 ;; match now, since the replacement for this match may
1322 ;; affect whether the next match is adjacent to this one.
1323 ;; If that match is empty, don't use it.
1324 (setq match-again
1325 (and nonempty-match
1326 (or (not regexp-flag)
1327 (and (looking-at search-string)
1328 (let ((match (match-data)))
1329 (and (/= (nth 0 match) (nth 1 match))
1330 match))))))
1331
1332 ;; Calculate the replacement string, if necessary.
1333 (when replacements
1334 (set-match-data real-match-data)
1335 (setq next-replacement
1336 (funcall (car replacements) (cdr replacements)
7c1c02ac
DK
1337 replace-count)
1338 noedit nil))
1c4fe319 1339 (if (not query-flag)
cb05ca25
DK
1340 (let ((inhibit-read-only
1341 query-replace-skip-read-only))
1342 (unless noedit
1343 (replace-highlight (nth 0 real-match-data)
1344 (nth 1 real-match-data)))
7c1c02ac
DK
1345 (setq noedit
1346 (replace-match-maybe-edit
1347 next-replacement nocasify literal
1348 noedit real-match-data)
1349 replace-count (1+ replace-count)))
1c4fe319
RS
1350 (undo-boundary)
1351 (let (done replaced key def)
1352 ;; Loop reading commands until one of them sets done,
7c1c02ac
DK
1353 ;; which means it has finished handling this
1354 ;; occurrence. Any command that sets `done' should
1355 ;; leave behind proper match data for the stack.
1356 ;; Commands not setting `done' need to adjust
1357 ;; `real-match-data'.
1c4fe319
RS
1358 (while (not done)
1359 (set-match-data real-match-data)
1360 (replace-highlight (match-beginning 0) (match-end 0))
1361 ;; Bind message-log-max so we don't fill up the message log
1362 ;; with a bunch of identical messages.
1363 (let ((message-log-max nil))
1364 (message message from-string next-replacement))
1365 (setq key (read-event))
1366 ;; Necessary in case something happens during read-event
1367 ;; that clobbers the match data.
1368 (set-match-data real-match-data)
1369 (setq key (vector key))
1370 (setq def (lookup-key map key))
1371 ;; Restore the match data while we process the command.
1372 (cond ((eq def 'help)
1373 (with-output-to-temp-buffer "*Help*"
1374 (princ
1375 (concat "Query replacing "
1376 (if regexp-flag "regexp " "")
1377 from-string " with "
1378 next-replacement ".\n\n"
1379 (substitute-command-keys
1380 query-replace-help)))
1381 (with-current-buffer standard-output
1382 (help-mode))))
1383 ((eq def 'exit)
1384 (setq keep-going nil)
1385 (setq done t))
1386 ((eq def 'backup)
1387 (if stack
588c915a 1388 (let ((elt (pop stack)))
7c1c02ac
DK
1389 (goto-char (nth 0 elt))
1390 (setq replaced (nth 1 elt)
1391 real-match-data
1392 (replace-match-data
1393 t real-match-data
1394 (nth 2 elt))))
1c4fe319
RS
1395 (message "No previous match")
1396 (ding 'no-terminate)
1397 (sit-for 1)))
1398 ((eq def 'act)
1399 (or replaced
7c1c02ac
DK
1400 (setq noedit
1401 (replace-match-maybe-edit
1402 next-replacement nocasify literal
1403 noedit real-match-data)
1404 replace-count (1+ replace-count)))
1c4fe319
RS
1405 (setq done t replaced t))
1406 ((eq def 'act-and-exit)
1407 (or replaced
7c1c02ac 1408 (setq noedit
da6eb51c 1409 (replace-match-maybe-edit
7c1c02ac
DK
1410 next-replacement nocasify literal
1411 noedit real-match-data)
1412 replace-count (1+ replace-count)))
1c4fe319
RS
1413 (setq keep-going nil)
1414 (setq done t replaced t))
1415 ((eq def 'act-and-show)
1416 (if (not replaced)
7c1c02ac
DK
1417 (setq noedit
1418 (replace-match-maybe-edit
1419 next-replacement nocasify literal
1420 noedit real-match-data)
1421 replace-count (1+ replace-count)
1422 real-match-data (replace-match-data
1423 t real-match-data)
1424 replaced t)))
1c4fe319
RS
1425 ((eq def 'automatic)
1426 (or replaced
7c1c02ac
DK
1427 (setq noedit
1428 (replace-match-maybe-edit
1429 next-replacement nocasify literal
1430 noedit real-match-data)
1431 replace-count (1+ replace-count)))
1c4fe319
RS
1432 (setq done t query-flag nil replaced t))
1433 ((eq def 'skip)
1434 (setq done t))
1435 ((eq def 'recenter)
1436 (recenter nil))
1437 ((eq def 'edit)
1438 (let ((opos (point-marker)))
7c1c02ac
DK
1439 (setq real-match-data (replace-match-data
1440 nil real-match-data
1441 real-match-data))
1c4fe319 1442 (goto-char (match-beginning 0))
86914dcc
RS
1443 (save-excursion
1444 (save-window-excursion
1445 (recursive-edit)))
7c1c02ac
DK
1446 (goto-char opos)
1447 (set-marker opos nil))
1c4fe319
RS
1448 ;; Before we make the replacement,
1449 ;; decide whether the search string
1450 ;; can match again just after this match.
1451 (if (and regexp-flag nonempty-match)
1452 (setq match-again (and (looking-at search-string)
1453 (match-data)))))
1c4fe319
RS
1454 ;; Edit replacement.
1455 ((eq def 'edit-replacement)
7c1c02ac
DK
1456 (setq real-match-data (replace-match-data
1457 nil real-match-data
1458 real-match-data)
1459 next-replacement
1c4fe319 1460 (read-input "Edit replacement string: "
7c1c02ac
DK
1461 next-replacement)
1462 noedit nil)
1463 (if replaced
1464 (set-match-data real-match-data)
1465 (setq noedit
1466 (replace-match-maybe-edit
1467 next-replacement nocasify literal noedit
1468 real-match-data)
1469 replaced t))
1c4fe319 1470 (setq done t))
d99118b0 1471
1c4fe319 1472 ((eq def 'delete-and-edit)
7c1c02ac
DK
1473 (replace-match "" t t)
1474 (setq real-match-data (replace-match-data
1475 nil real-match-data))
1476 (replace-dehighlight)
1477 (save-excursion (recursive-edit))
1c4fe319
RS
1478 (setq replaced t))
1479 ;; Note: we do not need to treat `exit-prefix'
1480 ;; specially here, since we reread
1481 ;; any unrecognized character.
1482 (t
1483 (setq this-command 'mode-exited)
1484 (setq keep-going nil)
1485 (setq unread-command-events
1486 (append (listify-key-sequence key)
1487 unread-command-events))
1488 (setq done t))))
1489 ;; Record previous position for ^ when we move on.
1490 ;; Change markers to numbers in the match data
1491 ;; since lots of markers slow down editing.
7c1c02ac
DK
1492 (push (list (point) replaced
1493;;; If the replacement has already happened, all we need is the
1494;;; current match start and end. We could get this with a trivial
1495;;; match like
1496;;; (save-excursion (goto-char (match-beginning 0))
1497;;; (search-forward (match-string 0))
1498;;; (match-data t))
1499;;; if we really wanted to avoid manually constructing match data.
1500;;; Adding current-buffer is necessary so that match-data calls can
1501;;; return markers which are appropriate for editing.
1502 (if replaced
1503 (list
1504 (match-beginning 0)
1505 (match-end 0)
1506 (current-buffer))
1507 (match-data t)))
1508 stack)))))
889617de
GM
1509
1510 ;; The code preventing adjacent regexp matches in the condition
1511 ;; of the while-loop above will haven taken us one character
1512 ;; beyond the last replacement. Undo that.
1513 (when (and regexp-flag (not match-again) (> replace-count 0))
1514 (backward-char 1))
d99118b0 1515
e782e9f2 1516 (replace-dehighlight))
4d33492a
RS
1517 (or unread-command-events
1518 (message "Replaced %d occurrence%s"
1519 replace-count
1520 (if (= replace-count 1) "" "s")))
1521 (and keep-going stack)))
698e1804 1522
95807e68 1523(defcustom query-replace-highlight t
9d325ebf
RS
1524 "*Non-nil means to highlight words during query replacement."
1525 :type 'boolean
1526 :group 'matching)
e782e9f2
RS
1527
1528(defvar replace-overlay nil)
1529
1530(defun replace-dehighlight ()
1531 (and replace-overlay
1532 (progn
1533 (delete-overlay replace-overlay)
1534 (setq replace-overlay nil))))
1535
1536(defun replace-highlight (start end)
1537 (and query-replace-highlight
7c1c02ac
DK
1538 (if replace-overlay
1539 (move-overlay replace-overlay start end (current-buffer))
1540 (setq replace-overlay (make-overlay start end))
1541 (overlay-put replace-overlay 'face
1542 (if (facep 'query-replace)
1543 'query-replace 'region)))))
e782e9f2 1544
ab5796a9 1545;;; arch-tag: 16b4cd61-fd40-497b-b86f-b667c4cf88e4
c88ab9ce 1546;;; replace.el ends here