Move lisp/emacs-lisp/authors.el to admin/
[bpt/emacs.git] / lisp / replace.el
CommitLineData
60370d40 1;;; replace.el --- replace commands for Emacs
c88ab9ce 2
ba318903
PE
3;; Copyright (C) 1985-1987, 1992, 1994, 1996-1997, 2000-2014 Free
4;; Software Foundation, Inc.
3a801d0c 5
34dc21db 6;; Maintainer: emacs-devel@gnu.org
bd78fa1d 7;; Package: emacs
30764597 8
698e1804
RS
9;; This file is part of GNU Emacs.
10
eb3fa2cf 11;; GNU Emacs is free software: you can redistribute it and/or modify
698e1804 12;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
698e1804
RS
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
eb3fa2cf 22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
698e1804 23
d9ecc911
ER
24;;; Commentary:
25
26;; This package supplies the string and regular-expression replace functions
27;; documented in the Emacs user's manual.
28
4f4b8eff 29;;; Code:
698e1804 30
9d325ebf 31(defcustom case-replace t
9201cc28 32 "Non-nil means `query-replace' should preserve case in replacements."
9d325ebf
RS
33 :type 'boolean
34 :group 'matching)
77176e73 35
826b3235
JL
36(defcustom replace-lax-whitespace nil
37 "Non-nil means `query-replace' matches a sequence of whitespace chars.
3231d532
JL
38When you enter a space or spaces in the strings to be replaced,
39it will match any sequence matched by the regexp `search-whitespace-regexp'."
40 :type 'boolean
41 :group 'matching
42 :version "24.3")
43
44(defcustom replace-regexp-lax-whitespace nil
45 "Non-nil means `query-replace-regexp' matches a sequence of whitespace chars.
46When you enter a space or spaces in the regexps to be replaced,
826b3235
JL
47it will match any sequence matched by the regexp `search-whitespace-regexp'."
48 :type 'boolean
49 :group 'matching
50 :version "24.3")
51
84d0a5f8
GM
52(defvar query-replace-history nil
53 "Default history list for query-replace commands.
54See `query-replace-from-history-variable' and
55`query-replace-to-history-variable'.")
770970cb 56
6b59b130
CY
57(defvar query-replace-defaults nil
58 "Default values of FROM-STRING and TO-STRING for `query-replace'.
59This is a cons cell (FROM-STRING . TO-STRING), or nil if there is
60no default value.")
61
5291cbca 62(defvar query-replace-interactive nil
151270f3 63 "Non-nil means `query-replace' uses the last search string.
5291cbca 64That becomes the \"string to replace\".")
0e2ae83d
JL
65(make-obsolete-variable 'query-replace-interactive
66 "use `M-n' to pull the last incremental search string
67to the minibuffer that reads the string to replace, or invoke replacements
68from Isearch by using a key sequence like `C-s C-s M-%'." "24.3")
151270f3 69
bdb1c08f 70(defcustom query-replace-from-history-variable 'query-replace-history
f54701d1 71 "History list to use for the FROM argument of `query-replace' commands.
bdb1c08f
RS
72The value of this variable should be a symbol; that symbol
73is used as a variable to hold a history list for the strings
74or patterns to be replaced."
75 :group 'matching
cd32a7ba
DN
76 :type 'symbol
77 :version "20.3")
bdb1c08f
RS
78
79(defcustom query-replace-to-history-variable 'query-replace-history
f54701d1 80 "History list to use for the TO argument of `query-replace' commands.
bdb1c08f
RS
81The value of this variable should be a symbol; that symbol
82is used as a variable to hold a history list for replacement
83strings or patterns."
84 :group 'matching
cd32a7ba
DN
85 :type 'symbol
86 :version "20.3")
bdb1c08f 87
1c4fe319 88(defcustom query-replace-skip-read-only nil
9201cc28 89 "Non-nil means `query-replace' and friends ignore read-only matches."
1c4fe319
RS
90 :type 'boolean
91 :group 'matching
bf247b6e 92 :version "22.1")
1c4fe319 93
7abe68aa 94(defcustom query-replace-show-replacement t
9201cc28 95 "Non-nil means to show what actual replacement text will be."
7abe68aa
JL
96 :type 'boolean
97 :group 'matching
98 :version "23.1")
99
afd33362 100(defcustom query-replace-highlight t
9201cc28 101 "Non-nil means to highlight matches during query replacement."
afd33362
JL
102 :type 'boolean
103 :group 'matching)
104
105(defcustom query-replace-lazy-highlight t
9201cc28 106 "Controls the lazy-highlighting during query replacements.
afd33362
JL
107When non-nil, all text in the buffer matching the current match
108is highlighted lazily using isearch lazy highlighting (see
109`lazy-highlight-initial-delay' and `lazy-highlight-interval')."
110 :type 'boolean
111 :group 'lazy-highlight
112 :group 'matching
bf247b6e 113 :version "22.1")
afd33362
JL
114
115(defface query-replace
116 '((t (:inherit isearch)))
117 "Face for highlighting query replacement matches."
118 :group 'matching
bf247b6e 119 :version "22.1")
afd33362 120
06b60517
JB
121(defvar replace-count 0
122 "Number of replacements done so far.
123See `replace-regexp' and `query-replace-regexp-eval'.")
124
6f1df6d9
SM
125(defun query-replace-descr (string)
126 (mapconcat 'isearch-text-char-description string ""))
127
90c9fc2a 128(defun query-replace-read-from (prompt regexp-flag)
6f1df6d9
SM
129 "Query and return the `from' argument of a query-replace operation.
130The return value can also be a pair (FROM . TO) indicating that the user
131wants to replace FROM with TO."
1606466a
SM
132 (if query-replace-interactive
133 (car (if regexp-flag regexp-search-ring search-ring))
2bf2b947 134 (let* ((history-add-new-input nil)
eb2deaff
JL
135 (prompt
136 (if query-replace-defaults
137 (format "%s (default %s -> %s): " prompt
138 (query-replace-descr (car query-replace-defaults))
139 (query-replace-descr (cdr query-replace-defaults)))
140 (format "%s: " prompt)))
2bf2b947 141 (from
1606466a
SM
142 ;; The save-excursion here is in case the user marks and copies
143 ;; a region in order to specify the minibuffer input.
144 ;; That should not clobber the region for the query-replace itself.
145 (save-excursion
eb2deaff
JL
146 (if regexp-flag
147 (read-regexp prompt nil query-replace-from-history-variable)
148 (read-from-minibuffer
0e2ae83d
JL
149 prompt nil nil nil query-replace-from-history-variable
150 (car (if regexp-flag regexp-search-ring search-ring)) t)))))
6b59b130 151 (if (and (zerop (length from)) query-replace-defaults)
5dae4b11
CY
152 (cons (car query-replace-defaults)
153 (query-replace-compile-replacement
154 (cdr query-replace-defaults) regexp-flag))
2bf2b947 155 (add-to-history query-replace-from-history-variable from nil t)
6f1df6d9
SM
156 ;; Warn if user types \n or \t, but don't reject the input.
157 (and regexp-flag
158 (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\(\\\\[nt]\\)" from)
159 (let ((match (match-string 3 from)))
160 (cond
161 ((string= match "\\n")
162 (message "Note: `\\n' here doesn't match a newline; to do that, type C-q C-j instead"))
163 ((string= match "\\t")
164 (message "Note: `\\t' here doesn't match a tab; to do that, just type TAB")))
165 (sit-for 2)))
166 from))))
1606466a 167
78629844
DK
168(defun query-replace-compile-replacement (to regexp-flag)
169 "Maybe convert a regexp replacement TO to Lisp.
170Returns a list suitable for `perform-replace' if necessary,
171the original string if not."
172 (if (and regexp-flag
173 (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" to))
7c1c02ac
DK
174 (let (pos list char)
175 (while
176 (progn
177 (setq pos (match-end 0))
178 (push (substring to 0 (- pos 2)) list)
179 (setq char (aref to (1- pos))
180 to (substring to pos))
181 (cond ((eq char ?\#)
182 (push '(number-to-string replace-count) list))
183 ((eq char ?\,)
184 (setq pos (read-from-string to))
185 (push `(replace-quote ,(car pos)) list)
9e5d1b63
RS
186 (let ((end
187 ;; Swallow a space after a symbol
188 ;; if there is a space.
189 (if (and (or (symbolp (car pos))
190 ;; Swallow a space after 'foo
191 ;; but not after (quote foo).
192 (and (eq (car-safe (car pos)) 'quote)
f1f6079c
JL
193 (not (= ?\( (aref to 0)))))
194 (eq (string-match " " to (cdr pos))
195 (cdr pos)))
9e5d1b63
RS
196 (1+ (cdr pos))
197 (cdr pos))))
198 (setq to (substring to end)))))
7c1c02ac 199 (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" to)))
78629844
DK
200 (setq to (nreverse (delete "" (cons to list))))
201 (replace-match-string-symbols to)
202 (cons 'replace-eval-replacement
203 (if (cdr to)
204 (cons 'concat to)
205 (car to))))
1606466a
SM
206 to))
207
78629844 208
90c9fc2a 209(defun query-replace-read-to (from prompt regexp-flag)
78629844
DK
210 "Query and return the `to' argument of a query-replace operation."
211 (query-replace-compile-replacement
212 (save-excursion
2bf2b947
JL
213 (let* ((history-add-new-input nil)
214 (to (read-from-minibuffer
215 (format "%s %s with: " prompt (query-replace-descr from))
216 nil nil nil
217 query-replace-to-history-variable from t)))
218 (add-to-history query-replace-to-history-variable to nil t)
6b59b130
CY
219 (setq query-replace-defaults (cons from to))
220 to))
78629844
DK
221 regexp-flag))
222
90c9fc2a 223(defun query-replace-read-args (prompt regexp-flag &optional noerror)
1606466a
SM
224 (unless noerror
225 (barf-if-buffer-read-only))
90c9fc2a 226 (let* ((from (query-replace-read-from prompt regexp-flag))
6f1df6d9 227 (to (if (consp from) (prog1 (cdr from) (setq from (car from)))
90c9fc2a 228 (query-replace-read-to from prompt regexp-flag))))
3ee4cd64
JL
229 (list from to
230 (and current-prefix-arg (not (eq current-prefix-arg '-)))
231 (and current-prefix-arg (eq current-prefix-arg '-)))))
770970cb 232
3ee4cd64 233(defun query-replace (from-string to-string &optional delimited start end backward)
da44e784
RM
234 "Replace some occurrences of FROM-STRING with TO-STRING.
235As each match is found, the user must type a character saying
236what to do with it. For directions, type \\[help-command] at that time.
237
7ef5c431
KH
238In Transient Mark mode, if the mark is active, operate on the contents
239of the region. Otherwise, operate from point to the end of the buffer.
240
0e2ae83d
JL
241Use \\<minibuffer-local-map>\\[next-history-element] \
242to pull the last incremental search string to the minibuffer
243that reads FROM-STRING, or invoke replacements from
244incremental search with a key sequence like `C-s C-s M-%'
245to use its current search string as the string to replace.
151270f3 246
446d9629
RS
247Matching is independent of case if `case-fold-search' is non-nil and
248FROM-STRING has no uppercase letters. Replacement transfers the case
249pattern of the old text to the new text, if `case-replace' and
250`case-fold-search' are non-nil and FROM-STRING has no uppercase
fa6bc6fd 251letters. (Transferring the case pattern means that if the old text
446d9629
RS
252matched is all caps, or capitalized, then its replacement is upcased
253or capitalized.)
9b0bf2b6 254
3c9c9d38
JL
255Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
256ignore hidden matches if `search-invisible' is nil, and ignore more
dc6c0eda 257matches using `isearch-filter-predicate'.
3c9c9d38 258
826b3235
JL
259If `replace-lax-whitespace' is non-nil, a space or spaces in the string
260to be replaced will match a sequence of whitespace chars defined by the
261regexp in `search-whitespace-regexp'.
262
118a01c9 263Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
3ee4cd64
JL
264only matches surrounded by word boundaries. A negative prefix arg means
265replace backward.
266
47d72254 267Fourth and fifth arg START and END specify the region to operate on.
81bdc14d
RS
268
269To customize possible responses, change the \"bindings\" in `query-replace-map'."
04ff2dee
JL
270 (interactive
271 (let ((common
272 (query-replace-read-args
273 (concat "Query replace"
3ee4cd64
JL
274 (if current-prefix-arg
275 (if (eq current-prefix-arg '-) " backward" " word")
276 "")
04ff2dee
JL
277 (if (and transient-mark-mode mark-active) " in region" ""))
278 nil)))
279 (list (nth 0 common) (nth 1 common) (nth 2 common)
280 ;; These are done separately here
281 ;; so that command-history will record these expressions
282 ;; rather than the values they had this time.
283 (if (and transient-mark-mode mark-active)
284 (region-beginning))
285 (if (and transient-mark-mode mark-active)
3ee4cd64
JL
286 (region-end))
287 (nth 3 common))))
288 (perform-replace from-string to-string t nil delimited nil nil start end backward))
7ef5c431 289
73fa8346 290(define-key esc-map "%" 'query-replace)
da44e784 291
3ee4cd64 292(defun query-replace-regexp (regexp to-string &optional delimited start end backward)
da44e784
RM
293 "Replace some things after point matching REGEXP with TO-STRING.
294As each match is found, the user must type a character saying
295what to do with it. For directions, type \\[help-command] at that time.
296
7ef5c431
KH
297In Transient Mark mode, if the mark is active, operate on the contents
298of the region. Otherwise, operate from point to the end of the buffer.
299
0e2ae83d
JL
300Use \\<minibuffer-local-map>\\[next-history-element] \
301to pull the last incremental search regexp to the minibuffer
302that reads REGEXP, or invoke replacements from
303incremental search with a key sequence like `C-M-s C-M-s C-M-%'
304to use its current search regexp as the regexp to replace.
151270f3 305
446d9629
RS
306Matching is independent of case if `case-fold-search' is non-nil and
307REGEXP has no uppercase letters. Replacement transfers the case
308pattern of the old text to the new text, if `case-replace' and
309`case-fold-search' are non-nil and REGEXP has no uppercase letters.
310\(Transferring the case pattern means that if the old text matched is
311all caps, or capitalized, then its replacement is upcased or
312capitalized.)
47d72254 313
3c9c9d38
JL
314Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
315ignore hidden matches if `search-invisible' is nil, and ignore more
dc6c0eda 316matches using `isearch-filter-predicate'.
3c9c9d38 317
3231d532 318If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp
826b3235
JL
319to be replaced will match a sequence of whitespace chars defined by the
320regexp in `search-whitespace-regexp'.
321
118a01c9 322Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
3ee4cd64
JL
323only matches surrounded by word boundaries. A negative prefix arg means
324replace backward.
325
47d72254
GM
326Fourth and fifth arg START and END specify the region to operate on.
327
118a01c9
RS
328In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
329and `\\=\\N' (where N is a digit) stands for
2f57bf85 330whatever what matched the Nth `\\(...\\)' in REGEXP.
7c1c02ac
DK
331`\\?' lets you edit the replacement text in the minibuffer
332at the given position for each replacement.
333
ba8d15f9
RS
334In interactive calls, the replacement text can contain `\\,'
335followed by a Lisp expression. Each
336replacement evaluates that expression to compute the replacement
337string. Inside of that expression, `\\&' is a string denoting the
f1f6079c 338whole match as a string, `\\N' for a partial match, `\\#&' and `\\#N'
ba8d15f9
RS
339for the whole or a partial match converted to a number with
340`string-to-number', and `\\#' itself for the number of replacements
341done so far (starting with zero).
7c1c02ac 342
ba8d15f9
RS
343If the replacement expression is a symbol, write a space after it
344to terminate it. One space there, if any, will be discarded.
7c1c02ac
DK
345
346When using those Lisp features interactively in the replacement
347text, TO-STRING is actually made a list instead of a string.
348Use \\[repeat-complex-command] after this command for details."
10784bac
RS
349 (interactive
350 (let ((common
10ddc30e 351 (query-replace-read-args
04ff2dee 352 (concat "Query replace"
3ee4cd64
JL
353 (if current-prefix-arg
354 (if (eq current-prefix-arg '-) " backward" " word")
355 "")
04ff2dee
JL
356 " regexp"
357 (if (and transient-mark-mode mark-active) " in region" ""))
f79bdb3a 358 t)))
7c1c02ac
DK
359 (list (nth 0 common) (nth 1 common) (nth 2 common)
360 ;; These are done separately here
361 ;; so that command-history will record these expressions
362 ;; rather than the values they had this time.
363 (if (and transient-mark-mode mark-active)
364 (region-beginning))
365 (if (and transient-mark-mode mark-active)
3ee4cd64
JL
366 (region-end))
367 (nth 3 common))))
368 (perform-replace regexp to-string t t delimited nil nil start end backward))
2f57bf85 369
cbc127de 370(define-key esc-map [?\C-%] 'query-replace-regexp)
da44e784 371
47d72254 372(defun query-replace-regexp-eval (regexp to-expr &optional delimited start end)
84482eb3 373 "Replace some things after point matching REGEXP with the result of TO-EXPR.
fc6a2250
DK
374
375Interactive use of this function is deprecated in favor of the
376`\\,' feature of `query-replace-regexp'. For non-interactive use, a loop
377using `search-forward-regexp' and `replace-match' is preferred.
378
84482eb3
RS
379As each match is found, the user must type a character saying
380what to do with it. For directions, type \\[help-command] at that time.
381
382TO-EXPR is a Lisp expression evaluated to compute each replacement. It may
383reference `replace-count' to get the number of replacements already made.
384If the result of TO-EXPR is not a string, it is converted to one using
385`prin1-to-string' with the NOESCAPE argument (which see).
386
387For convenience, when entering TO-EXPR interactively, you can use `\\&' or
653479ad
AS
388`\\0' to stand for whatever matched the whole of REGEXP, and `\\N' (where
389N is a digit) to stand for whatever matched the Nth `\\(...\\)' in REGEXP.
84482eb3 390Use `\\#&' or `\\#N' if you want a number instead of a string.
2f57bf85 391In interactive use, `\\#' in itself stands for `replace-count'.
84482eb3
RS
392
393In Transient Mark mode, if the mark is active, operate on the contents
394of the region. Otherwise, operate from point to the end of the buffer.
395
0e2ae83d
JL
396Use \\<minibuffer-local-map>\\[next-history-element] \
397to pull the last incremental search regexp to the minibuffer
398that reads REGEXP.
84482eb3
RS
399
400Preserves case in each replacement if `case-replace' and `case-fold-search'
401are non-nil and REGEXP has no uppercase letters.
47d72254 402
3c9c9d38
JL
403Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
404ignore hidden matches if `search-invisible' is nil, and ignore more
dc6c0eda 405matches using `isearch-filter-predicate'.
3c9c9d38 406
3231d532 407If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp
826b3235
JL
408to be replaced will match a sequence of whitespace chars defined by the
409regexp in `search-whitespace-regexp'.
410
84482eb3 411Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
470bbe9b 412only matches that are surrounded by word boundaries.
47d72254 413Fourth and fifth arg START and END specify the region to operate on."
59f7af81
CY
414 (declare (obsolete "use the `\\,' feature of `query-replace-regexp'
415for interactive calls, and `search-forward-regexp'/`replace-match'
416for Lisp calls." "22.1"))
84482eb3 417 (interactive
cc0aea1a 418 (progn
59f7af81
CY
419 (barf-if-buffer-read-only)
420 (let* ((from
421 ;; Let-bind the history var to disable the "foo -> bar"
422 ;; default. Maybe we shouldn't disable this default, but
423 ;; for now I'll leave it off. --Stef
424 (let ((query-replace-to-history-variable nil))
425 (query-replace-read-from "Query replace regexp" t)))
426 (to (list (read-from-minibuffer
427 (format "Query replace regexp %s with eval: "
428 (query-replace-descr from))
429 nil nil t query-replace-to-history-variable from t))))
430 ;; We make TO a list because replace-match-string-symbols requires one,
431 ;; and the user might enter a single token.
432 (replace-match-string-symbols to)
433 (list from (car to) current-prefix-arg
434 (if (and transient-mark-mode mark-active)
435 (region-beginning))
436 (if (and transient-mark-mode mark-active)
437 (region-end))))))
d2ce3151 438 (perform-replace regexp (cons 'replace-eval-replacement to-expr)
d83a97ab 439 t 'literal delimited nil nil start end))
84482eb3 440
47d72254 441(defun map-query-replace-regexp (regexp to-strings &optional n start end)
da44e784 442 "Replace some matches for REGEXP with various strings, in rotation.
d8f1d2f3
JB
443The second argument TO-STRINGS contains the replacement strings, separated
444by spaces. This command works like `query-replace-regexp' except that
445each successive replacement uses the next successive replacement string,
da44e784
RM
446wrapping around from the last such string to the first.
447
7ef5c431
KH
448In Transient Mark mode, if the mark is active, operate on the contents
449of the region. Otherwise, operate from point to the end of the buffer.
450
da44e784
RM
451Non-interactively, TO-STRINGS may be a list of replacement strings.
452
b8630261 453Interactively, reads the regexp using `read-regexp'.
0e2ae83d
JL
454Use \\<minibuffer-local-map>\\[next-history-element] \
455to pull the last incremental search regexp to the minibuffer
456that reads REGEXP.
151270f3 457
da44e784 458A prefix argument N says to use each replacement string N times
47d72254
GM
459before rotating to the next.
460Fourth and fifth arg START and END specify the region to operate on."
770970cb 461 (interactive
0e2ae83d
JL
462 (let* ((from (read-regexp "Map query replace (regexp): " nil
463 query-replace-from-history-variable))
5291cbca 464 (to (read-from-minibuffer
770970cb 465 (format "Query replace %s with (space-separated strings): "
6f1df6d9 466 (query-replace-descr from))
770970cb 467 nil nil nil
84d0a5f8 468 query-replace-to-history-variable from t)))
2f2f7e58
RS
469 (list from to
470 (and current-prefix-arg
471 (prefix-numeric-value current-prefix-arg))
10784bac
RS
472 (if (and transient-mark-mode mark-active)
473 (region-beginning))
474 (if (and transient-mark-mode mark-active)
475 (region-end)))))
da44e784
RM
476 (let (replacements)
477 (if (listp to-strings)
478 (setq replacements to-strings)
479 (while (/= (length to-strings) 0)
480 (if (string-match " " to-strings)
481 (setq replacements
482 (append replacements
483 (list (substring to-strings 0
484 (string-match " " to-strings))))
485 to-strings (substring to-strings
486 (1+ (string-match " " to-strings))))
487 (setq replacements (append replacements (list to-strings))
488 to-strings ""))))
99a7559f 489 (perform-replace regexp replacements t t nil n nil start end)))
da44e784 490
3ee4cd64 491(defun replace-string (from-string to-string &optional delimited start end backward)
da44e784
RM
492 "Replace occurrences of FROM-STRING with TO-STRING.
493Preserve case in each match if `case-replace' and `case-fold-search'
494are non-nil and FROM-STRING has no uppercase letters.
9b0bf2b6
RS
495\(Preserving case means that if the string matched is all caps, or capitalized,
496then its replacement is upcased or capitalized.)
497
3c9c9d38
JL
498Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
499ignore hidden matches if `search-invisible' is nil, and ignore more
dc6c0eda 500matches using `isearch-filter-predicate'.
3c9c9d38 501
826b3235
JL
502If `replace-lax-whitespace' is non-nil, a space or spaces in the string
503to be replaced will match a sequence of whitespace chars defined by the
504regexp in `search-whitespace-regexp'.
505
118a01c9 506Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
3ee4cd64
JL
507only matches surrounded by word boundaries. A negative prefix arg means
508replace backward.
39785324
GM
509
510Operates on the region between START and END (if both are nil, from point
511to the end of the buffer). Interactively, if Transient Mark mode is
512enabled and the mark is active, operates on the contents of the region;
513otherwise from point to the end of the buffer.
da44e784 514
0e2ae83d
JL
515Use \\<minibuffer-local-map>\\[next-history-element] \
516to pull the last incremental search string to the minibuffer
517that reads FROM-STRING.
151270f3 518
da44e784
RM
519This function is usually the wrong thing to use in a Lisp program.
520What you probably want is a loop like this:
118a01c9
RS
521 (while (search-forward FROM-STRING nil t)
522 (replace-match TO-STRING nil t))
87532fbe
RS
523which will run faster and will not set the mark or print anything.
524\(You may need a more complex loop if FROM-STRING can match the null string
525and TO-STRING is also null.)"
5076d275
GM
526 (declare (interactive-only
527 "use `search-forward' and `replace-match' instead."))
10784bac
RS
528 (interactive
529 (let ((common
10ddc30e 530 (query-replace-read-args
04ff2dee 531 (concat "Replace"
3ee4cd64
JL
532 (if current-prefix-arg
533 (if (eq current-prefix-arg '-) " backward" " word")
534 "")
04ff2dee
JL
535 " string"
536 (if (and transient-mark-mode mark-active) " in region" ""))
f79bdb3a 537 nil)))
10784bac
RS
538 (list (nth 0 common) (nth 1 common) (nth 2 common)
539 (if (and transient-mark-mode mark-active)
540 (region-beginning))
541 (if (and transient-mark-mode mark-active)
3ee4cd64
JL
542 (region-end))
543 (nth 3 common))))
544 (perform-replace from-string to-string nil nil delimited nil nil start end backward))
da44e784 545
3ee4cd64 546(defun replace-regexp (regexp to-string &optional delimited start end backward)
da44e784 547 "Replace things after point matching REGEXP with TO-STRING.
118a01c9 548Preserve case in each match if `case-replace' and `case-fold-search'
da44e784 549are non-nil and REGEXP has no uppercase letters.
47d72254 550
3c9c9d38
JL
551Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
552ignore hidden matches if `search-invisible' is nil, and ignore more
dc6c0eda 553matches using `isearch-filter-predicate'.
3c9c9d38 554
3231d532 555If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp
826b3235
JL
556to be replaced will match a sequence of whitespace chars defined by the
557regexp in `search-whitespace-regexp'.
558
47d72254
GM
559In Transient Mark mode, if the mark is active, operate on the contents
560of the region. Otherwise, operate from point to the end of the buffer.
561
118a01c9 562Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
3ee4cd64
JL
563only matches surrounded by word boundaries. A negative prefix arg means
564replace backward.
565
47d72254
GM
566Fourth and fifth arg START and END specify the region to operate on.
567
118a01c9
RS
568In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
569and `\\=\\N' (where N is a digit) stands for
7c1c02ac
DK
570whatever what matched the Nth `\\(...\\)' in REGEXP.
571`\\?' lets you edit the replacement text in the minibuffer
572at the given position for each replacement.
573
574In interactive calls, the replacement text may contain `\\,'
575followed by a Lisp expression used as part of the replacement
576text. Inside of that expression, `\\&' is a string denoting the
107173cf
JB
577whole match, `\\N' a partial match, `\\#&' and `\\#N' the respective
578numeric values from `string-to-number', and `\\#' itself for
579`replace-count', the number of replacements occurred so far.
7c1c02ac
DK
580
581If your Lisp expression is an identifier and the next letter in
582the replacement string would be interpreted as part of it, you
583can wrap it with an expression like `\\,(or \\#)'. Incidentally,
584for this particular case you may also enter `\\#' in the
585replacement text directly.
586
587When using those Lisp features interactively in the replacement
588text, TO-STRING is actually made a list instead of a string.
589Use \\[repeat-complex-command] after this command for details.
da44e784 590
0e2ae83d
JL
591Use \\<minibuffer-local-map>\\[next-history-element] \
592to pull the last incremental search regexp to the minibuffer
593that reads REGEXP.
151270f3 594
da44e784
RM
595This function is usually the wrong thing to use in a Lisp program.
596What you probably want is a loop like this:
597 (while (re-search-forward REGEXP nil t)
118a01c9 598 (replace-match TO-STRING nil nil))
da44e784 599which will run faster and will not set the mark or print anything."
5076d275
GM
600 (declare (interactive-only
601 "use `re-search-forward' and `replace-match' instead."))
10784bac
RS
602 (interactive
603 (let ((common
10ddc30e 604 (query-replace-read-args
04ff2dee 605 (concat "Replace"
3ee4cd64
JL
606 (if current-prefix-arg
607 (if (eq current-prefix-arg '-) " backward" " word")
608 "")
04ff2dee
JL
609 " regexp"
610 (if (and transient-mark-mode mark-active) " in region" ""))
f79bdb3a 611 t)))
10784bac
RS
612 (list (nth 0 common) (nth 1 common) (nth 2 common)
613 (if (and transient-mark-mode mark-active)
614 (region-beginning))
615 (if (and transient-mark-mode mark-active)
3ee4cd64
JL
616 (region-end))
617 (nth 3 common))))
618 (perform-replace regexp to-string nil t delimited nil nil start end backward))
e32eb3e6 619
4c53bd2b
RS
620\f
621(defvar regexp-history nil
fae97ed8
EZ
622 "History list for some commands that read regular expressions.
623
624Maximum length of the history list is determined by the value
625of `history-length', which see.")
da44e784 626
15af15e5
TO
627(defvar occur-collect-regexp-history '("\\1")
628 "History of regexp for occur's collect operation")
629
24da7273 630(defcustom read-regexp-defaults-function nil
b8630261
GM
631 "Function that provides default regexp(s) for `read-regexp'.
632This function should take no arguments and return one of: nil, a
633regexp, or a list of regexps. Interactively, `read-regexp' uses
634the return value of this function for its DEFAULT argument.
24da7273 635
b8630261
GM
636As an example, set this variable to `find-tag-default-as-regexp'
637to default to the symbol at point.
24da7273 638
b8630261
GM
639To provide different default regexps for different commands,
640the function that you set this to can check `this-command'."
24da7273
JL
641 :type '(choice
642 (const :tag "No default regexp reading function" nil)
643 (const :tag "Latest regexp history" regexp-history-last)
644 (function-item :tag "Tag at point"
645 find-tag-default)
646 (function-item :tag "Tag at point as regexp"
647 find-tag-default-as-regexp)
648 (function-item :tag "Tag at point as symbol regexp"
649 find-tag-default-as-symbol-regexp)
b8630261 650 (function :tag "Your choice of function"))
24da7273
JL
651 :group 'matching
652 :version "24.4")
653
654(defun read-regexp-suggestions ()
655 "Return a list of standard suggestions for `read-regexp'.
656By default, the list includes the tag at point, the last isearch regexp,
657the last isearch string, and the last replacement regexp. `read-regexp'
658appends the list returned by this function to the end of values available
659via \\<minibuffer-local-map>\\[next-history-element]."
660 (list
661 (find-tag-default-as-regexp)
662 (find-tag-default-as-symbol-regexp)
663 (car regexp-search-ring)
664 (regexp-quote (or (car search-ring) ""))
665 (car (symbol-value query-replace-from-history-variable))))
666
5825610b
JL
667(defun read-regexp (prompt &optional defaults history)
668 "Read and return a regular expression as a string.
b8630261
GM
669Prompt with the string PROMPT. If PROMPT ends in \":\" (followed by
670optional whitespace), use it as-is. Otherwise, add \": \" to the end,
ab837c60 671possibly preceded by the default result (see below).
b8630261
GM
672
673The optional argument DEFAULTS can be either: nil, a string, a list
674of strings, or a symbol. We use DEFAULTS to construct the default
675return value in case of empty input.
676
677If DEFAULTS is a string, we use it as-is.
678
679If DEFAULTS is a list of strings, the first element is the
680default return value, but all the elements are accessible
681using the history command \\<minibuffer-local-map>\\[next-history-element].
682
683If DEFAULTS is a non-nil symbol, then if `read-regexp-defaults-function'
684is non-nil, we use that in place of DEFAULTS in the following:
685 If DEFAULTS is the symbol `regexp-history-last', we use the first
686 element of HISTORY (if specified) or `regexp-history'.
687 If DEFAULTS is a function, we call it with no arguments and use
688 what it returns, which should be either nil, a string, or a list of strings.
689
690We append the standard values from `read-regexp-suggestions' to DEFAULTS
691before using it.
692
693If the first element of DEFAULTS is non-nil (and if PROMPT does not end
694in \":\", followed by optional whitespace), we add it to the prompt.
695
696The optional argument HISTORY is a symbol to use for the history list.
697If nil, uses `regexp-history'."
24da7273
JL
698 (let* ((defaults
699 (if (and defaults (symbolp defaults))
700 (cond
701 ((eq (or read-regexp-defaults-function defaults)
702 'regexp-history-last)
703 (car (symbol-value (or history 'regexp-history))))
704 ((functionp (or read-regexp-defaults-function defaults))
705 (funcall (or read-regexp-defaults-function defaults))))
706 defaults))
707 (default (if (consp defaults) (car defaults) defaults))
cd27a76d 708 (suggestions (if (listp defaults) defaults (list defaults)))
24da7273 709 (suggestions (append suggestions (read-regexp-suggestions)))
cd27a76d 710 (suggestions (delete-dups (delq nil (delete "" suggestions))))
5825610b 711 ;; Do not automatically add default to the history for empty input.
96f606c5 712 (history-add-new-input nil)
41a97e6f
JL
713 (input (read-from-minibuffer
714 (cond ((string-match-p ":[ \t]*\\'" prompt)
715 prompt)
24da7273 716 ((and default (> (length default) 0))
41a97e6f 717 (format "%s (default %s): " prompt
5825610b 718 (query-replace-descr default)))
41a97e6f
JL
719 (t
720 (format "%s: " prompt)))
cd27a76d 721 nil nil nil (or history 'regexp-history) suggestions t)))
96f606c5 722 (if (equal input "")
cd27a76d 723 ;; Return the default value when the user enters empty input.
24da7273
JL
724 (prog1 (or default input)
725 (when default
726 (add-to-history (or history 'regexp-history) default)))
cd27a76d 727 ;; Otherwise, add non-empty input to the history and return input.
96f606c5 728 (prog1 input
eebbf404 729 (add-to-history (or history 'regexp-history) input)))))
96f606c5 730
e32eb3e6 731
31e1d920 732(defalias 'delete-non-matching-lines 'keep-lines)
e32eb3e6
GM
733(defalias 'delete-matching-lines 'flush-lines)
734(defalias 'count-matches 'how-many)
735
736
737(defun keep-lines-read-args (prompt)
738 "Read arguments for `keep-lines' and friends.
739Prompt for a regexp with PROMPT.
2ced751f 740Value is a list, (REGEXP)."
99910cf4 741 (list (read-regexp prompt) nil nil t))
e32eb3e6 742
bace7209 743(defun keep-lines (regexp &optional rstart rend interactive)
698e1804
RS
744 "Delete all lines except those containing matches for REGEXP.
745A match split across lines preserves all the lines it lies in.
bace7209
LT
746When called from Lisp (and usually interactively as well, see below)
747applies to all lines starting after point.
d2a0ee8b 748
3be42fcd
JL
749If REGEXP contains upper case characters (excluding those preceded by `\\')
750and `search-upper-case' is non-nil, the matching is case-sensitive.
e32eb3e6
GM
751
752Second and third arg RSTART and REND specify the region to operate on.
bace7209
LT
753This command operates on (the accessible part of) all lines whose
754accessible part is entirely contained in the region determined by RSTART
755and REND. (A newline ending a line counts as part of that line.)
e32eb3e6 756
2ced751f 757Interactively, in Transient Mark mode when the mark is active, operate
bace7209
LT
758on all lines whose accessible part is entirely contained in the region.
759Otherwise, the command applies to all lines starting after point.
760When calling this function from Lisp, you can pretend that it was
761called interactively by passing a non-nil INTERACTIVE argument.
762
763This function starts looking for the next match from the end of
764the previous match. Hence, it ignores matches that overlap
765a previously found match."
2ced751f 766
e32eb3e6 767 (interactive
98faf1bb
RS
768 (progn
769 (barf-if-buffer-read-only)
96f606c5 770 (keep-lines-read-args "Keep lines containing match for regexp")))
e32eb3e6 771 (if rstart
119831da
RS
772 (progn
773 (goto-char (min rstart rend))
bace7209
LT
774 (setq rend
775 (progn
776 (save-excursion
777 (goto-char (max rstart rend))
778 (unless (or (bolp) (eobp))
779 (forward-line 0))
780 (point-marker)))))
781 (if (and interactive transient-mark-mode mark-active)
2ced751f 782 (setq rstart (region-beginning)
bace7209
LT
783 rend (progn
784 (goto-char (region-end))
785 (unless (or (bolp) (eobp))
786 (forward-line 0))
787 (point-marker)))
2ced751f
RS
788 (setq rstart (point)
789 rend (point-max-marker)))
790 (goto-char rstart))
698e1804
RS
791 (save-excursion
792 (or (bolp) (forward-line 1))
d2a0ee8b 793 (let ((start (point))
3be42fcd
JL
794 (case-fold-search
795 (if (and case-fold-search search-upper-case)
796 (isearch-no-upper-case-p regexp t)
797 case-fold-search)))
e32eb3e6 798 (while (< (point) rend)
698e1804 799 ;; Start is first char not preserved by previous match.
e32eb3e6
GM
800 (if (not (re-search-forward regexp rend 'move))
801 (delete-region start rend)
698e1804 802 (let ((end (save-excursion (goto-char (match-beginning 0))
bace7209 803 (forward-line 0)
698e1804
RS
804 (point))))
805 ;; Now end is first char preserved by the new match.
806 (if (< start end)
807 (delete-region start end))))
d99118b0 808
e32eb3e6 809 (setq start (save-excursion (forward-line 1) (point)))
698e1804 810 ;; If the match was empty, avoid matching again at same place.
e32eb3e6
GM
811 (and (< (point) rend)
812 (= (match-beginning 0) (match-end 0))
bace7209
LT
813 (forward-char 1)))))
814 (set-marker rend nil)
815 nil)
698e1804 816
e32eb3e6 817
bace7209
LT
818(defun flush-lines (regexp &optional rstart rend interactive)
819 "Delete lines containing matches for REGEXP.
820When called from Lisp (and usually when called interactively as
821well, see below), applies to the part of the buffer after point.
822The line point is in is deleted if and only if it contains a
823match for regexp starting after point.
d2a0ee8b 824
3be42fcd
JL
825If REGEXP contains upper case characters (excluding those preceded by `\\')
826and `search-upper-case' is non-nil, the matching is case-sensitive.
e32eb3e6
GM
827
828Second and third arg RSTART and REND specify the region to operate on.
bace7209
LT
829Lines partially contained in this region are deleted if and only if
830they contain a match entirely contained in it.
e32eb3e6 831
2ced751f
RS
832Interactively, in Transient Mark mode when the mark is active, operate
833on the contents of the region. Otherwise, operate from point to the
bace7209
LT
834end of (the accessible portion of) the buffer. When calling this function
835from Lisp, you can pretend that it was called interactively by passing
836a non-nil INTERACTIVE argument.
837
838If a match is split across lines, all the lines it lies in are deleted.
839They are deleted _before_ looking for the next match. Hence, a match
840starting on the same line at which another match ended is ignored."
2ced751f 841
e32eb3e6 842 (interactive
98faf1bb
RS
843 (progn
844 (barf-if-buffer-read-only)
96f606c5 845 (keep-lines-read-args "Flush lines containing match for regexp")))
e32eb3e6 846 (if rstart
119831da
RS
847 (progn
848 (goto-char (min rstart rend))
849 (setq rend (copy-marker (max rstart rend))))
bace7209 850 (if (and interactive transient-mark-mode mark-active)
2ced751f
RS
851 (setq rstart (region-beginning)
852 rend (copy-marker (region-end)))
853 (setq rstart (point)
854 rend (point-max-marker)))
855 (goto-char rstart))
3be42fcd
JL
856 (let ((case-fold-search
857 (if (and case-fold-search search-upper-case)
858 (isearch-no-upper-case-p regexp t)
859 case-fold-search)))
d2a0ee8b 860 (save-excursion
e32eb3e6
GM
861 (while (and (< (point) rend)
862 (re-search-forward regexp rend t))
d2a0ee8b 863 (delete-region (save-excursion (goto-char (match-beginning 0))
bace7209 864 (forward-line 0)
d2a0ee8b 865 (point))
bace7209
LT
866 (progn (forward-line 1) (point))))))
867 (set-marker rend nil)
868 nil)
698e1804 869
e32eb3e6 870
bace7209
LT
871(defun how-many (regexp &optional rstart rend interactive)
872 "Print and return number of matches for REGEXP following point.
873When called from Lisp and INTERACTIVE is omitted or nil, just return
874the number, do not print it; if INTERACTIVE is t, the function behaves
3f2372cb 875in all respects as if it had been called interactively.
d2a0ee8b 876
3be42fcd
JL
877If REGEXP contains upper case characters (excluding those preceded by `\\')
878and `search-upper-case' is non-nil, the matching is case-sensitive.
e32eb3e6
GM
879
880Second and third arg RSTART and REND specify the region to operate on.
881
2ced751f
RS
882Interactively, in Transient Mark mode when the mark is active, operate
883on the contents of the region. Otherwise, operate from point to the
bace7209
LT
884end of (the accessible portion of) the buffer.
885
886This function starts looking for the next match from the end of
887the previous match. Hence, it ignores matches that overlap
888a previously found match."
2ced751f 889
e32eb3e6 890 (interactive
96f606c5 891 (keep-lines-read-args "How many matches for regexp"))
f601efb0
SM
892 (save-excursion
893 (if rstart
fc7f501b
OK
894 (if rend
895 (progn
896 (goto-char (min rstart rend))
897 (setq rend (max rstart rend)))
898 (goto-char rstart)
899 (setq rend (point-max)))
bace7209 900 (if (and interactive transient-mark-mode mark-active)
2ced751f 901 (setq rstart (region-beginning)
bace7209 902 rend (region-end))
2ced751f 903 (setq rstart (point)
bace7209 904 rend (point-max)))
2ced751f 905 (goto-char rstart))
f601efb0
SM
906 (let ((count 0)
907 opoint
3be42fcd
JL
908 (case-fold-search
909 (if (and case-fold-search search-upper-case)
910 (isearch-no-upper-case-p regexp t)
911 case-fold-search)))
f601efb0
SM
912 (while (and (< (point) rend)
913 (progn (setq opoint (point))
914 (re-search-forward regexp rend t)))
915 (if (= opoint (point))
916 (forward-char 1)
917 (setq count (1+ count))))
bace7209
LT
918 (when interactive (message "%d occurrence%s"
919 count
920 (if (= count 1) "" "s")))
921 count)))
e32eb3e6 922
4c53bd2b 923\f
60e56523 924(defvar occur-menu-map
b016851c 925 (let ((map (make-sparse-keymap)))
1ec4b7b2
SM
926 (bindings--define-key map [next-error-follow-minor-mode]
927 '(menu-item "Auto Occurrence Display"
12544bbe 928 next-error-follow-minor-mode
1ec4b7b2 929 :help "Display another occurrence when moving the cursor"
12544bbe
GM
930 :button (:toggle . (and (boundp 'next-error-follow-minor-mode)
931 next-error-follow-minor-mode))))
1ec4b7b2
SM
932 (bindings--define-key map [separator-1] menu-bar-separator)
933 (bindings--define-key map [kill-this-buffer]
934 '(menu-item "Kill Occur Buffer" kill-this-buffer
935 :help "Kill the current *Occur* buffer"))
936 (bindings--define-key map [quit-window]
937 '(menu-item "Quit Occur Window" quit-window
938 :help "Quit the current *Occur* buffer. Bury it, and maybe delete the selected frame"))
939 (bindings--define-key map [revert-buffer]
940 '(menu-item "Revert Occur Buffer" revert-buffer
941 :help "Replace the text in the *Occur* buffer with the results of rerunning occur"))
942 (bindings--define-key map [clone-buffer]
943 '(menu-item "Clone Occur Buffer" clone-buffer
944 :help "Create and return a twin copy of the current *Occur* buffer"))
945 (bindings--define-key map [occur-rename-buffer]
946 '(menu-item "Rename Occur Buffer" occur-rename-buffer
947 :help "Rename the current *Occur* buffer to *Occur: original-buffer-name*."))
948 (bindings--define-key map [occur-edit-buffer]
949 '(menu-item "Edit Occur Buffer" occur-edit-mode
950 :help "Edit the *Occur* buffer and apply changes to the original buffers."))
951 (bindings--define-key map [separator-2] menu-bar-separator)
952 (bindings--define-key map [occur-mode-goto-occurrence-other-window]
953 '(menu-item "Go To Occurrence Other Window" occur-mode-goto-occurrence-other-window
954 :help "Go to the occurrence the current line describes, in another window"))
955 (bindings--define-key map [occur-mode-goto-occurrence]
956 '(menu-item "Go To Occurrence" occur-mode-goto-occurrence
957 :help "Go to the occurrence the current line describes"))
958 (bindings--define-key map [occur-mode-display-occurrence]
959 '(menu-item "Display Occurrence" occur-mode-display-occurrence
960 :help "Display in another window the occurrence the current line describes"))
961 (bindings--define-key map [occur-next]
962 '(menu-item "Move to Next Match" occur-next
963 :help "Move to the Nth (default 1) next match in an Occur mode buffer"))
964 (bindings--define-key map [occur-prev]
965 '(menu-item "Move to Previous Match" occur-prev
966 :help "Move to the Nth (default 1) previous match in an Occur mode buffer"))
b016851c 967 map)
60e56523
LL
968 "Menu keymap for `occur-mode'.")
969
970(defvar occur-mode-map
971 (let ((map (make-sparse-keymap)))
972 ;; We use this alternative name, so we can use \\[occur-mode-mouse-goto].
973 (define-key map [mouse-2] 'occur-mode-mouse-goto)
974 (define-key map "\C-c\C-c" 'occur-mode-goto-occurrence)
8c0f49f0 975 (define-key map "e" 'occur-edit-mode)
60e56523
LL
976 (define-key map "\C-m" 'occur-mode-goto-occurrence)
977 (define-key map "o" 'occur-mode-goto-occurrence-other-window)
978 (define-key map "\C-o" 'occur-mode-display-occurrence)
979 (define-key map "\M-n" 'occur-next)
980 (define-key map "\M-p" 'occur-prev)
981 (define-key map "r" 'occur-rename-buffer)
982 (define-key map "c" 'clone-buffer)
983 (define-key map "\C-c\C-f" 'next-error-follow-minor-mode)
1ec4b7b2 984 (bindings--define-key map [menu-bar occur] (cons "Occur" occur-menu-map))
60e56523 985 map)
b016851c 986 "Keymap for `occur-mode'.")
698e1804 987
46b3d18e
RS
988(defvar occur-revert-arguments nil
989 "Arguments to pass to `occur-1' to revert an Occur mode buffer.
990See `occur-revert-function'.")
08d355e3
LL
991(make-variable-buffer-local 'occur-revert-arguments)
992(put 'occur-revert-arguments 'permanent-local t)
698e1804 993
c9ae8cbb
JB
994(defcustom occur-mode-hook '(turn-on-font-lock)
995 "Hook run when entering Occur mode."
996 :type 'hook
997 :group 'matching)
998
999(defcustom occur-hook nil
c7d2f2cc 1000 "Hook run by Occur when there are any matches."
daae70bf
CW
1001 :type 'hook
1002 :group 'matching)
1003
8e62d5e8
CD
1004(defcustom occur-mode-find-occurrence-hook nil
1005 "Hook run by Occur after locating an occurrence.
1006This will be called with the cursor position at the occurrence. An application
1007for this is to reveal context in an outline-mode when the occurrence is hidden."
1008 :type 'hook
1009 :group 'matching)
1010
de3c9b09 1011(put 'occur-mode 'mode-class 'special)
abef340a 1012(define-derived-mode occur-mode special-mode "Occur"
698e1804 1013 "Major mode for output from \\[occur].
0081c8a1
RS
1014\\<occur-mode-map>Move point to one of the items in this buffer, then use
1015\\[occur-mode-goto-occurrence] to go to the occurrence that the item refers to.
1016Alternatively, click \\[occur-mode-mouse-goto] on an item to go to it.
1017
698e1804 1018\\{occur-mode-map}"
f601efb0 1019 (set (make-local-variable 'revert-buffer-function) 'occur-revert-function)
abef340a
SS
1020 (setq next-error-function 'occur-next-error))
1021
60e56523
LL
1022\f
1023;;; Occur Edit mode
1024
1025(defvar occur-edit-mode-map
1026 (let ((map (make-sparse-keymap)))
1027 (set-keymap-parent map text-mode-map)
1028 (define-key map [mouse-2] 'occur-mode-mouse-goto)
8c0f49f0
CY
1029 (define-key map "\C-c\C-c" 'occur-cease-edit)
1030 (define-key map "\C-o" 'occur-mode-display-occurrence)
60e56523 1031 (define-key map "\C-c\C-f" 'next-error-follow-minor-mode)
1ec4b7b2 1032 (bindings--define-key map [menu-bar occur] (cons "Occur" occur-menu-map))
60e56523
LL
1033 map)
1034 "Keymap for `occur-edit-mode'.")
1035
1036(define-derived-mode occur-edit-mode occur-mode "Occur-Edit"
1037 "Major mode for editing *Occur* buffers.
1038In this mode, changes to the *Occur* buffer are also applied to
1039the originating buffer.
1040
08d355e3 1041To return to ordinary Occur mode, use \\[occur-cease-edit]."
60e56523 1042 (setq buffer-read-only nil)
8c0f49f0
CY
1043 (add-hook 'after-change-functions 'occur-after-change-function nil t)
1044 (message (substitute-command-keys
1045 "Editing: Type \\[occur-cease-edit] to return to Occur mode.")))
1046
1047(defun occur-cease-edit ()
1048 "Switch from Occur Edit mode to Occur mode."
1049 (interactive)
1050 (when (derived-mode-p 'occur-edit-mode)
1051 (occur-mode)
1052 (message "Switching to Occur mode.")))
60e56523
LL
1053
1054(defun occur-after-change-function (beg end length)
1055 (save-excursion
1056 (goto-char beg)
8c0f49f0
CY
1057 (let* ((line-beg (line-beginning-position))
1058 (m (get-text-property line-beg 'occur-target))
60e56523 1059 (buf (marker-buffer m))
8c0f49f0
CY
1060 col)
1061 (when (and (get-text-property line-beg 'occur-prefix)
1062 (not (get-text-property end 'occur-prefix)))
1063 (when (= length 0)
1064 ;; Apply occur-target property to inserted (e.g. yanked) text.
1065 (put-text-property beg end 'occur-target m)
1066 ;; Did we insert a newline? Occur Edit mode can't create new
1067 ;; Occur entries; just discard everything after the newline.
1068 (save-excursion
1069 (and (search-forward "\n" end t)
1070 (delete-region (1- (point)) end))))
1071 (let* ((line (- (line-number-at-pos)
1072 (line-number-at-pos (window-start))))
1073 (readonly (with-current-buffer buf buffer-read-only))
1074 (win (or (get-buffer-window buf)
90749b53
CY
1075 (display-buffer buf
1076 '(nil (inhibit-same-window . t)
1077 (inhibit-switch-frame . t)))))
8c0f49f0
CY
1078 (line-end (line-end-position))
1079 (text (save-excursion
1080 (goto-char (next-single-property-change
1081 line-beg 'occur-prefix nil
1082 line-end))
1083 (setq col (- (point) line-beg))
1084 (buffer-substring-no-properties (point) line-end))))
1085 (with-selected-window win
1086 (goto-char m)
1087 (recenter line)
1088 (if readonly
1089 (message "Buffer `%s' is read only." buf)
1090 (delete-region (line-beginning-position) (line-end-position))
1091 (insert text))
1092 (move-to-column col)))))))
60e56523
LL
1093
1094\f
06b60517 1095(defun occur-revert-function (_ignore1 _ignore2)
46b3d18e 1096 "Handle `revert-buffer' for Occur mode buffers."
e1690783 1097 (apply 'occur-1 (append occur-revert-arguments (list (buffer-name)))))
a41284da 1098
78bead73 1099(defun occur-mode-find-occurrence ()
46b3d18e
RS
1100 (let ((pos (get-text-property (point) 'occur-target)))
1101 (unless pos
68608d9c 1102 (error "No occurrence on this line"))
46b3d18e
RS
1103 (unless (buffer-live-p (marker-buffer pos))
1104 (error "Buffer for this occurrence was killed"))
1105 pos))
78bead73 1106
cedbd3f0
SM
1107(defalias 'occur-mode-mouse-goto 'occur-mode-goto-occurrence)
1108(defun occur-mode-goto-occurrence (&optional event)
3199b96f 1109 "Go to the occurrence on the current line."
cedbd3f0
SM
1110 (interactive (list last-nonmenu-event))
1111 (let ((pos
1112 (if (null event)
1113 ;; Actually `event-end' works correctly with a nil argument as
1114 ;; well, so we could dispense with this test, but let's not
1115 ;; rely on this undocumented behavior.
1116 (occur-mode-find-occurrence)
1117 (with-current-buffer (window-buffer (posn-window (event-end event)))
1118 (save-excursion
1119 (goto-char (posn-point (event-end event)))
3199b96f 1120 (occur-mode-find-occurrence))))))
17bb0a2d 1121 (pop-to-buffer (marker-buffer pos))
8e62d5e8
CD
1122 (goto-char pos)
1123 (run-hooks 'occur-mode-find-occurrence-hook)))
8d15583f 1124
029024e2
RS
1125(defun occur-mode-goto-occurrence-other-window ()
1126 "Go to the occurrence the current line describes, in another window."
1127 (interactive)
46b3d18e
RS
1128 (let ((pos (occur-mode-find-occurrence)))
1129 (switch-to-buffer-other-window (marker-buffer pos))
8e62d5e8
CD
1130 (goto-char pos)
1131 (run-hooks 'occur-mode-find-occurrence-hook)))
029024e2 1132
365486d6
RS
1133(defun occur-mode-display-occurrence ()
1134 "Display in another window the occurrence the current line describes."
1135 (interactive)
46b3d18e 1136 (let ((pos (occur-mode-find-occurrence))
3199b96f
CY
1137 window)
1138 (setq window (display-buffer (marker-buffer pos) t))
365486d6
RS
1139 ;; This is the way to set point in the proper window.
1140 (save-selected-window
1141 (select-window window)
8e62d5e8
CD
1142 (goto-char pos)
1143 (run-hooks 'occur-mode-find-occurrence-hook))))
365486d6 1144
123d5548 1145(defun occur-find-match (n search message)
8d15583f
RS
1146 (if (not n) (setq n 1))
1147 (let ((r))
1148 (while (> n 0)
123d5548
JB
1149 (setq r (funcall search (point) 'occur-match))
1150 (and r
1151 (get-text-property r 'occur-match)
1152 (setq r (funcall search r 'occur-match)))
8d15583f 1153 (if r
123d5548
JB
1154 (goto-char r)
1155 (error message))
8d15583f
RS
1156 (setq n (1- n)))))
1157
123d5548
JB
1158(defun occur-next (&optional n)
1159 "Move to the Nth (default 1) next match in an Occur mode buffer."
1160 (interactive "p")
1161 (occur-find-match n #'next-single-property-change "No more matches"))
1162
8d15583f 1163(defun occur-prev (&optional n)
46b3d18e 1164 "Move to the Nth (default 1) previous match in an Occur mode buffer."
8d15583f 1165 (interactive "p")
123d5548 1166 (occur-find-match n #'previous-single-property-change "No earlier matches"))
423e4de7
KS
1167
1168(defun occur-next-error (&optional argp reset)
1169 "Move to the Nth (default 1) next match in an Occur mode buffer.
1170Compatibility function for \\[next-error] invocations."
1171 (interactive "p")
5f9e0ca5 1172 ;; we need to run occur-find-match from within the Occur buffer
f1f007dc 1173 (with-current-buffer
f42a241b 1174 ;; Choose the buffer and make it current.
5f9e0ca5
TZ
1175 (if (next-error-buffer-p (current-buffer))
1176 (current-buffer)
f42a241b
RS
1177 (next-error-find-buffer nil nil
1178 (lambda ()
1179 (eq major-mode 'occur-mode))))
f1f007dc
JL
1180
1181 (goto-char (cond (reset (point-min))
1182 ((< argp 0) (line-beginning-position))
6c6605b2
JL
1183 ((> argp 0) (line-end-position))
1184 ((point))))
5f9e0ca5 1185 (occur-find-match
f1f007dc
JL
1186 (abs argp)
1187 (if (> 0 argp)
5f9e0ca5
TZ
1188 #'previous-single-property-change
1189 #'next-single-property-change)
1190 "No more matches")
1191 ;; In case the *Occur* buffer is visible in a nonselected window.
084c41ca
SM
1192 (let ((win (get-buffer-window (current-buffer) t)))
1193 (if win (set-window-point win (point))))
5f9e0ca5 1194 (occur-mode-goto-occurrence)))
4c53bd2b 1195\f
aaaecfcd
JL
1196(defface match
1197 '((((class color) (min-colors 88) (background light))
5183d4c9 1198 :background "yellow1")
aaaecfcd 1199 (((class color) (min-colors 88) (background dark))
4bc30b74 1200 :background "RoyalBlue3")
330167fc
RS
1201 (((class color) (min-colors 8) (background light))
1202 :background "yellow" :foreground "black")
1203 (((class color) (min-colors 8) (background dark))
aaaecfcd
JL
1204 :background "blue" :foreground "white")
1205 (((type tty) (class mono))
1206 :inverse-video t)
1207 (t :background "gray"))
1208 "Face used to highlight matches permanently."
1209 :group 'matching
bf247b6e 1210 :version "22.1")
aaaecfcd 1211
9d325ebf 1212(defcustom list-matching-lines-default-context-lines 0
9201cc28 1213 "Default number of context lines included around `list-matching-lines' matches.
e730be7f 1214A negative number means to include that many lines before the match.
9d325ebf
RS
1215A positive number means to include that many lines both before and after."
1216 :type 'integer
1217 :group 'matching)
698e1804 1218
31e1d920 1219(defalias 'list-matching-lines 'occur)
698e1804 1220
aaaecfcd 1221(defcustom list-matching-lines-face 'match
9201cc28 1222 "Face used by \\[list-matching-lines] to show the text that matches.
68608d9c
CW
1223If the value is nil, don't highlight the matching portions specially."
1224 :type 'face
1225 :group 'matching)
1226
1227(defcustom list-matching-lines-buffer-name-face 'underline
9201cc28 1228 "Face used by \\[list-matching-lines] to show the names of buffers.
68608d9c
CW
1229If the value is nil, don't highlight the buffer names specially."
1230 :type 'face
1231 :group 'matching)
1232
ddfa3cb4
JL
1233(defcustom list-matching-lines-prefix-face 'shadow
1234 "Face used by \\[list-matching-lines] to show the prefix column.
1235If the face doesn't differ from the default face,
1236don't highlight the prefix with line numbers specially."
1237 :type 'face
1238 :group 'matching
1239 :version "24.4")
1240
8b363e6f
JL
1241(defcustom occur-excluded-properties
1242 '(read-only invisible intangible field mouse-face help-echo local-map keymap
1243 yank-handler follow-link)
9201cc28 1244 "Text properties to discard when copying lines to the *Occur* buffer.
8b363e6f
JL
1245The value should be a list of text properties to discard or t,
1246which means to discard all text properties."
1247 :type '(choice (const :tag "All" t) (repeat symbol))
1248 :group 'matching
1249 :version "22.1")
1250
68608d9c 1251(defun occur-read-primary-args ()
15af15e5
TO
1252 (let* ((perform-collect (consp current-prefix-arg))
1253 (regexp (read-regexp (if perform-collect
1254 "Collect strings matching regexp"
1255 "List lines matching regexp")
24da7273 1256 'regexp-history-last)))
15af15e5
TO
1257 (list regexp
1258 (if perform-collect
1259 ;; Perform collect operation
1260 (if (zerop (regexp-opt-depth regexp))
1261 ;; No subexpression so collect the entire match.
1262 "\\&"
1263 ;; Get the regexp for collection pattern.
1264 (let ((default (car occur-collect-regexp-history)))
eb2deaff 1265 (read-regexp
15af15e5 1266 (format "Regexp to collect (default %s): " default)
eb2deaff 1267 default 'occur-collect-regexp-history)))
15af15e5
TO
1268 ;; Otherwise normal occur takes numerical prefix argument.
1269 (when current-prefix-arg
1270 (prefix-numeric-value current-prefix-arg))))))
c9daced0 1271
a653724b 1272(defun occur-rename-buffer (&optional unique-p interactive-p)
d99118b0 1273 "Rename the current *Occur* buffer to *Occur: original-buffer-name*.
47c88c06 1274Here `original-buffer-name' is the buffer name where Occur was originally run.
a653724b
JB
1275When given the prefix argument, or called non-interactively, the renaming
1276will not clobber the existing buffer(s) of that name, but use
1277`generate-new-buffer-name' instead. You can add this to `occur-hook'
1278if you always want a separate *Occur* buffer for each buffer where you
1279invoke `occur'."
1280 (interactive "P\np")
d99118b0
SS
1281 (with-current-buffer
1282 (if (eq major-mode 'occur-mode) (current-buffer) (get-buffer "*Occur*"))
1283 (rename-buffer (concat "*Occur: "
1284 (mapconcat #'buffer-name
1285 (car (cddr occur-revert-arguments)) "/")
1286 "*")
a653724b 1287 (or unique-p (not interactive-p)))))
d99118b0 1288
698e1804 1289(defun occur (regexp &optional nlines)
99976f85 1290 "Show all lines in the current buffer containing a match for REGEXP.
774642e5 1291If a match spreads across multiple lines, all those lines are shown.
698e1804 1292
da44e784
RM
1293Each line is displayed with NLINES lines before and after, or -NLINES
1294before if NLINES is negative.
1295NLINES defaults to `list-matching-lines-default-context-lines'.
698e1804
RS
1296Interactively it is the prefix arg.
1297
4c53bd2b 1298The lines are shown in a buffer named `*Occur*'.
698e1804 1299It serves as a menu to find any of the occurrences in this buffer.
de3c9b09 1300\\<occur-mode-map>\\[describe-mode] in that buffer will explain how.
9483d601 1301
3be42fcd 1302If REGEXP contains upper case characters (excluding those preceded by `\\')
15af15e5
TO
1303and `search-upper-case' is non-nil, the matching is case-sensitive.
1304
1305When NLINES is a string or when the function is called
1306interactively with prefix argument without a number (`C-u' alone
1307as prefix) the matching strings are collected into the `*Occur*'
1308buffer by using NLINES as a replacement regexp. NLINES may
1309contain \\& and \\N which convention follows `replace-match'.
1310For example, providing \"defun\\s +\\(\\S +\\)\" for REGEXP and
1311\"\\1\" for NLINES collects all the function names in a lisp
1312program. When there is no parenthesized subexpressions in REGEXP
66ec2442
BG
1313the entire match is collected. In any case the searched buffer
1314is not modified."
68608d9c
CW
1315 (interactive (occur-read-primary-args))
1316 (occur-1 regexp nlines (list (current-buffer))))
1317
06b60517
JB
1318(defvar ido-ignore-item-temp-list)
1319
68608d9c
CW
1320(defun multi-occur (bufs regexp &optional nlines)
1321 "Show all lines in buffers BUFS containing a match for REGEXP.
1322This function acts on multiple buffers; otherwise, it is exactly like
191b577e 1323`occur'. When you invoke this command interactively, you must specify
5cf56143
LMI
1324the buffer names that you want, one by one.
1325See also `multi-occur-in-matching-buffers'."
a5dfed3e 1326 (interactive
68608d9c 1327 (cons
52698d45
KS
1328 (let* ((bufs (list (read-buffer "First buffer to search: "
1329 (current-buffer) t)))
1330 (buf nil)
1331 (ido-ignore-item-temp-list bufs))
68608d9c 1332 (while (not (string-equal
f1180544 1333 (setq buf (read-buffer
52698d45
KS
1334 (if (eq read-buffer-function 'ido-read-buffer)
1335 "Next buffer to search (C-j to end): "
1336 "Next buffer to search (RET to end): ")
1337 nil t))
68608d9c 1338 ""))
52698d45
KS
1339 (add-to-list 'bufs buf)
1340 (setq ido-ignore-item-temp-list bufs))
68608d9c
CW
1341 (nreverse (mapcar #'get-buffer bufs)))
1342 (occur-read-primary-args)))
1343 (occur-1 regexp nlines bufs))
1344
191b577e
RS
1345(defun multi-occur-in-matching-buffers (bufregexp regexp &optional allbufs)
1346 "Show all lines matching REGEXP in buffers specified by BUFREGEXP.
1347Normally BUFREGEXP matches against each buffer's visited file name,
1348but if you specify a prefix argument, it matches against the buffer name.
68608d9c
CW
1349See also `multi-occur'."
1350 (interactive
1351 (cons
1352 (let* ((default (car regexp-history))
1353 (input
eb2deaff 1354 (read-regexp
689f4394 1355 (if current-prefix-arg
191b577e 1356 "List lines in buffers whose names match regexp: "
eb2deaff 1357 "List lines in buffers whose filenames match regexp: "))))
68608d9c
CW
1358 (if (equal input "")
1359 default
1360 input))
1361 (occur-read-primary-args)))
1362 (when bufregexp
689f4394 1363 (occur-1 regexp nil
68608d9c
CW
1364 (delq nil
1365 (mapcar (lambda (buf)
191b577e
RS
1366 (when (if allbufs
1367 (string-match bufregexp
1368 (buffer-name buf))
1369 (and (buffer-file-name buf)
1370 (string-match bufregexp
1371 (buffer-file-name buf))))
68608d9c
CW
1372 buf))
1373 (buffer-list))))))
1374
e1690783 1375(defun occur-1 (regexp nlines bufs &optional buf-name)
360289a6
JL
1376 (unless (and regexp (not (equal regexp "")))
1377 (error "Occur doesn't work with the empty regexp"))
e1690783
CW
1378 (unless buf-name
1379 (setq buf-name "*Occur*"))
f42a241b 1380 (let (occur-buf
70ed2a76
CW
1381 (active-bufs (delq nil (mapcar #'(lambda (buf)
1382 (when (buffer-live-p buf) buf))
1383 bufs))))
1384 ;; Handle the case where one of the buffers we're searching is the
f42a241b
RS
1385 ;; output buffer. Just rename it.
1386 (when (member buf-name (mapcar 'buffer-name active-bufs))
1387 (with-current-buffer (get-buffer buf-name)
1388 (rename-uniquely)))
1389
1390 ;; Now find or create the output buffer.
1391 ;; If we just renamed that buffer, we will make a new one here.
1392 (setq occur-buf (get-buffer-create buf-name))
1393
68608d9c 1394 (with-current-buffer occur-buf
15af15e5 1395 (if (stringp nlines)
e1dbe924 1396 (fundamental-mode) ;; This is for collect operation.
15af15e5 1397 (occur-mode))
8121414a
CY
1398 (let ((inhibit-read-only t)
1399 ;; Don't generate undo entries for creation of the initial contents.
1400 (buffer-undo-list t))
06df7f87 1401 (erase-buffer)
15af15e5
TO
1402 (let ((count
1403 (if (stringp nlines)
1404 ;; Treat nlines as a regexp to collect.
1405 (let ((bufs active-bufs)
1406 (count 0))
1407 (while bufs
1408 (with-current-buffer (car bufs)
1409 (save-excursion
1410 (goto-char (point-min))
1411 (while (re-search-forward regexp nil t)
1412 ;; Insert the replacement regexp.
1413 (let ((str (match-substitute-replacement nlines)))
1414 (if str
1415 (with-current-buffer occur-buf
1416 (insert str)
1417 (setq count (1+ count))
1418 (or (zerop (current-column))
1419 (insert "\n"))))))))
1420 (setq bufs (cdr bufs)))
1421 count)
1422 ;; Perform normal occur.
1423 (occur-engine
1424 regexp active-bufs occur-buf
1425 (or nlines list-matching-lines-default-context-lines)
1426 (if (and case-fold-search search-upper-case)
1427 (isearch-no-upper-case-p regexp t)
1428 case-fold-search)
1429 list-matching-lines-buffer-name-face
ddfa3cb4
JL
1430 (if (face-differs-from-default-p list-matching-lines-prefix-face)
1431 list-matching-lines-prefix-face)
1432 list-matching-lines-face
15af15e5 1433 (not (eq occur-excluded-properties t))))))
06df7f87
EZ
1434 (let* ((bufcount (length active-bufs))
1435 (diff (- (length bufs) bufcount)))
d66ecdbb 1436 (message "Searched %d buffer%s%s; %s match%s%s"
06df7f87
EZ
1437 bufcount (if (= bufcount 1) "" "s")
1438 (if (zerop diff) "" (format " (%d killed)" diff))
1439 (if (zerop count) "no" (format "%d" count))
1440 (if (= count 1) "" "es")
d66ecdbb
JL
1441 ;; Don't display regexp if with remaining text
1442 ;; it is longer than window-width.
1443 (if (> (+ (length regexp) 42) (window-width))
1444 "" (format " for `%s'" (query-replace-descr regexp)))))
06df7f87 1445 (setq occur-revert-arguments (list regexp nlines bufs))
c7d2f2cc
JB
1446 (if (= count 0)
1447 (kill-buffer occur-buf)
1448 (display-buffer occur-buf)
1449 (setq next-error-last-buffer occur-buf)
1450 (setq buffer-read-only t)
1451 (set-buffer-modified-p nil)
1452 (run-hooks 'occur-hook)))))))
68608d9c 1453
06b60517 1454(defun occur-engine (regexp buffers out-buf nlines case-fold
46b3d18e
RS
1455 title-face prefix-face match-face keep-props)
1456 (with-current-buffer out-buf
ac44d6c1
JL
1457 (let ((global-lines 0) ;; total count of matching lines
1458 (global-matches 0) ;; total count of matches
06b60517
JB
1459 (coding nil)
1460 (case-fold-search case-fold))
46b3d18e
RS
1461 ;; Map over all the buffers
1462 (dolist (buf buffers)
1463 (when (buffer-live-p buf)
ac44d6c1
JL
1464 (let ((lines 0) ;; count of matching lines
1465 (matches 0) ;; count of matches
1466 (curr-line 1) ;; line count
1467 (prev-line nil) ;; line number of prev match endpt
1468 (prev-after-lines nil) ;; context lines of prev match
46b3d18e 1469 (matchbeg 0)
46b3d18e
RS
1470 (origpt nil)
1471 (begpt nil)
1472 (endpt nil)
1473 (marker nil)
1474 (curstring "")
dc2d2590 1475 (ret nil)
bc16bf5e 1476 (inhibit-field-text-motion t)
46b3d18e 1477 (headerpt (with-current-buffer out-buf (point))))
cedbd3f0 1478 (with-current-buffer buf
5cb4031d
KH
1479 (or coding
1480 ;; Set CODING only if the current buffer locally
1481 ;; binds buffer-file-coding-system.
1482 (not (local-variable-p 'buffer-file-coding-system))
1483 (setq coding buffer-file-coding-system))
68608d9c 1484 (save-excursion
46b3d18e
RS
1485 (goto-char (point-min)) ;; begin searching in the buffer
1486 (while (not (eobp))
1487 (setq origpt (point))
1488 (when (setq endpt (re-search-forward regexp nil t))
ac44d6c1 1489 (setq lines (1+ lines)) ;; increment matching lines count
5291cbca 1490 (setq matchbeg (match-beginning 0))
774642e5 1491 ;; Get beginning of first match line and end of the last.
f1f007dc
JL
1492 (save-excursion
1493 (goto-char matchbeg)
774642e5
JL
1494 (setq begpt (line-beginning-position))
1495 (goto-char endpt)
1496 (setq endpt (line-end-position)))
1497 ;; Sum line numbers up to the first match line.
ac44d6c1 1498 (setq curr-line (+ curr-line (count-lines origpt begpt)))
46b3d18e
RS
1499 (setq marker (make-marker))
1500 (set-marker marker matchbeg)
53e87c57 1501 (setq curstring (occur-engine-line begpt endpt keep-props))
8b363e6f 1502 ;; Highlight the matches
46b3d18e
RS
1503 (let ((len (length curstring))
1504 (start 0))
46b3d18e
RS
1505 (while (and (< start len)
1506 (string-match regexp curstring start))
ac44d6c1 1507 (setq matches (1+ matches))
f1f007dc
JL
1508 (add-text-properties
1509 (match-beginning 0) (match-end 0)
501158bc
JL
1510 '(occur-match t) curstring)
1511 (when match-face
1512 ;; Add `match-face' to faces copied from the buffer.
1513 (add-face-text-property
1514 (match-beginning 0) (match-end 0)
1515 match-face nil curstring))
50ff2e06
CY
1516 ;; Avoid infloop (Bug#7593).
1517 (let ((end (match-end 0)))
1518 (setq start (if (= start end) (1+ start) end)))))
46b3d18e 1519 ;; Generate the string to insert for this match
774642e5
JL
1520 (let* ((match-prefix
1521 ;; Using 7 digits aligns tabs properly.
ac44d6c1 1522 (apply #'propertize (format "%7d:" curr-line)
774642e5
JL
1523 (append
1524 (when prefix-face
ddfa3cb4 1525 `(font-lock-face ,prefix-face))
774642e5 1526 `(occur-prefix t mouse-face (highlight)
8c0f49f0
CY
1527 ;; Allow insertion of text at
1528 ;; the end of the prefix (for
1529 ;; Occur Edit mode).
1530 front-sticky t rear-nonsticky t
1531 occur-target ,marker follow-link t
1532 help-echo "mouse-2: go to this occurrence"))))
774642e5
JL
1533 (match-str
1534 ;; We don't put `mouse-face' on the newline,
1535 ;; because that loses. And don't put it
1536 ;; on context lines to reduce flicker.
1537 (propertize curstring 'mouse-face (list 'highlight)
1538 'occur-target marker
1539 'follow-link t
1540 'help-echo
1541 "mouse-2: go to this occurrence"))
1542 (out-line
46b3d18e 1543 (concat
774642e5
JL
1544 match-prefix
1545 ;; Add non-numeric prefix to all non-first lines
1546 ;; of multi-line matches.
1547 (replace-regexp-in-string
1548 "\n"
ddfa3cb4
JL
1549 (if prefix-face
1550 (propertize "\n :" 'font-lock-face prefix-face)
1551 "\n :")
774642e5 1552 match-str)
61f570e2
RF
1553 ;; Add marker at eol, but no mouse props.
1554 (propertize "\n" 'occur-target marker)))
46b3d18e
RS
1555 (data
1556 (if (= nlines 0)
1557 ;; The simple display style
1558 out-line
f8edc67e 1559 ;; The complex multi-line display style.
dc2d2590
JL
1560 (setq ret (occur-context-lines
1561 out-line nlines keep-props begpt endpt
ac44d6c1 1562 curr-line prev-line prev-after-lines
ddfa3cb4 1563 prefix-face))
dc2d2590
JL
1564 ;; Set first elem of the returned list to `data',
1565 ;; and the second elem to `prev-after-lines'.
1566 (setq prev-after-lines (nth 1 ret))
1567 (nth 0 ret))))
46b3d18e
RS
1568 ;; Actually insert the match display data
1569 (with-current-buffer out-buf
06b60517 1570 (insert data)))
46b3d18e 1571 (goto-char endpt))
e1690783
CW
1572 (if endpt
1573 (progn
774642e5 1574 ;; Sum line numbers between first and last match lines.
ac44d6c1
JL
1575 (setq curr-line (+ curr-line (count-lines begpt endpt)
1576 ;; Add 1 for empty last match line since
1577 ;; count-lines returns 1 line less.
1578 (if (and (bolp) (eolp)) 1 0)))
e1690783
CW
1579 ;; On to the next match...
1580 (forward-line 1))
dc2d2590 1581 (goto-char (point-max)))
ac44d6c1 1582 (setq prev-line (1- curr-line)))
dc2d2590
JL
1583 ;; Flush remaining context after-lines.
1584 (when prev-after-lines
1585 (with-current-buffer out-buf
1586 (insert (apply #'concat (occur-engine-add-prefix
ddfa3cb4 1587 prev-after-lines prefix-face)))))))
ac44d6c1
JL
1588 (when (not (zerop lines)) ;; is the count zero?
1589 (setq global-lines (+ global-lines lines)
1590 global-matches (+ global-matches matches))
46b3d18e
RS
1591 (with-current-buffer out-buf
1592 (goto-char headerpt)
1593 (let ((beg (point))
1594 end)
60e56523 1595 (insert (propertize
ac44d6c1 1596 (format "%d match%s%s%s in buffer: %s\n"
60e56523 1597 matches (if (= matches 1) "" "es")
ac44d6c1
JL
1598 ;; Don't display the same number of lines
1599 ;; and matches in case of 1 match per line.
1600 (if (= lines matches)
1601 "" (format " in %d line%s"
1602 lines (if (= lines 1) "" "s")))
60e56523
LL
1603 ;; Don't display regexp for multi-buffer.
1604 (if (> (length buffers) 1)
1605 "" (format " for \"%s\""
1606 (query-replace-descr regexp)))
1607 (buffer-name buf))
1608 'read-only t))
46b3d18e 1609 (setq end (point))
501158bc
JL
1610 (add-text-properties beg end `(occur-title ,buf))
1611 (when title-face
1612 (add-face-text-property beg end title-face)))
46b3d18e 1613 (goto-char (point-min)))))))
d66ecdbb 1614 ;; Display total match count and regexp for multi-buffer.
ac44d6c1 1615 (when (and (not (zerop global-lines)) (> (length buffers) 1))
d66ecdbb
JL
1616 (goto-char (point-min))
1617 (let ((beg (point))
1618 end)
ac44d6c1
JL
1619 (insert (format "%d match%s%s total for \"%s\":\n"
1620 global-matches (if (= global-matches 1) "" "es")
1621 ;; Don't display the same number of lines
1622 ;; and matches in case of 1 match per line.
1623 (if (= global-lines global-matches)
1624 "" (format " in %d line%s"
1625 global-lines (if (= global-lines 1) "" "s")))
d66ecdbb
JL
1626 (query-replace-descr regexp)))
1627 (setq end (point))
501158bc
JL
1628 (when title-face
1629 (add-face-text-property beg end title-face)))
d66ecdbb 1630 (goto-char (point-min)))
5cb4031d
KH
1631 (if coding
1632 ;; CODING is buffer-file-coding-system of the first buffer
1633 ;; that locally binds it. Let's use it also for the output
1634 ;; buffer.
1635 (set-buffer-file-coding-system coding))
46b3d18e 1636 ;; Return the number of matches
ac44d6c1 1637 global-matches)))
68608d9c 1638
53e87c57 1639(defun occur-engine-line (beg end &optional keep-props)
f14d1172
JL
1640 (if (and keep-props (if (boundp 'jit-lock-mode) jit-lock-mode)
1641 (text-property-not-all beg end 'fontified t))
1642 (if (fboundp 'jit-lock-fontify-now)
1643 (jit-lock-fontify-now beg end)))
1644 (if (and keep-props (not (eq occur-excluded-properties t)))
1645 (let ((str (buffer-substring beg end)))
1646 (remove-list-of-text-properties
1647 0 (length str) occur-excluded-properties str)
1648 str)
1649 (buffer-substring-no-properties beg end)))
1650
ddfa3cb4 1651(defun occur-engine-add-prefix (lines &optional prefix-face)
0ef84fc8
JL
1652 (mapcar
1653 #'(lambda (line)
ddfa3cb4
JL
1654 (concat (if prefix-face
1655 (propertize " :" 'font-lock-face prefix-face)
1656 " :")
1657 line "\n"))
0ef84fc8
JL
1658 lines))
1659
1660(defun occur-accumulate-lines (count &optional keep-props pt)
1661 (save-excursion
1662 (when pt
1663 (goto-char pt))
1664 (let ((forwardp (> count 0))
1665 result beg end moved)
1666 (while (not (or (zerop count)
1667 (if forwardp
1668 (eobp)
1669 (and (bobp) (not moved)))))
1670 (setq count (+ count (if forwardp -1 1)))
1671 (setq beg (line-beginning-position)
1672 end (line-end-position))
1673 (push (occur-engine-line beg end keep-props) result)
1674 (setq moved (= 0 (forward-line (if forwardp 1 -1)))))
1675 (nreverse result))))
1676
f8edc67e
RS
1677;; Generate context display for occur.
1678;; OUT-LINE is the line where the match is.
1679;; NLINES and KEEP-PROPS are args to occur-engine.
ac44d6c1
JL
1680;; CURR-LINE is line count of the current match,
1681;; PREV-LINE is line count of the previous match,
dc2d2590 1682;; PREV-AFTER-LINES is a list of after-context lines of the previous match.
f8edc67e
RS
1683;; Generate a list of lines, add prefixes to all but OUT-LINE,
1684;; then concatenate them all together.
dc2d2590 1685(defun occur-context-lines (out-line nlines keep-props begpt endpt
ac44d6c1 1686 curr-line prev-line prev-after-lines
ddfa3cb4 1687 &optional prefix-face)
dc2d2590
JL
1688 ;; Find after- and before-context lines of the current match.
1689 (let ((before-lines
1690 (nreverse (cdr (occur-accumulate-lines
1691 (- (1+ (abs nlines))) keep-props begpt))))
1692 (after-lines
1693 (cdr (occur-accumulate-lines
1694 (1+ nlines) keep-props endpt)))
1695 separator)
1696
1697 ;; Combine after-lines of the previous match
1698 ;; with before-lines of the current match.
1699
1700 (when prev-after-lines
1701 ;; Don't overlap prev after-lines with current before-lines.
ac44d6c1
JL
1702 (if (>= (+ prev-line (length prev-after-lines))
1703 (- curr-line (length before-lines)))
dc2d2590
JL
1704 (setq prev-after-lines
1705 (butlast prev-after-lines
1706 (- (length prev-after-lines)
ac44d6c1 1707 (- curr-line prev-line (length before-lines) 1))))
dc2d2590
JL
1708 ;; Separate non-overlapping context lines with a dashed line.
1709 (setq separator "-------\n")))
1710
ac44d6c1 1711 (when prev-line
dc2d2590 1712 ;; Don't overlap current before-lines with previous match line.
ac44d6c1
JL
1713 (if (<= (- curr-line (length before-lines))
1714 prev-line)
dc2d2590
JL
1715 (setq before-lines
1716 (nthcdr (- (length before-lines)
ac44d6c1 1717 (- curr-line prev-line 1))
dc2d2590
JL
1718 before-lines))
1719 ;; Separate non-overlapping before-context lines.
1720 (unless (> nlines 0)
1721 (setq separator "-------\n"))))
1722
1723 (list
1724 ;; Return a list where the first element is the output line.
1725 (apply #'concat
1726 (append
ddfa3cb4
JL
1727 (if prev-after-lines
1728 (occur-engine-add-prefix prev-after-lines prefix-face))
1729 (if separator
1730 (list (if prefix-face
1731 (propertize separator 'font-lock-face prefix-face)
1732 separator)))
1733 (occur-engine-add-prefix before-lines prefix-face)
dc2d2590
JL
1734 (list out-line)))
1735 ;; And the second element is the list of context after-lines.
1736 (if (> nlines 0) after-lines))))
1737
698e1804 1738\f
81bdc14d
RS
1739;; It would be nice to use \\[...], but there is no reasonable way
1740;; to make that display both SPC and Y.
698e1804
RS
1741(defconst query-replace-help
1742 "Type Space or `y' to replace one match, Delete or `n' to skip to next,
be44f62c 1743RET or `q' to exit, Period to replace one match and exit,
698e1804
RS
1744Comma to replace but not move point immediately,
1745C-r to enter recursive edit (\\[exit-recursive-edit] to get out again),
1746C-w to delete match and recursive edit,
1747C-l to clear the screen, redisplay, and offer same replacement again,
e5a94ec4 1748! to replace all remaining matches in this buffer with no more questions,
7ce278f3 1749^ to move point back to previous match,
e5a94ec4
JL
1750E to edit the replacement string.
1751In multi-buffer replacements type `Y' to replace all remaining
1752matches in all remaining buffers with no more questions,
1753`N' to skip to the next buffer without replacing remaining matches
1754in the current buffer."
f54701d1 1755 "Help message while in `query-replace'.")
698e1804 1756
cedbd3f0
SM
1757(defvar query-replace-map
1758 (let ((map (make-sparse-keymap)))
1759 (define-key map " " 'act)
1760 (define-key map "\d" 'skip)
1761 (define-key map [delete] 'skip)
1762 (define-key map [backspace] 'skip)
1763 (define-key map "y" 'act)
1764 (define-key map "n" 'skip)
1765 (define-key map "Y" 'act)
1766 (define-key map "N" 'skip)
1767 (define-key map "e" 'edit-replacement)
1768 (define-key map "E" 'edit-replacement)
1769 (define-key map "," 'act-and-show)
1770 (define-key map "q" 'exit)
1771 (define-key map "\r" 'exit)
1772 (define-key map [return] 'exit)
1773 (define-key map "." 'act-and-exit)
1774 (define-key map "\C-r" 'edit)
1775 (define-key map "\C-w" 'delete-and-edit)
1776 (define-key map "\C-l" 'recenter)
1777 (define-key map "!" 'automatic)
1778 (define-key map "^" 'backup)
1779 (define-key map "\C-h" 'help)
1780 (define-key map [f1] 'help)
1781 (define-key map [help] 'help)
1782 (define-key map "?" 'help)
1783 (define-key map "\C-g" 'quit)
1784 (define-key map "\C-]" 'quit)
011474aa
CY
1785 (define-key map "\C-v" 'scroll-up)
1786 (define-key map "\M-v" 'scroll-down)
1787 (define-key map [next] 'scroll-up)
1788 (define-key map [prior] 'scroll-down)
1789 (define-key map [?\C-\M-v] 'scroll-other-window)
1790 (define-key map [M-next] 'scroll-other-window)
1791 (define-key map [?\C-\M-\S-v] 'scroll-other-window-down)
1792 (define-key map [M-prior] 'scroll-other-window-down)
1793 ;; Binding ESC would prohibit the M-v binding. Instead, callers
1794 ;; should check for ESC specially.
1795 ;; (define-key map "\e" 'exit-prefix)
cedbd3f0
SM
1796 (define-key map [escape] 'exit-prefix)
1797 map)
011474aa 1798 "Keymap of responses to questions posed by commands like `query-replace'.
81bdc14d
RS
1799The \"bindings\" in this map are not commands; they are answers.
1800The valid answers include `act', `skip', `act-and-show',
011474aa
CY
1801`act-and-exit', `exit', `exit-prefix', `recenter', `scroll-up',
1802`scroll-down', `scroll-other-window', `scroll-other-window-down',
1803`edit', `edit-replacement', `delete-and-edit', `automatic',
1804`backup', `quit', and `help'.
1805
1806This keymap is used by `y-or-n-p' as well as `query-replace'.")
81bdc14d 1807
b591f338
JL
1808(defvar multi-query-replace-map
1809 (let ((map (make-sparse-keymap)))
1810 (set-keymap-parent map query-replace-map)
1811 (define-key map "Y" 'automatic-all)
1812 (define-key map "N" 'exit-current)
1813 map)
1814 "Keymap that defines additional bindings for multi-buffer replacements.
1815It extends its parent map `query-replace-map' with new bindings to
1816operate on a set of buffers/files. The difference with its parent map
1817is the additional answers `automatic-all' to replace all remaining
1818matches in all remaining buffers with no more questions, and
1819`exit-current' to skip remaining matches in the current buffer
1820and to continue with the next buffer in the sequence.")
1821
84482eb3 1822(defun replace-match-string-symbols (n)
e730be7f
DL
1823 "Process a list (and any sub-lists), expanding certain symbols.
1824Symbol Expands To
1825N (match-string N) (where N is a string of digits)
1826#N (string-to-number (match-string N))
1827& (match-string 0)
1828#& (string-to-number (match-string 0))
2f57bf85 1829# replace-count
e730be7f 1830
97610156 1831Note that these symbols must be preceded by a backslash in order to
f72f9f1a
RS
1832type them using Lisp syntax."
1833 (while (consp n)
84482eb3
RS
1834 (cond
1835 ((consp (car n))
1836 (replace-match-string-symbols (car n))) ;Process sub-list
1837 ((symbolp (car n))
1838 (let ((name (symbol-name (car n))))
1839 (cond
1840 ((string-match "^[0-9]+$" name)
1841 (setcar n (list 'match-string (string-to-number name))))
1842 ((string-match "^#[0-9]+$" name)
1843 (setcar n (list 'string-to-number
1844 (list 'match-string
1845 (string-to-number (substring name 1))))))
1846 ((string= "&" name)
1847 (setcar n '(match-string 0)))
1848 ((string= "#&" name)
2f57bf85
DK
1849 (setcar n '(string-to-number (match-string 0))))
1850 ((string= "#" name)
1851 (setcar n 'replace-count))))))
84482eb3
RS
1852 (setq n (cdr n))))
1853
06b60517
JB
1854(defun replace-eval-replacement (expression count)
1855 (let* ((replace-count count)
1d43dba1
GM
1856 err
1857 (replacement
1858 (condition-case err
1859 (eval expression)
1860 (error
1861 (error "Error evaluating replacement expression: %S" err)))))
84482eb3
RS
1862 (if (stringp replacement)
1863 replacement
1864 (prin1-to-string replacement t))))
1865
2f57bf85
DK
1866(defun replace-quote (replacement)
1867 "Quote a replacement string.
1868This just doubles all backslashes in REPLACEMENT and
1869returns the resulting string. If REPLACEMENT is not
1870a string, it is first passed through `prin1-to-string'
1871with the `noescape' argument set.
1872
1873`match-data' is preserved across the call."
1874 (save-match-data
1875 (replace-regexp-in-string "\\\\" "\\\\"
1876 (if (stringp replacement)
1877 replacement
1878 (prin1-to-string replacement t))
1879 t t)))
1880
06b60517 1881(defun replace-loop-through-replacements (data count)
e4769531 1882 ;; DATA is a vector containing the following values:
84482eb3
RS
1883 ;; 0 next-rotate-count
1884 ;; 1 repeat-count
1885 ;; 2 next-replacement
1886 ;; 3 replacements
06b60517 1887 (if (= (aref data 0) count)
84482eb3 1888 (progn
06b60517 1889 (aset data 0 (+ count (aref data 1)))
84482eb3
RS
1890 (let ((next (cdr (aref data 2))))
1891 (aset data 2 (if (consp next) next (aref data 3))))))
1892 (car (aref data 2)))
1893
7c1c02ac
DK
1894(defun replace-match-data (integers reuse &optional new)
1895 "Like `match-data', but markers in REUSE get invalidated.
6a964bb1 1896If NEW is non-nil, it is set and returned instead of fresh data,
7c1c02ac
DK
1897but coerced to the correct value of INTEGERS."
1898 (or (and new
1899 (progn
1900 (set-match-data new)
1901 (and (eq new reuse)
1902 (eq (null integers) (markerp (car reuse)))
1903 new)))
10ddc30e 1904 (match-data integers reuse t)))
7c1c02ac 1905
3ee4cd64 1906(defun replace-match-maybe-edit (newtext fixedcase literal noedit match-data backward)
7c1c02ac 1907 "Make a replacement with `replace-match', editing `\\?'.
f7a17bb3
LI
1908FIXEDCASE, LITERAL are passed to `replace-match' (which see).
1909After possibly editing it (if `\\?' is present), NEWTEXT is also
1910passed to `replace-match'. If NOEDIT is true, no check for `\\?'
1911is made (to save time). MATCH-DATA is used for the replacement.
1912In case editing is done, it is changed to use markers.
7c1c02ac 1913
6a964bb1 1914The return value is non-nil if there has been no `\\?' or NOEDIT was
7c1c02ac
DK
1915passed in. If LITERAL is set, no checking is done, anyway."
1916 (unless (or literal noedit)
1917 (setq noedit t)
1918 (while (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\(\\\\\\?\\)"
1919 newtext)
1920 (setq newtext
3981e5b5
JB
1921 (read-string "Edit replacement string: "
1922 (prog1
1923 (cons
1924 (replace-match "" t t newtext 3)
1925 (1+ (match-beginning 3)))
1926 (setq match-data
1927 (replace-match-data
1928 nil match-data match-data))))
7c1c02ac
DK
1929 noedit nil)))
1930 (set-match-data match-data)
1931 (replace-match newtext fixedcase literal)
3ee4cd64
JL
1932 ;; `replace-match' leaves point at the end of the replacement text,
1933 ;; so move point to the beginning when replacing backward.
1934 (when backward (goto-char (nth 0 match-data)))
7c1c02ac
DK
1935 noedit)
1936
1ec5e41d 1937(defvar replace-search-function nil
c35a09fc
CY
1938 "Function to use when searching for strings to replace.
1939It is used by `query-replace' and `replace-string', and is called
1940with three arguments, as if it were `search-forward'.")
1941
1ec5e41d 1942(defvar replace-re-search-function nil
c35a09fc
CY
1943 "Function to use when searching for regexps to replace.
1944It is used by `query-replace-regexp', `replace-regexp',
96f606c5
JL
1945`query-replace-regexp-eval', and `map-query-replace-regexp'.
1946It is called with three arguments, as if it were
1947`re-search-forward'.")
c35a09fc 1948
3a52ccf7 1949(defun replace-search (search-string limit regexp-flag delimited-flag
3ee4cd64 1950 case-fold-search backward)
fa6bc6fd 1951 "Search for the next occurrence of SEARCH-STRING to replace."
3a52ccf7
JL
1952 ;; Let-bind global isearch-* variables to values used
1953 ;; to search the next replacement. These let-bindings
1954 ;; should be effective both at the time of calling
1955 ;; `isearch-search-fun-default' and also at the
1956 ;; time of funcalling `search-function'.
1957 ;; These isearch-* bindings can't be placed higher
1958 ;; outside of this function because then another I-search
1959 ;; used after `recursive-edit' might override them.
1960 (let* ((isearch-regexp regexp-flag)
1961 (isearch-word delimited-flag)
1962 (isearch-lax-whitespace
1963 replace-lax-whitespace)
1964 (isearch-regexp-lax-whitespace
1965 replace-regexp-lax-whitespace)
1966 (isearch-case-fold-search case-fold-search)
1967 (isearch-adjusted nil)
1968 (isearch-nonincremental t) ; don't use lax word mode
3ee4cd64 1969 (isearch-forward (not backward))
3a52ccf7
JL
1970 (search-function
1971 (or (if regexp-flag
1972 replace-re-search-function
1973 replace-search-function)
1974 (isearch-search-fun-default))))
1975 (funcall search-function search-string limit t)))
1976
1977(defvar replace-overlay nil)
1978
1979(defun replace-highlight (match-beg match-end range-beg range-end
1980 search-string regexp-flag delimited-flag
3ee4cd64 1981 case-fold-search backward)
3a52ccf7
JL
1982 (if query-replace-highlight
1983 (if replace-overlay
1984 (move-overlay replace-overlay match-beg match-end (current-buffer))
1985 (setq replace-overlay (make-overlay match-beg match-end))
1986 (overlay-put replace-overlay 'priority 1001) ;higher than lazy overlays
1987 (overlay-put replace-overlay 'face 'query-replace)))
1988 (if query-replace-lazy-highlight
1989 (let ((isearch-string search-string)
1990 (isearch-regexp regexp-flag)
1991 (isearch-word delimited-flag)
1992 (isearch-lax-whitespace
1993 replace-lax-whitespace)
1994 (isearch-regexp-lax-whitespace
1995 replace-regexp-lax-whitespace)
1996 (isearch-case-fold-search case-fold-search)
3ee4cd64 1997 (isearch-forward (not backward))
3a52ccf7
JL
1998 (isearch-other-end match-beg)
1999 (isearch-error nil))
2000 (isearch-lazy-highlight-new-loop range-beg range-end))))
2001
2002(defun replace-dehighlight ()
2003 (when replace-overlay
2004 (delete-overlay replace-overlay))
2005 (when query-replace-lazy-highlight
2006 (lazy-highlight-cleanup lazy-highlight-cleanup)
2007 (setq isearch-lazy-highlight-last-string nil))
2008 ;; Close overlays opened by `isearch-range-invisible' in `perform-replace'.
2009 (isearch-clean-overlays))
2010
d99118b0 2011(defun perform-replace (from-string replacements
698e1804 2012 query-flag regexp-flag delimited-flag
3ee4cd64 2013 &optional repeat-count map start end backward)
698e1804
RS
2014 "Subroutine of `query-replace'. Its complexity handles interactive queries.
2015Don't use this in your own program unless you want to query and set the mark
2016just as `query-replace' does. Instead, write a simple loop like this:
698665d1
GM
2017
2018 (while (re-search-forward \"foo[ \\t]+bar\" nil t)
698e1804 2019 (replace-match \"foobar\" nil nil))
698665d1
GM
2020
2021which will run faster and probably do exactly what you want. Please
2022see the documentation of `replace-match' to find out how to simulate
588c915a
CW
2023`case-replace'.
2024
2025This function returns nil if and only if there were no matches to
2026make, or the user didn't cancel the call."
81bdc14d 2027 (or map (setq map query-replace-map))
1c1dadab
RS
2028 (and query-flag minibuffer-auto-raise
2029 (raise-frame (window-frame (minibuffer-window))))
26cc71af 2030 (let* ((case-fold-search
3be42fcd
JL
2031 (if (and case-fold-search search-upper-case)
2032 (isearch-no-upper-case-p from-string regexp-flag)
2033 case-fold-search))
26cc71af
SM
2034 (nocasify (not (and case-replace case-fold-search)))
2035 (literal (or (not regexp-flag) (eq regexp-flag 'literal)))
26cc71af
SM
2036 (search-string from-string)
2037 (real-match-data nil) ; The match data for the current match.
2038 (next-replacement nil)
2039 ;; This is non-nil if we know there is nothing for the user
2040 ;; to edit in the replacement.
2041 (noedit nil)
2042 (keep-going t)
2043 (stack nil)
2044 (replace-count 0)
3c9c9d38
JL
2045 (skip-read-only-count 0)
2046 (skip-filtered-count 0)
2047 (skip-invisible-count 0)
26cc71af 2048 (nonempty-match nil)
b591f338 2049 (multi-buffer nil)
2952b1ae 2050 (recenter-last-op nil) ; Start cycling order with initial position.
26cc71af
SM
2051
2052 ;; If non-nil, it is marker saying where in the buffer to stop.
2053 (limit nil)
2054
2055 ;; Data for the next match. If a cons, it has the same format as
2056 ;; (match-data); otherwise it is t if a match is possible at point.
2057 (match-again t)
2058
2059 (message
2060 (if query-flag
2061 (apply 'propertize
2062 (substitute-command-keys
2063 "Query replacing %s with %s: (\\<query-replace-map>\\[help] for help) ")
2064 minibuffer-prompt-properties))))
7ef5c431
KH
2065
2066 ;; If region is active, in Transient Mark mode, operate on region.
3ee4cd64
JL
2067 (if backward
2068 (when end
2069 (setq limit (copy-marker (min start end)))
2070 (goto-char (max start end))
2071 (deactivate-mark))
2072 (when start
2073 (setq limit (copy-marker (max start end)))
2074 (goto-char (min start end))
2075 (deactivate-mark)))
84482eb3 2076
b591f338
JL
2077 ;; If last typed key in previous call of multi-buffer perform-replace
2078 ;; was `automatic-all', don't ask more questions in next files
1e4bd40d 2079 (when (eq (lookup-key map (vector last-input-event)) 'automatic-all)
b591f338
JL
2080 (setq query-flag nil multi-buffer t))
2081
84482eb3
RS
2082 ;; REPLACEMENTS is either a string, a list of strings, or a cons cell
2083 ;; containing a function and its first argument. The function is
2084 ;; called to generate each replacement like this:
2085 ;; (funcall (car replacements) (cdr replacements) replace-count)
2086 ;; It must return a string.
2087 (cond
2088 ((stringp replacements)
2089 (setq next-replacement replacements
2090 replacements nil))
2091 ((stringp (car replacements)) ; If it isn't a string, it must be a cons
2092 (or repeat-count (setq repeat-count 1))
2093 (setq replacements (cons 'replace-loop-through-replacements
2094 (vector repeat-count repeat-count
2095 replacements replacements)))))
2096
ccec9764 2097 (when query-replace-lazy-highlight
444697a1 2098 (setq isearch-lazy-highlight-last-string nil))
35d59c0f 2099
698e1804
RS
2100 (push-mark)
2101 (undo-boundary)
e782e9f2
RS
2102 (unwind-protect
2103 ;; Loop finding occurrences that perhaps should be replaced.
2104 (while (and keep-going
3ee4cd64
JL
2105 (if backward
2106 (not (or (bobp) (and limit (<= (point) limit))))
2107 (not (or (eobp) (and limit (>= (point) limit)))))
3a52ccf7
JL
2108 ;; Use the next match if it is already known;
2109 ;; otherwise, search for a match after moving forward
2110 ;; one char if progress is required.
2111 (setq real-match-data
2112 (cond ((consp match-again)
3ee4cd64
JL
2113 (goto-char (if backward
2114 (nth 0 match-again)
2115 (nth 1 match-again)))
3a52ccf7
JL
2116 (replace-match-data
2117 t real-match-data match-again))
2118 ;; MATCH-AGAIN non-nil means accept an
2119 ;; adjacent match.
2120 (match-again
2121 (and
2122 (replace-search search-string limit
2123 regexp-flag delimited-flag
3ee4cd64 2124 case-fold-search backward)
3a52ccf7
JL
2125 ;; For speed, use only integers and
2126 ;; reuse the list used last time.
2127 (replace-match-data t real-match-data)))
3ee4cd64
JL
2128 ((and (if backward
2129 (> (1- (point)) (point-min))
2130 (< (1+ (point)) (point-max)))
3a52ccf7 2131 (or (null limit)
3ee4cd64
JL
2132 (if backward
2133 (> (1- (point)) limit)
2134 (< (1+ (point)) limit))))
3a52ccf7
JL
2135 ;; If not accepting adjacent matches,
2136 ;; move one char to the right before
2137 ;; searching again. Undo the motion
2138 ;; if the search fails.
2139 (let ((opoint (point)))
3ee4cd64 2140 (forward-char (if backward -1 1))
3a52ccf7
JL
2141 (if (replace-search search-string limit
2142 regexp-flag delimited-flag
3ee4cd64 2143 case-fold-search backward)
3a52ccf7
JL
2144 (replace-match-data
2145 t real-match-data)
2146 (goto-char opoint)
2147 nil))))))
6a964bb1 2148
c0b45763
RS
2149 ;; Record whether the match is nonempty, to avoid an infinite loop
2150 ;; repeatedly matching the same empty string.
2151 (setq nonempty-match
2152 (/= (nth 0 real-match-data) (nth 1 real-match-data)))
2153
2154 ;; If the match is empty, record that the next one can't be
2155 ;; adjacent.
2156
2157 ;; Otherwise, if matching a regular expression, do the next
2158 ;; match now, since the replacement for this match may
2159 ;; affect whether the next match is adjacent to this one.
2160 ;; If that match is empty, don't use it.
2161 (setq match-again
2162 (and nonempty-match
2163 (or (not regexp-flag)
3ee4cd64
JL
2164 (and (if backward
2165 (looking-back search-string)
2166 (looking-at search-string))
c0b45763
RS
2167 (let ((match (match-data)))
2168 (and (/= (nth 0 match) (nth 1 match))
2169 match))))))
2170
3c9c9d38
JL
2171 (cond
2172 ;; Optionally ignore matches that have a read-only property.
2173 ((not (or (not query-replace-skip-read-only)
2174 (not (text-property-not-all
2175 (nth 0 real-match-data) (nth 1 real-match-data)
2176 'read-only nil))))
2177 (setq skip-read-only-count (1+ skip-read-only-count)))
2178 ;; Optionally filter out matches.
dc6c0eda
SM
2179 ((not (funcall isearch-filter-predicate
2180 (nth 0 real-match-data) (nth 1 real-match-data)))
3c9c9d38
JL
2181 (setq skip-filtered-count (1+ skip-filtered-count)))
2182 ;; Optionally ignore invisible matches.
2183 ((not (or (eq search-invisible t)
ab1bdce5
JL
2184 ;; Don't open overlays for automatic replacements.
2185 (and (not query-flag) search-invisible)
2186 ;; Open hidden overlays for interactive replacements.
3c9c9d38
JL
2187 (not (isearch-range-invisible
2188 (nth 0 real-match-data) (nth 1 real-match-data)))))
2189 (setq skip-invisible-count (1+ skip-invisible-count)))
2190 (t
1c4fe319
RS
2191 ;; Calculate the replacement string, if necessary.
2192 (when replacements
2193 (set-match-data real-match-data)
2194 (setq next-replacement
2195 (funcall (car replacements) (cdr replacements)
2f857176 2196 replace-count)))
1c4fe319 2197 (if (not query-flag)
f2e7b9ef 2198 (progn
15fd7d5d 2199 (unless (or literal noedit)
444697a1
JL
2200 (replace-highlight
2201 (nth 0 real-match-data) (nth 1 real-match-data)
2202 start end search-string
3ee4cd64 2203 regexp-flag delimited-flag case-fold-search backward))
7c1c02ac
DK
2204 (setq noedit
2205 (replace-match-maybe-edit
2206 next-replacement nocasify literal
3ee4cd64 2207 noedit real-match-data backward)
7c1c02ac 2208 replace-count (1+ replace-count)))
1c4fe319
RS
2209 (undo-boundary)
2210 (let (done replaced key def)
2211 ;; Loop reading commands until one of them sets done,
7c1c02ac
DK
2212 ;; which means it has finished handling this
2213 ;; occurrence. Any command that sets `done' should
2214 ;; leave behind proper match data for the stack.
2215 ;; Commands not setting `done' need to adjust
2216 ;; `real-match-data'.
1c4fe319
RS
2217 (while (not done)
2218 (set-match-data real-match-data)
444697a1
JL
2219 (replace-highlight
2220 (match-beginning 0) (match-end 0)
2221 start end search-string
3ee4cd64 2222 regexp-flag delimited-flag case-fold-search backward)
1c4fe319
RS
2223 ;; Bind message-log-max so we don't fill up the message log
2224 ;; with a bunch of identical messages.
7abe68aa
JL
2225 (let ((message-log-max nil)
2226 (replacement-presentation
2227 (if query-replace-show-replacement
2228 (save-match-data
2229 (set-match-data real-match-data)
2230 (match-substitute-replacement next-replacement
2231 nocasify literal))
2232 next-replacement)))
b938735a
JL
2233 (message message
2234 (query-replace-descr from-string)
7abe68aa 2235 (query-replace-descr replacement-presentation)))
1c4fe319
RS
2236 (setq key (read-event))
2237 ;; Necessary in case something happens during read-event
2238 ;; that clobbers the match data.
2239 (set-match-data real-match-data)
2240 (setq key (vector key))
2241 (setq def (lookup-key map key))
2242 ;; Restore the match data while we process the command.
2243 (cond ((eq def 'help)
2244 (with-output-to-temp-buffer "*Help*"
2245 (princ
2246 (concat "Query replacing "
bc5c8c5a
JL
2247 (if delimited-flag
2248 (or (and (symbolp delimited-flag)
2249 (get delimited-flag 'isearch-message-prefix))
2250 "word ") "")
1c4fe319 2251 (if regexp-flag "regexp " "")
3ee4cd64 2252 (if backward "backward " "")
1c4fe319
RS
2253 from-string " with "
2254 next-replacement ".\n\n"
2255 (substitute-command-keys
2256 query-replace-help)))
2257 (with-current-buffer standard-output
2258 (help-mode))))
2259 ((eq def 'exit)
2260 (setq keep-going nil)
2261 (setq done t))
b591f338
JL
2262 ((eq def 'exit-current)
2263 (setq multi-buffer t keep-going nil done t))
1c4fe319
RS
2264 ((eq def 'backup)
2265 (if stack
588c915a 2266 (let ((elt (pop stack)))
7c1c02ac
DK
2267 (goto-char (nth 0 elt))
2268 (setq replaced (nth 1 elt)
2269 real-match-data
2270 (replace-match-data
2271 t real-match-data
2272 (nth 2 elt))))
1c4fe319
RS
2273 (message "No previous match")
2274 (ding 'no-terminate)
2275 (sit-for 1)))
2276 ((eq def 'act)
2277 (or replaced
7c1c02ac
DK
2278 (setq noedit
2279 (replace-match-maybe-edit
2280 next-replacement nocasify literal
3ee4cd64 2281 noedit real-match-data backward)
7c1c02ac 2282 replace-count (1+ replace-count)))
1c4fe319
RS
2283 (setq done t replaced t))
2284 ((eq def 'act-and-exit)
2285 (or replaced
7c1c02ac 2286 (setq noedit
da6eb51c 2287 (replace-match-maybe-edit
7c1c02ac 2288 next-replacement nocasify literal
3ee4cd64 2289 noedit real-match-data backward)
7c1c02ac 2290 replace-count (1+ replace-count)))
1c4fe319
RS
2291 (setq keep-going nil)
2292 (setq done t replaced t))
2293 ((eq def 'act-and-show)
2294 (if (not replaced)
7c1c02ac
DK
2295 (setq noedit
2296 (replace-match-maybe-edit
2297 next-replacement nocasify literal
3ee4cd64 2298 noedit real-match-data backward)
7c1c02ac
DK
2299 replace-count (1+ replace-count)
2300 real-match-data (replace-match-data
2301 t real-match-data)
2302 replaced t)))
b591f338 2303 ((or (eq def 'automatic) (eq def 'automatic-all))
1c4fe319 2304 (or replaced
7c1c02ac
DK
2305 (setq noedit
2306 (replace-match-maybe-edit
2307 next-replacement nocasify literal
3ee4cd64 2308 noedit real-match-data backward)
7c1c02ac 2309 replace-count (1+ replace-count)))
b591f338
JL
2310 (setq done t query-flag nil replaced t)
2311 (if (eq def 'automatic-all) (setq multi-buffer t)))
1c4fe319
RS
2312 ((eq def 'skip)
2313 (setq done t))
2314 ((eq def 'recenter)
2952b1ae
JL
2315 ;; `this-command' has the value `query-replace',
2316 ;; so we need to bind it to `recenter-top-bottom'
2317 ;; to allow it to detect a sequence of `C-l'.
2318 (let ((this-command 'recenter-top-bottom)
2319 (last-command 'recenter-top-bottom))
2320 (recenter-top-bottom)))
1c4fe319
RS
2321 ((eq def 'edit)
2322 (let ((opos (point-marker)))
7c1c02ac
DK
2323 (setq real-match-data (replace-match-data
2324 nil real-match-data
2325 real-match-data))
1c4fe319 2326 (goto-char (match-beginning 0))
86914dcc
RS
2327 (save-excursion
2328 (save-window-excursion
2329 (recursive-edit)))
7c1c02ac
DK
2330 (goto-char opos)
2331 (set-marker opos nil))
1c4fe319
RS
2332 ;; Before we make the replacement,
2333 ;; decide whether the search string
2334 ;; can match again just after this match.
2335 (if (and regexp-flag nonempty-match)
2336 (setq match-again (and (looking-at search-string)
2337 (match-data)))))
1c4fe319
RS
2338 ;; Edit replacement.
2339 ((eq def 'edit-replacement)
7c1c02ac
DK
2340 (setq real-match-data (replace-match-data
2341 nil real-match-data
2342 real-match-data)
2343 next-replacement
3981e5b5
JB
2344 (read-string "Edit replacement string: "
2345 next-replacement)
7c1c02ac
DK
2346 noedit nil)
2347 (if replaced
2348 (set-match-data real-match-data)
2349 (setq noedit
2350 (replace-match-maybe-edit
2351 next-replacement nocasify literal noedit
3ee4cd64 2352 real-match-data backward)
7c1c02ac 2353 replaced t))
1c4fe319 2354 (setq done t))
d99118b0 2355
1c4fe319 2356 ((eq def 'delete-and-edit)
7c1c02ac
DK
2357 (replace-match "" t t)
2358 (setq real-match-data (replace-match-data
2359 nil real-match-data))
2360 (replace-dehighlight)
2361 (save-excursion (recursive-edit))
1c4fe319
RS
2362 (setq replaced t))
2363 ;; Note: we do not need to treat `exit-prefix'
2364 ;; specially here, since we reread
2365 ;; any unrecognized character.
2366 (t
2367 (setq this-command 'mode-exited)
2368 (setq keep-going nil)
2369 (setq unread-command-events
2370 (append (listify-key-sequence key)
2371 unread-command-events))
35d59c0f 2372 (setq done t)))
ccec9764 2373 (when query-replace-lazy-highlight
2952b1ae 2374 ;; Force lazy rehighlighting only after replacements.
ccec9764 2375 (if (not (memq def '(skip backup)))
2952b1ae
JL
2376 (setq isearch-lazy-highlight-last-string nil)))
2377 (unless (eq def 'recenter)
2378 ;; Reset recenter cycling order to initial position.
2379 (setq recenter-last-op nil)))
1c4fe319
RS
2380 ;; Record previous position for ^ when we move on.
2381 ;; Change markers to numbers in the match data
2382 ;; since lots of markers slow down editing.
7c1c02ac 2383 (push (list (point) replaced
bace7209
LT
2384;;; If the replacement has already happened, all we need is the
2385;;; current match start and end. We could get this with a trivial
2386;;; match like
2387;;; (save-excursion (goto-char (match-beginning 0))
2388;;; (search-forward (match-string 0))
2389;;; (match-data t))
2390;;; if we really wanted to avoid manually constructing match data.
2391;;; Adding current-buffer is necessary so that match-data calls can
2392;;; return markers which are appropriate for editing.
7c1c02ac
DK
2393 (if replaced
2394 (list
2395 (match-beginning 0)
2396 (match-end 0)
2397 (current-buffer))
2398 (match-data t)))
3c9c9d38 2399 stack))))))
889617de 2400
e782e9f2 2401 (replace-dehighlight))
4d33492a 2402 (or unread-command-events
3c9c9d38 2403 (message "Replaced %d occurrence%s%s"
4d33492a 2404 replace-count
3c9c9d38
JL
2405 (if (= replace-count 1) "" "s")
2406 (if (> (+ skip-read-only-count
2407 skip-filtered-count
2408 skip-invisible-count) 0)
2409 (format " (skipped %s)"
2410 (mapconcat
2411 'identity
2412 (delq nil (list
2413 (if (> skip-read-only-count 0)
2414 (format "%s read-only"
2415 skip-read-only-count))
2416 (if (> skip-invisible-count 0)
2417 (format "%s invisible"
2418 skip-invisible-count))
2419 (if (> skip-filtered-count 0)
2420 (format "%s filtered out"
2421 skip-filtered-count))))
2422 ", "))
2423 "")))
b591f338 2424 (or (and keep-going stack) multi-buffer)))
698e1804 2425
c88ab9ce 2426;;; replace.el ends here