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