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