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