*** empty log message ***
[bpt/emacs.git] / lisp / replace.el
CommitLineData
c88ab9ce
ER
1;;; replace.el --- replace commands for Emacs.
2
aeab5be0 3;; Copyright (C) 1985, 86, 87, 92, 94, 96, 1997 Free Software Foundation, Inc.
3a801d0c 4
698e1804
RS
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs is free software; you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
e5d77022 9;; the Free Software Foundation; either version 2, or (at your option)
698e1804
RS
10;; any later version.
11
12;; GNU Emacs is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
b578f267
EN
18;; along with GNU Emacs; see the file COPYING. If not, write to the
19;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20;; Boston, MA 02111-1307, USA.
698e1804 21
d9ecc911
ER
22;;; Commentary:
23
24;; This package supplies the string and regular-expression replace functions
25;; documented in the Emacs user's manual.
26
4f4b8eff 27;;; Code:
698e1804 28
9d325ebf
RS
29(defcustom case-replace t
30 "*Non-nil means query-replace should preserve case in replacements."
31 :type 'boolean
32 :group 'matching)
77176e73 33
770970cb
RS
34(defvar query-replace-history nil)
35
151270f3
RS
36(defvar query-replace-interactive nil
37 "Non-nil means `query-replace' uses the last search string.
38That becomes the \"string to replace\".")
39
bdb1c08f
RS
40(defcustom query-replace-from-history-variable 'query-replace-history
41 "History list to use for the FROM argument of query-replace commands.
42The value of this variable should be a symbol; that symbol
43is used as a variable to hold a history list for the strings
44or patterns to be replaced."
45 :group 'matching
cd32a7ba
DN
46 :type 'symbol
47 :version "20.3")
bdb1c08f
RS
48
49(defcustom query-replace-to-history-variable 'query-replace-history
50 "History list to use for the TO argument of query-replace commands.
51The value of this variable should be a symbol; that symbol
52is used as a variable to hold a history list for replacement
53strings or patterns."
54 :group 'matching
cd32a7ba
DN
55 :type 'symbol
56 :version "20.3")
bdb1c08f 57
151270f3 58(defun query-replace-read-args (string regexp-flag)
770970cb 59 (let (from to)
151270f3
RS
60 (if query-replace-interactive
61 (setq from (car (if regexp-flag regexp-search-ring search-ring)))
62 (setq from (read-from-minibuffer (format "%s: " string)
63 nil nil nil
bdb1c08f
RS
64 query-replace-from-history-variable
65 nil t)))
770970cb
RS
66 (setq to (read-from-minibuffer (format "%s %s with: " string from)
67 nil nil nil
4a8f3b3d 68 query-replace-to-history-variable from t))
770970cb
RS
69 (list from to current-prefix-arg)))
70
da44e784
RM
71(defun query-replace (from-string to-string &optional arg)
72 "Replace some occurrences of FROM-STRING with TO-STRING.
73As each match is found, the user must type a character saying
74what to do with it. For directions, type \\[help-command] at that time.
75
7ef5c431
KH
76In Transient Mark mode, if the mark is active, operate on the contents
77of the region. Otherwise, operate from point to the end of the buffer.
78
151270f3
RS
79If `query-replace-interactive' is non-nil, the last incremental search
80string is used as FROM-STRING--you don't have to specify it with the
81minibuffer.
82
d2a0ee8b
RS
83Replacement transfers the case of the old text to the new text,
84if `case-replace' and `case-fold-search'
da44e784 85are non-nil and FROM-STRING has no uppercase letters.
9b0bf2b6
RS
86\(Preserving case means that if the string matched is all caps, or capitalized,
87then its replacement is upcased or capitalized.)
88
118a01c9 89Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
81bdc14d
RS
90only matches surrounded by word boundaries.
91
92To customize possible responses, change the \"bindings\" in `query-replace-map'."
151270f3 93 (interactive (query-replace-read-args "Query replace" nil))
4d33492a 94 (perform-replace from-string to-string t nil arg))
7ef5c431 95
73fa8346 96(define-key esc-map "%" 'query-replace)
da44e784 97
da44e784
RM
98(defun query-replace-regexp (regexp to-string &optional arg)
99 "Replace some things after point matching REGEXP with TO-STRING.
100As each match is found, the user must type a character saying
101what to do with it. For directions, type \\[help-command] at that time.
102
7ef5c431
KH
103In Transient Mark mode, if the mark is active, operate on the contents
104of the region. Otherwise, operate from point to the end of the buffer.
105
151270f3
RS
106If `query-replace-interactive' is non-nil, the last incremental search
107regexp is used as REGEXP--you don't have to specify it with the
108minibuffer.
109
118a01c9 110Preserves case in each replacement if `case-replace' and `case-fold-search'
da44e784 111are non-nil and REGEXP has no uppercase letters.
118a01c9 112Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
da44e784 113only matches surrounded by word boundaries.
118a01c9
RS
114In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
115and `\\=\\N' (where N is a digit) stands for
116 whatever what matched the Nth `\\(...\\)' in REGEXP."
151270f3 117 (interactive (query-replace-read-args "Query replace regexp" t))
4d33492a 118 (perform-replace regexp to-string t t arg))
cbc127de 119(define-key esc-map [?\C-%] 'query-replace-regexp)
da44e784 120
84482eb3
RS
121(defun query-replace-regexp-eval (regexp to-expr &optional arg)
122 "Replace some things after point matching REGEXP with the result of TO-EXPR.
123As each match is found, the user must type a character saying
124what to do with it. For directions, type \\[help-command] at that time.
125
126TO-EXPR is a Lisp expression evaluated to compute each replacement. It may
127reference `replace-count' to get the number of replacements already made.
128If the result of TO-EXPR is not a string, it is converted to one using
129`prin1-to-string' with the NOESCAPE argument (which see).
130
131For convenience, when entering TO-EXPR interactively, you can use `\\&' or
132`\\0'to stand for whatever matched the whole of REGEXP, and `\\=\\N' (where
133N is a digit) stands for whatever what matched the Nth `\\(...\\)' in REGEXP.
134Use `\\#&' or `\\#N' if you want a number instead of a string.
135
136In Transient Mark mode, if the mark is active, operate on the contents
137of the region. Otherwise, operate from point to the end of the buffer.
138
139If `query-replace-interactive' is non-nil, the last incremental search
140regexp is used as REGEXP--you don't have to specify it with the
141minibuffer.
142
143Preserves case in each replacement if `case-replace' and `case-fold-search'
144are non-nil and REGEXP has no uppercase letters.
145Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
146only matches surrounded by word boundaries."
147 (interactive
148 (let (from to)
149 (if query-replace-interactive
150 (setq from (car regexp-search-ring))
151 (setq from (read-from-minibuffer "Query replace regexp: "
152 nil nil nil
153 query-replace-from-history-variable
154 nil t)))
155 (setq to (list (read-from-minibuffer
156 (format "Query replace regexp %s with eval: " from)
157 nil nil t query-replace-to-history-variable from t)))
158 ;; We make TO a list because replace-match-string-symbols requires one,
159 ;; and the user might enter a single token.
160 (replace-match-string-symbols to)
161 (list from (car to) current-prefix-arg)))
162 (perform-replace regexp (cons 'replace-eval-replacement to-expr) t t arg))
163
da44e784
RM
164(defun map-query-replace-regexp (regexp to-strings &optional arg)
165 "Replace some matches for REGEXP with various strings, in rotation.
166The second argument TO-STRINGS contains the replacement strings, separated
167by spaces. This command works like `query-replace-regexp' except
168that each successive replacement uses the next successive replacement string,
169wrapping around from the last such string to the first.
170
7ef5c431
KH
171In Transient Mark mode, if the mark is active, operate on the contents
172of the region. Otherwise, operate from point to the end of the buffer.
173
da44e784
RM
174Non-interactively, TO-STRINGS may be a list of replacement strings.
175
151270f3
RS
176If `query-replace-interactive' is non-nil, the last incremental search
177regexp is used as REGEXP--you don't have to specify it with the minibuffer.
178
da44e784
RM
179A prefix argument N says to use each replacement string N times
180before rotating to the next."
770970cb
RS
181 (interactive
182 (let (from to)
151270f3
RS
183 (setq from (if query-replace-interactive
184 (car regexp-search-ring)
185 (read-from-minibuffer "Map query replace (regexp): "
186 nil nil nil
fce31d51 187 'query-replace-history nil t)))
770970cb
RS
188 (setq to (read-from-minibuffer
189 (format "Query replace %s with (space-separated strings): "
190 from)
191 nil nil nil
4a8f3b3d 192 'query-replace-history from t))
770970cb 193 (list from to current-prefix-arg)))
da44e784
RM
194 (let (replacements)
195 (if (listp to-strings)
196 (setq replacements to-strings)
197 (while (/= (length to-strings) 0)
198 (if (string-match " " to-strings)
199 (setq replacements
200 (append replacements
201 (list (substring to-strings 0
202 (string-match " " to-strings))))
203 to-strings (substring to-strings
204 (1+ (string-match " " to-strings))))
205 (setq replacements (append replacements (list to-strings))
206 to-strings ""))))
4d33492a 207 (perform-replace regexp replacements t t nil arg)))
da44e784 208
da44e784
RM
209(defun replace-string (from-string to-string &optional delimited)
210 "Replace occurrences of FROM-STRING with TO-STRING.
211Preserve case in each match if `case-replace' and `case-fold-search'
212are non-nil and FROM-STRING has no uppercase letters.
9b0bf2b6
RS
213\(Preserving case means that if the string matched is all caps, or capitalized,
214then its replacement is upcased or capitalized.)
215
7ef5c431
KH
216In Transient Mark mode, if the mark is active, operate on the contents
217of the region. Otherwise, operate from point to the end of the buffer.
218
118a01c9 219Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
da44e784
RM
220only matches surrounded by word boundaries.
221
151270f3
RS
222If `query-replace-interactive' is non-nil, the last incremental search
223string is used as FROM-STRING--you don't have to specify it with the
224minibuffer.
225
da44e784
RM
226This function is usually the wrong thing to use in a Lisp program.
227What you probably want is a loop like this:
118a01c9
RS
228 (while (search-forward FROM-STRING nil t)
229 (replace-match TO-STRING nil t))
87532fbe
RS
230which will run faster and will not set the mark or print anything.
231\(You may need a more complex loop if FROM-STRING can match the null string
232and TO-STRING is also null.)"
151270f3 233 (interactive (query-replace-read-args "Replace string" nil))
4d33492a 234 (perform-replace from-string to-string nil nil delimited))
da44e784 235
da44e784
RM
236(defun replace-regexp (regexp to-string &optional delimited)
237 "Replace things after point matching REGEXP with TO-STRING.
118a01c9 238Preserve case in each match if `case-replace' and `case-fold-search'
da44e784 239are non-nil and REGEXP has no uppercase letters.
118a01c9 240Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
da44e784 241only matches surrounded by word boundaries.
118a01c9
RS
242In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
243and `\\=\\N' (where N is a digit) stands for
880f22a1 244 whatever what matched the Nth `\\(...\\)' in REGEXP.
da44e784 245
7ef5c431
KH
246In Transient Mark mode, if the mark is active, operate on the contents
247of the region. Otherwise, operate from point to the end of the buffer.
248
151270f3
RS
249If `query-replace-interactive' is non-nil, the last incremental search
250regexp is used as REGEXP--you don't have to specify it with the minibuffer.
251
da44e784
RM
252This function is usually the wrong thing to use in a Lisp program.
253What you probably want is a loop like this:
254 (while (re-search-forward REGEXP nil t)
118a01c9 255 (replace-match TO-STRING nil nil))
da44e784 256which will run faster and will not set the mark or print anything."
151270f3 257 (interactive (query-replace-read-args "Replace regexp" t))
4d33492a 258 (perform-replace regexp to-string nil t delimited))
4c53bd2b
RS
259\f
260(defvar regexp-history nil
261 "History list for some commands that read regular expressions.")
da44e784 262
31e1d920 263(defalias 'delete-non-matching-lines 'keep-lines)
698e1804
RS
264(defun keep-lines (regexp)
265 "Delete all lines except those containing matches for REGEXP.
266A match split across lines preserves all the lines it lies in.
d2a0ee8b
RS
267Applies to all lines after point.
268
269If REGEXP contains upper case characters (excluding those preceded by `\\'),
270the matching is case-sensitive."
4c53bd2b 271 (interactive (list (read-from-minibuffer
72f21cdf 272 "Keep lines (containing match for regexp): "
fce31d51 273 nil nil nil 'regexp-history nil t)))
698e1804
RS
274 (save-excursion
275 (or (bolp) (forward-line 1))
d2a0ee8b
RS
276 (let ((start (point))
277 (case-fold-search (and case-fold-search
278 (isearch-no-upper-case-p regexp t))))
698e1804
RS
279 (while (not (eobp))
280 ;; Start is first char not preserved by previous match.
281 (if (not (re-search-forward regexp nil 'move))
282 (delete-region start (point-max))
283 (let ((end (save-excursion (goto-char (match-beginning 0))
284 (beginning-of-line)
285 (point))))
286 ;; Now end is first char preserved by the new match.
287 (if (< start end)
288 (delete-region start end))))
289 (setq start (save-excursion (forward-line 1)
290 (point)))
291 ;; If the match was empty, avoid matching again at same place.
292 (and (not (eobp)) (= (match-beginning 0) (match-end 0))
293 (forward-char 1))))))
294
31e1d920 295(defalias 'delete-matching-lines 'flush-lines)
698e1804
RS
296(defun flush-lines (regexp)
297 "Delete lines containing matches for REGEXP.
298If a match is split across lines, all the lines it lies in are deleted.
d2a0ee8b
RS
299Applies to lines after point.
300
301If REGEXP contains upper case characters (excluding those preceded by `\\'),
302the matching is case-sensitive."
4c53bd2b 303 (interactive (list (read-from-minibuffer
72f21cdf 304 "Flush lines (containing match for regexp): "
fce31d51 305 nil nil nil 'regexp-history nil t)))
d2a0ee8b
RS
306 (let ((case-fold-search (and case-fold-search
307 (isearch-no-upper-case-p regexp t))))
308 (save-excursion
309 (while (and (not (eobp))
310 (re-search-forward regexp nil t))
311 (delete-region (save-excursion (goto-char (match-beginning 0))
312 (beginning-of-line)
313 (point))
314 (progn (forward-line 1) (point)))))))
698e1804 315
31e1d920 316(defalias 'count-matches 'how-many)
698e1804 317(defun how-many (regexp)
d2a0ee8b
RS
318 "Print number of matches for REGEXP following point.
319
320If REGEXP contains upper case characters (excluding those preceded by `\\'),
321the matching is case-sensitive."
b7f096ee
RS
322 (interactive (list (read-from-minibuffer
323 "How many matches for (regexp): "
324 nil nil nil 'regexp-history nil t)))
d2a0ee8b
RS
325 (let ((count 0) opoint
326 (case-fold-search (and case-fold-search
327 (isearch-no-upper-case-p regexp t))))
698e1804
RS
328 (save-excursion
329 (while (and (not (eobp))
330 (progn (setq opoint (point))
331 (re-search-forward regexp nil t)))
332 (if (= opoint (point))
333 (forward-char 1)
334 (setq count (1+ count))))
335 (message "%d occurrences" count))))
4c53bd2b 336\f
698e1804
RS
337(defvar occur-mode-map ())
338(if occur-mode-map
339 ()
340 (setq occur-mode-map (make-sparse-keymap))
78bead73 341 (define-key occur-mode-map [mouse-2] 'occur-mode-mouse-goto)
0081c8a1 342 (define-key occur-mode-map "\C-c\C-c" 'occur-mode-goto-occurrence)
a41284da 343 (define-key occur-mode-map "\C-m" 'occur-mode-goto-occurrence)
8d15583f
RS
344 (define-key occur-mode-map "\M-n" 'occur-next)
345 (define-key occur-mode-map "\M-p" 'occur-prev)
a41284da 346 (define-key occur-mode-map "g" 'revert-buffer))
698e1804 347
e09d4033
RS
348
349(defvar occur-buffer nil
350 "Name of buffer for last occur.")
351
352
353(defvar occur-nlines nil
354 "Number of lines of context to show around matching line.")
355
a41284da
RS
356(defvar occur-command-arguments nil
357 "Arguments that were given to `occur' when it made this buffer.")
698e1804 358
de3c9b09
RS
359(put 'occur-mode 'mode-class 'special)
360
698e1804
RS
361(defun occur-mode ()
362 "Major mode for output from \\[occur].
0081c8a1
RS
363\\<occur-mode-map>Move point to one of the items in this buffer, then use
364\\[occur-mode-goto-occurrence] to go to the occurrence that the item refers to.
365Alternatively, click \\[occur-mode-mouse-goto] on an item to go to it.
366
698e1804
RS
367\\{occur-mode-map}"
368 (kill-all-local-variables)
369 (use-local-map occur-mode-map)
370 (setq major-mode 'occur-mode)
371 (setq mode-name "Occur")
a41284da
RS
372 (make-local-variable 'revert-buffer-function)
373 (setq revert-buffer-function 'occur-revert-function)
698e1804
RS
374 (make-local-variable 'occur-buffer)
375 (make-local-variable 'occur-nlines)
a41284da 376 (make-local-variable 'occur-command-arguments)
4baf5620 377 (run-hooks 'occur-mode-hook))
698e1804 378
a41284da
RS
379;; Handle revert-buffer for *Occur* buffers.
380(defun occur-revert-function (ignore1 ignore2)
381 (let ((args occur-command-arguments ))
382 (save-excursion
383 (set-buffer occur-buffer)
384 (apply 'occur args))))
385
78bead73
RS
386(defun occur-mode-mouse-goto (event)
387 "In Occur mode, go to the occurrence whose line you click on."
388 (interactive "e")
389 (let (buffer pos)
390 (save-excursion
391 (set-buffer (window-buffer (posn-window (event-end event))))
392 (save-excursion
393 (goto-char (posn-point (event-end event)))
394 (setq pos (occur-mode-find-occurrence))
395 (setq buffer occur-buffer)))
396 (pop-to-buffer buffer)
397 (goto-char (marker-position pos))))
398
399(defun occur-mode-find-occurrence ()
698e1804
RS
400 (if (or (null occur-buffer)
401 (null (buffer-name occur-buffer)))
402 (progn
8d15583f 403 (setq occur-buffer nil)
698e1804 404 (error "Buffer in which occurrences were found is deleted")))
8d15583f
RS
405 (let ((pos (get-text-property (point) 'occur)))
406 (if (null pos)
407 (error "No occurrence on this line")
408 pos)))
78bead73
RS
409
410(defun occur-mode-goto-occurrence ()
411 "Go to the occurrence the current line describes."
412 (interactive)
413 (let ((pos (occur-mode-find-occurrence)))
698e1804 414 (pop-to-buffer occur-buffer)
121e2227 415 (goto-char (marker-position pos))))
8d15583f
RS
416
417(defun occur-next (&optional n)
418 "Move to the Nth (default 1) next match in the *Occur* buffer."
419 (interactive "p")
420 (if (not n) (setq n 1))
421 (let ((r))
422 (while (> n 0)
423 (if (get-text-property (point) 'occur-point)
424 (forward-char 1))
425 (setq r (next-single-property-change (point) 'occur-point))
426 (if r
427 (goto-char r)
428 (error "no more matches"))
429 (setq n (1- n)))))
430
431
432
433(defun occur-prev (&optional n)
434 "Move to the Nth (default 1) previous match in the *Occur* buffer."
435 (interactive "p")
436 (if (not n) (setq n 1))
437 (let ((r))
438 (while (> n 0)
439
440 (setq r (get-text-property (point) 'occur-point))
441 (if r (forward-char -1))
442
443 (setq r (previous-single-property-change (point) 'occur-point))
444 (if r
445 (goto-char (- r 1))
446 (error "no earlier matches"))
447
448 (setq n (1- n)))))
4c53bd2b 449\f
9d325ebf 450(defcustom list-matching-lines-default-context-lines 0
da44e784 451 "*Default number of context lines to include around a `list-matching-lines'
698e1804 452match. A negative number means to include that many lines before the match.
9d325ebf
RS
453A positive number means to include that many lines both before and after."
454 :type 'integer
455 :group 'matching)
698e1804 456
31e1d920 457(defalias 'list-matching-lines 'occur)
698e1804 458
c9daced0
RS
459(defvar list-matching-lines-face 'bold
460 "*Face used by M-x list-matching-lines to show the text that matches.
461If the value is nil, don't highlight the matching portions specially.")
462
698e1804 463(defun occur (regexp &optional nlines)
99976f85 464 "Show all lines in the current buffer containing a match for REGEXP.
da44e784
RM
465
466If a match spreads across multiple lines, all those lines are shown.
698e1804 467
da44e784
RM
468Each line is displayed with NLINES lines before and after, or -NLINES
469before if NLINES is negative.
470NLINES defaults to `list-matching-lines-default-context-lines'.
698e1804
RS
471Interactively it is the prefix arg.
472
4c53bd2b 473The lines are shown in a buffer named `*Occur*'.
698e1804 474It serves as a menu to find any of the occurrences in this buffer.
de3c9b09 475\\<occur-mode-map>\\[describe-mode] in that buffer will explain how.
9483d601 476
de3c9b09
RS
477If REGEXP contains upper case characters (excluding those preceded by `\\'),
478the matching is case-sensitive."
a5dfed3e
RS
479 (interactive
480 (list (let* ((default (car regexp-history))
481 (input
482 (read-from-minibuffer
483 (if default
484 (format "List lines matching regexp (default `%s'): "
485 default)
486 "List lines matching regexp: ")
aeab5be0 487 nil nil nil 'regexp-history default t)))
4a8f3b3d
RS
488 (and (equal input "") default
489 (setq input default))
aeab5be0 490 input)
a5dfed3e
RS
491 current-prefix-arg))
492 (let ((nlines (if nlines
493 (prefix-numeric-value nlines)
494 list-matching-lines-default-context-lines))
495 (first t)
e09d4033 496 ;;flag to prevent printing separator for first match
8d15583f 497 (occur-num-matches 0)
698e1804 498 (buffer (current-buffer))
bdd610b2 499 (dir default-directory)
698e1804 500 (linenum 1)
e09d4033
RS
501 (prevpos
502 ;;position of most recent match
503 (point-min))
9483d601
RS
504 (case-fold-search (and case-fold-search
505 (isearch-no-upper-case-p regexp t)))
e09d4033
RS
506 (final-context-start
507 ;; Marker to the start of context immediately following
508 ;; the matched text in *Occur*.
509 (make-marker)))
99976f85
RS
510;;; (save-excursion
511;;; (beginning-of-line)
512;;; (setq linenum (1+ (count-lines (point-min) (point))))
513;;; (setq prevpos (point)))
016c214f
RS
514 (save-excursion
515 (goto-char (point-min))
516 ;; Check first whether there are any matches at all.
517 (if (not (re-search-forward regexp nil t))
518 (message "No matches for `%s'" regexp)
519 ;; Back up, so the search loop below will find the first match.
520 (goto-char (match-beginning 0))
521 (with-output-to-temp-buffer "*Occur*"
522 (save-excursion
523 (set-buffer standard-output)
524 (setq default-directory dir)
525 ;; We will insert the number of lines, and "lines", later.
526 (insert " matching ")
527 (let ((print-escape-newlines t))
528 (prin1 regexp))
529 (insert " in buffer " (buffer-name buffer) ?. ?\n)
530 (occur-mode)
531 (setq occur-buffer buffer)
532 (setq occur-nlines nlines)
a41284da
RS
533 (setq occur-command-arguments
534 (list regexp nlines)))
016c214f 535 (if (eq buffer standard-output)
91c6bdc0 536 (goto-char (point-max)))
016c214f
RS
537 (save-excursion
538 ;; Find next match, but give up if prev match was at end of buffer.
539 (while (and (not (= prevpos (point-max)))
540 (re-search-forward regexp nil t))
541 (goto-char (match-beginning 0))
542 (beginning-of-line)
543 (save-match-data
544 (setq linenum (+ linenum (count-lines prevpos (point)))))
545 (setq prevpos (point))
546 (goto-char (match-end 0))
e09d4033
RS
547 (let* ((start
548 ;;start point of text in source buffer to be put
549 ;;into *Occur*
550 (save-excursion
016c214f 551 (goto-char (match-beginning 0))
e09d4033
RS
552 (forward-line (if (< nlines 0)
553 nlines
554 (- nlines)))
016c214f 555 (point)))
e09d4033
RS
556 (end
557 ;; end point of text in source buffer to be put
558 ;; into *Occur*
559 (save-excursion
560 (goto-char (match-end 0))
561 (if (> nlines 0)
562 (forward-line (1+ nlines))
563 (forward-line 1))
564 (point)))
565 (match-beg
566 ;; Amount of context before matching text
567 (- (match-beginning 0) start))
568 (match-len
569 ;; Length of matching text
570 (- (match-end 0) (match-beginning 0)))
016c214f
RS
571 (tag (format "%5d" linenum))
572 (empty (make-string (length tag) ?\ ))
e09d4033 573 tem
0f0a7f7c 574 insertion-start
e09d4033
RS
575 ;; Number of lines of context to show for current match.
576 occur-marker
577 ;; Marker pointing to end of match in source buffer.
578 (text-beg
579 ;; Marker pointing to start of text for one
580 ;; match in *Occur*.
581 (make-marker))
582 (text-end
583 ;; Marker pointing to end of text for one match
584 ;; in *Occur*.
585 (make-marker))
8d15583f 586 )
016c214f 587 (save-excursion
8d15583f
RS
588 (setq occur-marker (make-marker))
589 (set-marker occur-marker (point))
016c214f 590 (set-buffer standard-output)
8d15583f 591 (setq occur-num-matches (1+ occur-num-matches))
016c214f
RS
592 (or first (zerop nlines)
593 (insert "--------\n"))
594 (setq first nil)
e09d4033
RS
595
596 ;; Insert matching text including context lines from
597 ;; source buffer into *Occur*
8d15583f 598 (set-marker text-beg (point))
0f0a7f7c 599 (setq insertion-start (point))
016c214f 600 (insert-buffer-substring buffer start end)
0f0a7f7c
KH
601 (or (and (/= (+ start match-beg) end)
602 (with-current-buffer buffer
603 (eq (char-before end) ?\n)))
604 (insert "\n"))
605 (set-marker final-context-start
606 (+ (- (point) (- end (match-end 0)))
607 (if (save-excursion
608 (set-buffer buffer)
609 (save-excursion
610 (goto-char (match-end 0))
611 (end-of-line)
612 (bolp)))
613 1 0)))
8d15583f 614 (set-marker text-end (point))
e09d4033
RS
615
616 ;; Highlight text that was matched.
8d15583f
RS
617 (if list-matching-lines-face
618 (put-text-property
619 (+ (marker-position text-beg) match-beg)
620 (+ (marker-position text-beg) match-beg match-len)
621 'face list-matching-lines-face))
622
e09d4033
RS
623 ;; `occur-point' property is used by occur-next and
624 ;; occur-prev to move between matching lines.
8d15583f
RS
625 (put-text-property
626 (+ (marker-position text-beg) match-beg match-len)
627 (+ (marker-position text-beg) match-beg match-len 1)
628 'occur-point t)
e09d4033
RS
629
630 ;; Now go back to the start of the matching text
631 ;; adding the space and colon to the start of each line.
0f0a7f7c 632 (goto-char insertion-start)
e09d4033 633 ;; Insert space and colon for lines of context before match.
8d15583f
RS
634 (setq tem (if (< linenum nlines)
635 (- nlines linenum)
636 nlines))
016c214f
RS
637 (while (> tem 0)
638 (insert empty ?:)
639 (forward-line 1)
640 (setq tem (1- tem)))
e09d4033
RS
641
642 ;; Insert line number and colon for the lines of
643 ;; matching text.
644 (let ((this-linenum linenum))
016c214f
RS
645 (while (< (point) final-context-start)
646 (if (null tag)
647 (setq tag (format "%5d" this-linenum)))
648 (insert tag ?:)
016c214f
RS
649 (forward-line 1)
650 (setq tag nil)
651 (setq this-linenum (1+ this-linenum)))
0f0a7f7c 652 (while (and (not (eobp)) (<= (point) final-context-start))
016c214f
RS
653 (insert empty ?:)
654 (forward-line 1)
655 (setq this-linenum (1+ this-linenum))))
e09d4033
RS
656
657 ;; Insert space and colon for lines of context after match.
8d15583f 658 (while (and (< (point) (point-max)) (< tem nlines))
016c214f
RS
659 (insert empty ?:)
660 (forward-line 1)
661 (setq tem (1+ tem)))
8d15583f
RS
662
663 ;; Add text properties. The `occur' prop is used to
664 ;; store the marker of the matching text in the
665 ;; source buffer.
666 (put-text-property (marker-position text-beg)
667 (- (marker-position text-end) 1)
668 'mouse-face 'highlight)
669 (put-text-property (marker-position text-beg)
e09d4033 670 (marker-position text-end)
8d15583f 671 'occur occur-marker)
016c214f
RS
672 (goto-char (point-max)))
673 (forward-line 1)))
674 (set-buffer standard-output)
e09d4033
RS
675 ;; Go back to top of *Occur* and finish off by printing the
676 ;; number of matching lines.
016c214f 677 (goto-char (point-min))
65b4665c 678 (let ((message-string
8d15583f 679 (if (= occur-num-matches 1)
65b4665c 680 "1 line"
8d15583f 681 (format "%d lines" occur-num-matches))))
65b4665c
RS
682 (insert message-string)
683 (if (interactive-p)
5ddf4bda
KH
684 (message "%s matched" message-string)))
685 (setq buffer-read-only t)))))))
698e1804 686\f
81bdc14d
RS
687;; It would be nice to use \\[...], but there is no reasonable way
688;; to make that display both SPC and Y.
698e1804
RS
689(defconst query-replace-help
690 "Type Space or `y' to replace one match, Delete or `n' to skip to next,
be44f62c 691RET or `q' to exit, Period to replace one match and exit,
698e1804
RS
692Comma to replace but not move point immediately,
693C-r to enter recursive edit (\\[exit-recursive-edit] to get out again),
694C-w to delete match and recursive edit,
695C-l to clear the screen, redisplay, and offer same replacement again,
696! to replace all remaining matches with no more questions,
697^ to move point back to previous match."
698 "Help message while in query-replace")
699
81bdc14d
RS
700(defvar query-replace-map (make-sparse-keymap)
701 "Keymap that defines the responses to questions in `query-replace'.
702The \"bindings\" in this map are not commands; they are answers.
703The valid answers include `act', `skip', `act-and-show',
704`exit', `act-and-exit', `edit', `delete-and-edit', `recenter',
d9121bc0 705`automatic', `backup', `exit-prefix', and `help'.")
81bdc14d
RS
706
707(define-key query-replace-map " " 'act)
708(define-key query-replace-map "\d" 'skip)
709(define-key query-replace-map [delete] 'skip)
9275e5e3 710(define-key query-replace-map [backspace] 'skip)
81bdc14d
RS
711(define-key query-replace-map "y" 'act)
712(define-key query-replace-map "n" 'skip)
633a305a
RS
713(define-key query-replace-map "Y" 'act)
714(define-key query-replace-map "N" 'skip)
81bdc14d 715(define-key query-replace-map "," 'act-and-show)
81bdc14d 716(define-key query-replace-map "q" 'exit)
919592c0 717(define-key query-replace-map "\r" 'exit)
384c7da4 718(define-key query-replace-map [return] 'exit)
81bdc14d
RS
719(define-key query-replace-map "." 'act-and-exit)
720(define-key query-replace-map "\C-r" 'edit)
721(define-key query-replace-map "\C-w" 'delete-and-edit)
722(define-key query-replace-map "\C-l" 'recenter)
723(define-key query-replace-map "!" 'automatic)
724(define-key query-replace-map "^" 'backup)
725(define-key query-replace-map "\C-h" 'help)
e731045a
KH
726(define-key query-replace-map [f1] 'help)
727(define-key query-replace-map [help] 'help)
81bdc14d 728(define-key query-replace-map "?" 'help)
bc6312e1
RS
729(define-key query-replace-map "\C-g" 'quit)
730(define-key query-replace-map "\C-]" 'quit)
d9121bc0
RS
731(define-key query-replace-map "\e" 'exit-prefix)
732(define-key query-replace-map [escape] 'exit-prefix)
81bdc14d 733
84482eb3
RS
734(defun replace-match-string-symbols (n)
735 ;; Process a list (and any sub-lists), expanding certain symbols:
736 ;; Symbol Expands To
737 ;; N (match-string N) (where N is a string of digits)
738 ;; #N (string-to-number (match-string N))
739 ;; & (match-string 0)
740 ;; #& (string-to-number (match-string 0))
741 ;;
742 ;; Note that these symbols must be preceeded by a backslash in order to
743 ;; type them.
744 (while n
745 (cond
746 ((consp (car n))
747 (replace-match-string-symbols (car n))) ;Process sub-list
748 ((symbolp (car n))
749 (let ((name (symbol-name (car n))))
750 (cond
751 ((string-match "^[0-9]+$" name)
752 (setcar n (list 'match-string (string-to-number name))))
753 ((string-match "^#[0-9]+$" name)
754 (setcar n (list 'string-to-number
755 (list 'match-string
756 (string-to-number (substring name 1))))))
757 ((string= "&" name)
758 (setcar n '(match-string 0)))
759 ((string= "#&" name)
760 (setcar n '(string-to-number (match-string 0))))))))
761 (setq n (cdr n))))
762
763(defun replace-eval-replacement (expression replace-count)
764 (let ((replacement (eval expression)))
765 (if (stringp replacement)
766 replacement
767 (prin1-to-string replacement t))))
768
769(defun replace-loop-through-replacements (data replace-count)
770 ;; DATA is a vector contaning the following values:
771 ;; 0 next-rotate-count
772 ;; 1 repeat-count
773 ;; 2 next-replacement
774 ;; 3 replacements
775 (if (= (aref data 0) replace-count)
776 (progn
777 (aset data 0 (+ replace-count (aref data 1)))
778 (let ((next (cdr (aref data 2))))
779 (aset data 2 (if (consp next) next (aref data 3))))))
780 (car (aref data 2)))
781
698e1804
RS
782(defun perform-replace (from-string replacements
783 query-flag regexp-flag delimited-flag
81bdc14d 784 &optional repeat-count map)
698e1804
RS
785 "Subroutine of `query-replace'. Its complexity handles interactive queries.
786Don't use this in your own program unless you want to query and set the mark
787just as `query-replace' does. Instead, write a simple loop like this:
788 (while (re-search-forward \"foo[ \t]+bar\" nil t)
789 (replace-match \"foobar\" nil nil))
e782e9f2 790which will run faster and probably do exactly what you want."
81bdc14d 791 (or map (setq map query-replace-map))
1c1dadab
RS
792 (and query-flag minibuffer-auto-raise
793 (raise-frame (window-frame (minibuffer-window))))
698e1804
RS
794 (let ((nocasify (not (and case-fold-search case-replace
795 (string-equal from-string
796 (downcase from-string)))))
5a78b471
KH
797 (case-fold-search (and case-fold-search
798 (string-equal from-string
799 (downcase from-string))))
698e1804
RS
800 (literal (not regexp-flag))
801 (search-function (if regexp-flag 're-search-forward 'search-forward))
802 (search-string from-string)
e5d77022 803 (real-match-data nil) ; the match data for the current match
698e1804 804 (next-replacement nil)
698e1804
RS
805 (keep-going t)
806 (stack nil)
698e1804 807 (replace-count 0)
5632eb27
PE
808 (nonempty-match nil)
809
7ef5c431
KH
810 ;; If non-nil, it is marker saying where in the buffer to stop.
811 (limit nil)
812
5632eb27
PE
813 ;; Data for the next match. If a cons, it has the same format as
814 ;; (match-data); otherwise it is t if a match is possible at point.
ae4eb03c 815 (match-again t)
5632eb27 816
02d95a27
RS
817 (message
818 (if query-flag
819 (substitute-command-keys
820 "Query replacing %s with %s: (\\<query-replace-map>\\[help] for help) "))))
7ef5c431
KH
821
822 ;; If region is active, in Transient Mark mode, operate on region.
823 (if (and transient-mark-mode mark-active)
824 (progn
825 (setq limit (copy-marker (region-end)))
826 (goto-char (region-beginning))
827 (deactivate-mark)))
84482eb3
RS
828
829 ;; REPLACEMENTS is either a string, a list of strings, or a cons cell
830 ;; containing a function and its first argument. The function is
831 ;; called to generate each replacement like this:
832 ;; (funcall (car replacements) (cdr replacements) replace-count)
833 ;; It must return a string.
834 (cond
835 ((stringp replacements)
836 (setq next-replacement replacements
837 replacements nil))
838 ((stringp (car replacements)) ; If it isn't a string, it must be a cons
839 (or repeat-count (setq repeat-count 1))
840 (setq replacements (cons 'replace-loop-through-replacements
841 (vector repeat-count repeat-count
842 replacements replacements)))))
843
698e1804
RS
844 (if delimited-flag
845 (setq search-function 're-search-forward
846 search-string (concat "\\b"
847 (if regexp-flag from-string
848 (regexp-quote from-string))
849 "\\b")))
850 (push-mark)
851 (undo-boundary)
e782e9f2
RS
852 (unwind-protect
853 ;; Loop finding occurrences that perhaps should be replaced.
854 (while (and keep-going
855 (not (eobp))
5632eb27
PE
856 ;; Use the next match if it is already known;
857 ;; otherwise, search for a match after moving forward
858 ;; one char if progress is required.
859 (setq real-match-data
860 (if (consp match-again)
861 (progn (goto-char (nth 1 match-again))
862 match-again)
863 (and (or match-again
864 (progn
865 (forward-char 1)
866 (not (eobp))))
7ef5c431 867 (funcall search-function search-string limit t)
5632eb27
PE
868 ;; For speed, use only integers and
869 ;; reuse the list used last time.
870 (match-data t real-match-data)))))
871
872 ;; Record whether the match is nonempty, to avoid an infinite loop
873 ;; repeatedly matching the same empty string.
874 (setq nonempty-match
875 (/= (nth 0 real-match-data) (nth 1 real-match-data)))
876
877 ;; If the match is empty, record that the next one can't be adjacent.
878 ;; Otherwise, if matching a regular expression, do the next
879 ;; match now, since the replacement for this match may
880 ;; affect whether the next match is adjacent to this one.
881 (setq match-again
882 (and nonempty-match
883 (or (not regexp-flag)
884 (and (looking-at search-string)
937ab68f 885 (match-data)))))
5632eb27 886
84482eb3
RS
887 ;; Calculate the replacement string, if necessary.
888 (when replacements
889 (set-match-data real-match-data)
890 (setq next-replacement
891 (funcall (car replacements) (cdr replacements)
892 replace-count)))
e782e9f2
RS
893 (if (not query-flag)
894 (progn
ef4aaf5f 895 (set-match-data real-match-data)
e782e9f2
RS
896 (replace-match next-replacement nocasify literal)
897 (setq replace-count (1+ replace-count)))
898 (undo-boundary)
899 (let (done replaced key def)
900 ;; Loop reading commands until one of them sets done,
901 ;; which means it has finished handling this occurrence.
902 (while (not done)
ef4aaf5f 903 (set-match-data real-match-data)
e782e9f2 904 (replace-highlight (match-beginning 0) (match-end 0))
c006b215
KH
905 ;; Bind message-log-max so we don't fill up the message log
906 ;; with a bunch of identical messages.
907 (let ((message-log-max nil))
908 (message message from-string next-replacement))
e782e9f2 909 (setq key (read-event))
f5e52cd3
RS
910 ;; Necessary in case something happens during read-event
911 ;; that clobbers the match data.
ef4aaf5f 912 (set-match-data real-match-data)
e782e9f2
RS
913 (setq key (vector key))
914 (setq def (lookup-key map key))
915 ;; Restore the match data while we process the command.
e782e9f2
RS
916 (cond ((eq def 'help)
917 (with-output-to-temp-buffer "*Help*"
918 (princ
919 (concat "Query replacing "
920 (if regexp-flag "regexp " "")
921 from-string " with "
922 next-replacement ".\n\n"
923 (substitute-command-keys
b905ac33
KH
924 query-replace-help)))
925 (save-excursion
926 (set-buffer standard-output)
927 (help-mode))))
e782e9f2
RS
928 ((eq def 'exit)
929 (setq keep-going nil)
930 (setq done t))
931 ((eq def 'backup)
237e6ab0
KH
932 (if stack
933 (let ((elt (car stack)))
934 (goto-char (car elt))
935 (setq replaced (eq t (cdr elt)))
936 (or replaced
ef4aaf5f 937 (set-match-data (cdr elt)))
237e6ab0
KH
938 (setq stack (cdr stack)))
939 (message "No previous match")
940 (ding 'no-terminate)
941 (sit-for 1)))
e782e9f2
RS
942 ((eq def 'act)
943 (or replaced
3043b0b4
RS
944 (progn
945 (replace-match next-replacement nocasify literal)
946 (setq replace-count (1+ replace-count))))
e782e9f2
RS
947 (setq done t replaced t))
948 ((eq def 'act-and-exit)
949 (or replaced
3043b0b4
RS
950 (progn
951 (replace-match next-replacement nocasify literal)
952 (setq replace-count (1+ replace-count))))
e782e9f2
RS
953 (setq keep-going nil)
954 (setq done t replaced t))
955 ((eq def 'act-and-show)
956 (if (not replaced)
957 (progn
958 (replace-match next-replacement nocasify literal)
3043b0b4 959 (setq replace-count (1+ replace-count))
e782e9f2
RS
960 (setq replaced t))))
961 ((eq def 'automatic)
962 (or replaced
3043b0b4
RS
963 (progn
964 (replace-match next-replacement nocasify literal)
965 (setq replace-count (1+ replace-count))))
e782e9f2
RS
966 (setq done t query-flag nil replaced t))
967 ((eq def 'skip)
968 (setq done t))
969 ((eq def 'recenter)
970 (recenter nil))
971 ((eq def 'edit)
596235d6
KH
972 (let ((opos (point-marker)))
973 (goto-char (match-beginning 0))
974 (save-excursion
975 (funcall search-function search-string limit t)
976 (setq real-match-data (match-data)))
977 (save-excursion (recursive-edit))
978 (goto-char opos))
a9c4c78a 979 (set-match-data real-match-data)
ae4eb03c
RS
980 ;; Before we make the replacement,
981 ;; decide whether the search string
982 ;; can match again just after this match.
5632eb27
PE
983 (if (and regexp-flag nonempty-match)
984 (setq match-again (and (looking-at search-string)
937ab68f 985 (match-data)))))
e782e9f2
RS
986 ((eq def 'delete-and-edit)
987 (delete-region (match-beginning 0) (match-end 0))
ef4aaf5f 988 (set-match-data
e782e9f2
RS
989 (prog1 (match-data)
990 (save-excursion (recursive-edit))))
991 (setq replaced t))
d9121bc0
RS
992 ;; Note: we do not need to treat `exit-prefix'
993 ;; specially here, since we reread
994 ;; any unrecognized character.
e782e9f2 995 (t
d9121bc0 996 (setq this-command 'mode-exited)
e782e9f2
RS
997 (setq keep-going nil)
998 (setq unread-command-events
999 (append (listify-key-sequence key)
1000 unread-command-events))
1001 (setq done t))))
1002 ;; Record previous position for ^ when we move on.
1003 ;; Change markers to numbers in the match data
1004 ;; since lots of markers slow down editing.
1005 (setq stack
1006 (cons (cons (point)
141aa68c 1007 (or replaced (match-data t)))
5632eb27 1008 stack)))))
e782e9f2 1009 (replace-dehighlight))
4d33492a
RS
1010 (or unread-command-events
1011 (message "Replaced %d occurrence%s"
1012 replace-count
1013 (if (= replace-count 1) "" "s")))
1014 (and keep-going stack)))
698e1804 1015
95807e68 1016(defcustom query-replace-highlight t
9d325ebf
RS
1017 "*Non-nil means to highlight words during query replacement."
1018 :type 'boolean
1019 :group 'matching)
e782e9f2
RS
1020
1021(defvar replace-overlay nil)
1022
1023(defun replace-dehighlight ()
1024 (and replace-overlay
1025 (progn
1026 (delete-overlay replace-overlay)
1027 (setq replace-overlay nil))))
1028
1029(defun replace-highlight (start end)
1030 (and query-replace-highlight
1031 (progn
1032 (or replace-overlay
1033 (progn
1034 (setq replace-overlay (make-overlay start end))
1035 (overlay-put replace-overlay 'face
1036 (if (internal-find-face 'query-replace)
1037 'query-replace 'region))))
1038 (move-overlay replace-overlay start end (current-buffer)))))
1039
c88ab9ce 1040;;; replace.el ends here