38414
|
1 ;;; replace.el --- replace commands for Emacs
|
658
|
2
|
64762
|
3 ;; Copyright (C) 1985, 1986, 1987, 1992, 1994, 1996, 1997, 2000, 2001,
|
68651
|
4 ;; 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
61
|
5
|
45078
|
6 ;; Maintainer: FSF
|
|
7
|
61
|
8 ;; This file is part of GNU Emacs.
|
|
9
|
|
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
|
|
11 ;; it under the terms of the GNU General Public License as published by
|
732
|
12 ;; the Free Software Foundation; either version 2, or (at your option)
|
61
|
13 ;; any later version.
|
|
14
|
|
15 ;; GNU Emacs is distributed in the hope that it will be useful,
|
|
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
18 ;; GNU General Public License for more details.
|
|
19
|
|
20 ;; You should have received a copy of the GNU General Public License
|
14169
|
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
|
64091
|
22 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
23 ;; Boston, MA 02110-1301, USA.
|
61
|
24
|
2315
|
25 ;;; Commentary:
|
|
26
|
|
27 ;; This package supplies the string and regular-expression replace functions
|
|
28 ;; documented in the Emacs user's manual.
|
|
29
|
788
|
30 ;;; Code:
|
61
|
31
|
17664
|
32 (defcustom case-replace t
|
38036
|
33 "*Non-nil means `query-replace' should preserve case in replacements."
|
17664
|
34 :type 'boolean
|
|
35 :group 'matching)
|
264
|
36
|
864
|
37 (defvar query-replace-history nil)
|
|
38
|
71025
|
39 (defvar query-replace-defaults nil
|
|
40 "Default values of FROM-STRING and TO-STRING for `query-replace'.
|
|
41 This is a cons cell (FROM-STRING . TO-STRING), or nil if there is
|
|
42 no default value.")
|
|
43
|
56350
|
44 (defvar query-replace-interactive nil
|
8935
|
45 "Non-nil means `query-replace' uses the last search string.
|
56350
|
46 That becomes the \"string to replace\".")
|
8935
|
47
|
20806
|
48 (defcustom query-replace-from-history-variable 'query-replace-history
|
38036
|
49 "History list to use for the FROM argument of `query-replace' commands.
|
20806
|
50 The value of this variable should be a symbol; that symbol
|
|
51 is used as a variable to hold a history list for the strings
|
|
52 or patterns to be replaced."
|
|
53 :group 'matching
|
21669
|
54 :type 'symbol
|
|
55 :version "20.3")
|
20806
|
56
|
|
57 (defcustom query-replace-to-history-variable 'query-replace-history
|
38036
|
58 "History list to use for the TO argument of `query-replace' commands.
|
20806
|
59 The value of this variable should be a symbol; that symbol
|
|
60 is used as a variable to hold a history list for replacement
|
|
61 strings or patterns."
|
|
62 :group 'matching
|
21669
|
63 :type 'symbol
|
|
64 :version "20.3")
|
20806
|
65
|
40925
|
66 (defcustom query-replace-skip-read-only nil
|
|
67 "*Non-nil means `query-replace' and friends ignore read-only matches."
|
|
68 :type 'boolean
|
|
69 :group 'matching
|
59996
|
70 :version "22.1")
|
40925
|
71
|
59479
|
72 (defcustom query-replace-highlight t
|
|
73 "*Non-nil means to highlight matches during query replacement."
|
|
74 :type 'boolean
|
|
75 :group 'matching)
|
|
76
|
|
77 (defcustom query-replace-lazy-highlight t
|
|
78 "*Controls the lazy-highlighting during query replacements.
|
|
79 When non-nil, all text in the buffer matching the current match
|
|
80 is highlighted lazily using isearch lazy highlighting (see
|
|
81 `lazy-highlight-initial-delay' and `lazy-highlight-interval')."
|
|
82 :type 'boolean
|
|
83 :group 'lazy-highlight
|
|
84 :group 'matching
|
59996
|
85 :version "22.1")
|
59479
|
86
|
|
87 (defface query-replace
|
|
88 '((t (:inherit isearch)))
|
|
89 "Face for highlighting query replacement matches."
|
|
90 :group 'matching
|
59996
|
91 :version "22.1")
|
59479
|
92
|
56355
|
93 (defun query-replace-descr (string)
|
|
94 (mapconcat 'isearch-text-char-description string ""))
|
|
95
|
64866
|
96 (defun query-replace-read-from (prompt regexp-flag)
|
56355
|
97 "Query and return the `from' argument of a query-replace operation.
|
|
98 The return value can also be a pair (FROM . TO) indicating that the user
|
|
99 wants to replace FROM with TO."
|
56351
d073da76f0a5
(query-replace-read-from, query-replace-read-to): New funs extracted
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
100 (if query-replace-interactive
|
d073da76f0a5
(query-replace-read-from, query-replace-read-to): New funs extracted
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
101 (car (if regexp-flag regexp-search-ring search-ring))
|
71125
|
102 (let* ((history-add-new-input nil)
|
|
103 (from
|
56351
d073da76f0a5
(query-replace-read-from, query-replace-read-to): New funs extracted
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
104 ;; The save-excursion here is in case the user marks and copies
|
d073da76f0a5
(query-replace-read-from, query-replace-read-to): New funs extracted
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
105 ;; a region in order to specify the minibuffer input.
|
d073da76f0a5
(query-replace-read-from, query-replace-read-to): New funs extracted
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
106 ;; That should not clobber the region for the query-replace itself.
|
d073da76f0a5
(query-replace-read-from, query-replace-read-to): New funs extracted
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
107 (save-excursion
|
d073da76f0a5
(query-replace-read-from, query-replace-read-to): New funs extracted
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
108 (read-from-minibuffer
|
71025
|
109 (if query-replace-defaults
|
64866
|
110 (format "%s (default %s -> %s): " prompt
|
71025
|
111 (query-replace-descr (car query-replace-defaults))
|
|
112 (query-replace-descr (cdr query-replace-defaults)))
|
64866
|
113 (format "%s: " prompt))
|
56351
d073da76f0a5
(query-replace-read-from, query-replace-read-to): New funs extracted
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
114 nil nil nil
|
d073da76f0a5
(query-replace-read-from, query-replace-read-to): New funs extracted
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
115 query-replace-from-history-variable
|
70936
|
116 nil t))))
|
71025
|
117 (if (and (zerop (length from)) query-replace-defaults)
|
71026
|
118 (cons (car query-replace-defaults)
|
|
119 (query-replace-compile-replacement
|
|
120 (cdr query-replace-defaults) regexp-flag))
|
71125
|
121 (add-to-history query-replace-from-history-variable from nil t)
|
56355
|
122 ;; Warn if user types \n or \t, but don't reject the input.
|
|
123 (and regexp-flag
|
|
124 (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\(\\\\[nt]\\)" from)
|
|
125 (let ((match (match-string 3 from)))
|
|
126 (cond
|
|
127 ((string= match "\\n")
|
|
128 (message "Note: `\\n' here doesn't match a newline; to do that, type C-q C-j instead"))
|
|
129 ((string= match "\\t")
|
|
130 (message "Note: `\\t' here doesn't match a tab; to do that, just type TAB")))
|
|
131 (sit-for 2)))
|
|
132 from))))
|
41761
878a3e2e7cfa
(query-replace-read-args): Display message if FROM contains `\n' or `\t'.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
133
|
56581
|
134 (defun query-replace-compile-replacement (to regexp-flag)
|
|
135 "Maybe convert a regexp replacement TO to Lisp.
|
|
136 Returns a list suitable for `perform-replace' if necessary,
|
|
137 the original string if not."
|
|
138 (if (and regexp-flag
|
|
139 (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" to))
|
56228
|
140 (let (pos list char)
|
|
141 (while
|
|
142 (progn
|
|
143 (setq pos (match-end 0))
|
|
144 (push (substring to 0 (- pos 2)) list)
|
|
145 (setq char (aref to (1- pos))
|
|
146 to (substring to pos))
|
|
147 (cond ((eq char ?\#)
|
|
148 (push '(number-to-string replace-count) list))
|
|
149 ((eq char ?\,)
|
|
150 (setq pos (read-from-string to))
|
|
151 (push `(replace-quote ,(car pos)) list)
|
56325
06c785c5e655
(query-replace-read-args): Swallow space after symbols, not after
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
152 (let ((end
|
06c785c5e655
(query-replace-read-args): Swallow space after symbols, not after
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
153 ;; Swallow a space after a symbol
|
06c785c5e655
(query-replace-read-args): Swallow space after symbols, not after
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
154 ;; if there is a space.
|
06c785c5e655
(query-replace-read-args): Swallow space after symbols, not after
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
155 (if (and (or (symbolp (car pos))
|
06c785c5e655
(query-replace-read-args): Swallow space after symbols, not after
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
156 ;; Swallow a space after 'foo
|
06c785c5e655
(query-replace-read-args): Swallow space after symbols, not after
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
157 ;; but not after (quote foo).
|
06c785c5e655
(query-replace-read-args): Swallow space after symbols, not after
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
158 (and (eq (car-safe (car pos)) 'quote)
|
56328
|
159 (not (= ?\( (aref to 0)))))
|
|
160 (eq (string-match " " to (cdr pos))
|
|
161 (cdr pos)))
|
56325
06c785c5e655
(query-replace-read-args): Swallow space after symbols, not after
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
162 (1+ (cdr pos))
|
06c785c5e655
(query-replace-read-args): Swallow space after symbols, not after
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
163 (cdr pos))))
|
06c785c5e655
(query-replace-read-args): Swallow space after symbols, not after
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
164 (setq to (substring to end)))))
|
56228
|
165 (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" to)))
|
56581
|
166 (setq to (nreverse (delete "" (cons to list))))
|
|
167 (replace-match-string-symbols to)
|
|
168 (cons 'replace-eval-replacement
|
|
169 (if (cdr to)
|
|
170 (cons 'concat to)
|
|
171 (car to))))
|
56351
d073da76f0a5
(query-replace-read-from, query-replace-read-to): New funs extracted
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
172 to))
|
d073da76f0a5
(query-replace-read-from, query-replace-read-to): New funs extracted
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
173
|
56581
|
174
|
64866
|
175 (defun query-replace-read-to (from prompt regexp-flag)
|
56581
|
176 "Query and return the `to' argument of a query-replace operation."
|
|
177 (query-replace-compile-replacement
|
|
178 (save-excursion
|
71125
|
179 (let* ((history-add-new-input nil)
|
|
180 (to (read-from-minibuffer
|
|
181 (format "%s %s with: " prompt (query-replace-descr from))
|
|
182 nil nil nil
|
|
183 query-replace-to-history-variable from t)))
|
|
184 (add-to-history query-replace-to-history-variable to nil t)
|
71025
|
185 (setq query-replace-defaults (cons from to))
|
|
186 to))
|
56581
|
187 regexp-flag))
|
|
188
|
64866
|
189 (defun query-replace-read-args (prompt regexp-flag &optional noerror)
|
56351
d073da76f0a5
(query-replace-read-from, query-replace-read-to): New funs extracted
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
190 (unless noerror
|
d073da76f0a5
(query-replace-read-from, query-replace-read-to): New funs extracted
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
191 (barf-if-buffer-read-only))
|
64866
|
192 (let* ((from (query-replace-read-from prompt regexp-flag))
|
56355
|
193 (to (if (consp from) (prog1 (cdr from) (setq from (car from)))
|
64866
|
194 (query-replace-read-to from prompt regexp-flag))))
|
49958
|
195 (list from to current-prefix-arg)))
|
864
|
196
|
28706
|
197 (defun query-replace (from-string to-string &optional delimited start end)
|
260
|
198 "Replace some occurrences of FROM-STRING with TO-STRING.
|
|
199 As each match is found, the user must type a character saying
|
|
200 what to do with it. For directions, type \\[help-command] at that time.
|
|
201
|
20248
|
202 In Transient Mark mode, if the mark is active, operate on the contents
|
|
203 of the region. Otherwise, operate from point to the end of the buffer.
|
|
204
|
8935
|
205 If `query-replace-interactive' is non-nil, the last incremental search
|
|
206 string is used as FROM-STRING--you don't have to specify it with the
|
|
207 minibuffer.
|
|
208
|
48173
|
209 Matching is independent of case if `case-fold-search' is non-nil and
|
|
210 FROM-STRING has no uppercase letters. Replacement transfers the case
|
|
211 pattern of the old text to the new text, if `case-replace' and
|
|
212 `case-fold-search' are non-nil and FROM-STRING has no uppercase
|
|
213 letters. \(Transferring the case pattern means that if the old text
|
|
214 matched is all caps, or capitalized, then its replacement is upcased
|
|
215 or capitalized.)
|
10104
|
216
|
6707
|
217 Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
|
2080
|
218 only matches surrounded by word boundaries.
|
28706
|
219 Fourth and fifth arg START and END specify the region to operate on.
|
2080
|
220
|
|
221 To customize possible responses, change the \"bindings\" in `query-replace-map'."
|
49958
|
222 (interactive (let ((common
|
63150
|
223 (query-replace-read-args
|
60174
|
224 (if (and transient-mark-mode mark-active)
|
|
225 "Query replace in region"
|
|
226 "Query replace")
|
|
227 nil)))
|
49958
|
228 (list (nth 0 common) (nth 1 common) (nth 2 common)
|
|
229 ;; These are done separately here
|
|
230 ;; so that command-history will record these expressions
|
|
231 ;; rather than the values they had this time.
|
|
232 (if (and transient-mark-mode mark-active)
|
|
233 (region-beginning))
|
|
234 (if (and transient-mark-mode mark-active)
|
|
235 (region-end)))))
|
40254
|
236 (perform-replace from-string to-string t nil delimited nil nil start end))
|
20248
|
237
|
268
|
238 (define-key esc-map "%" 'query-replace)
|
260
|
239
|
28706
|
240 (defun query-replace-regexp (regexp to-string &optional delimited start end)
|
260
|
241 "Replace some things after point matching REGEXP with TO-STRING.
|
|
242 As each match is found, the user must type a character saying
|
|
243 what to do with it. For directions, type \\[help-command] at that time.
|
|
244
|
20248
|
245 In Transient Mark mode, if the mark is active, operate on the contents
|
|
246 of the region. Otherwise, operate from point to the end of the buffer.
|
|
247
|
8935
|
248 If `query-replace-interactive' is non-nil, the last incremental search
|
|
249 regexp is used as REGEXP--you don't have to specify it with the
|
|
250 minibuffer.
|
|
251
|
48173
|
252 Matching is independent of case if `case-fold-search' is non-nil and
|
|
253 REGEXP has no uppercase letters. Replacement transfers the case
|
|
254 pattern of the old text to the new text, if `case-replace' and
|
|
255 `case-fold-search' are non-nil and REGEXP has no uppercase letters.
|
|
256 \(Transferring the case pattern means that if the old text matched is
|
|
257 all caps, or capitalized, then its replacement is upcased or
|
|
258 capitalized.)
|
28706
|
259
|
6707
|
260 Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
|
260
|
261 only matches surrounded by word boundaries.
|
28706
|
262 Fourth and fifth arg START and END specify the region to operate on.
|
|
263
|
6707
|
264 In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
|
|
265 and `\\=\\N' (where N is a digit) stands for
|
56148
|
266 whatever what matched the Nth `\\(...\\)' in REGEXP.
|
56228
|
267 `\\?' lets you edit the replacement text in the minibuffer
|
|
268 at the given position for each replacement.
|
56148
|
269
|
56245
|
270 In interactive calls, the replacement text can contain `\\,'
|
|
271 followed by a Lisp expression. Each
|
|
272 replacement evaluates that expression to compute the replacement
|
|
273 string. Inside of that expression, `\\&' is a string denoting the
|
56328
|
274 whole match as a string, `\\N' for a partial match, `\\#&' and `\\#N'
|
56245
|
275 for the whole or a partial match converted to a number with
|
|
276 `string-to-number', and `\\#' itself for the number of replacements
|
|
277 done so far (starting with zero).
|
56148
|
278
|
56245
|
279 If the replacement expression is a symbol, write a space after it
|
|
280 to terminate it. One space there, if any, will be discarded.
|
56228
|
281
|
|
282 When using those Lisp features interactively in the replacement
|
|
283 text, TO-STRING is actually made a list instead of a string.
|
|
284 Use \\[repeat-complex-command] after this command for details."
|
49958
|
285 (interactive
|
|
286 (let ((common
|
63150
|
287 (query-replace-read-args
|
60174
|
288 (if (and transient-mark-mode mark-active)
|
|
289 "Query replace regexp in region"
|
|
290 "Query replace regexp")
|
|
291 t)))
|
56228
|
292 (list (nth 0 common) (nth 1 common) (nth 2 common)
|
|
293 ;; These are done separately here
|
|
294 ;; so that command-history will record these expressions
|
|
295 ;; rather than the values they had this time.
|
|
296 (if (and transient-mark-mode mark-active)
|
|
297 (region-beginning))
|
|
298 (if (and transient-mark-mode mark-active)
|
|
299 (region-end)))))
|
56148
|
300 (perform-replace regexp to-string t t delimited nil nil start end))
|
49958
|
301
|
22353
|
302 (define-key esc-map [?\C-%] 'query-replace-regexp)
|
260
|
303
|
28706
|
304 (defun query-replace-regexp-eval (regexp to-expr &optional delimited start end)
|
25167
|
305 "Replace some things after point matching REGEXP with the result of TO-EXPR.
|
|
306 As each match is found, the user must type a character saying
|
|
307 what to do with it. For directions, type \\[help-command] at that time.
|
|
308
|
|
309 TO-EXPR is a Lisp expression evaluated to compute each replacement. It may
|
|
310 reference `replace-count' to get the number of replacements already made.
|
|
311 If the result of TO-EXPR is not a string, it is converted to one using
|
|
312 `prin1-to-string' with the NOESCAPE argument (which see).
|
|
313
|
|
314 For convenience, when entering TO-EXPR interactively, you can use `\\&' or
|
43406
|
315 `\\0' to stand for whatever matched the whole of REGEXP, and `\\N' (where
|
|
316 N is a digit) to stand for whatever matched the Nth `\\(...\\)' in REGEXP.
|
25167
|
317 Use `\\#&' or `\\#N' if you want a number instead of a string.
|
56148
|
318 In interactive use, `\\#' in itself stands for `replace-count'.
|
25167
|
319
|
|
320 In Transient Mark mode, if the mark is active, operate on the contents
|
|
321 of the region. Otherwise, operate from point to the end of the buffer.
|
|
322
|
|
323 If `query-replace-interactive' is non-nil, the last incremental search
|
|
324 regexp is used as REGEXP--you don't have to specify it with the
|
|
325 minibuffer.
|
|
326
|
|
327 Preserves case in each replacement if `case-replace' and `case-fold-search'
|
|
328 are non-nil and REGEXP has no uppercase letters.
|
28706
|
329
|
25167
|
330 Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
|
37536
|
331 only matches that are surrounded by word boundaries.
|
28706
|
332 Fourth and fifth arg START and END specify the region to operate on."
|
25167
|
333 (interactive
|
56360
|
334 (progn
|
56355
|
335 (barf-if-buffer-read-only)
|
|
336 (let* ((from
|
|
337 ;; Let-bind the history var to disable the "foo -> bar" default.
|
|
338 ;; Maybe we shouldn't disable this default, but for now I'll
|
|
339 ;; leave it off. --Stef
|
|
340 (let ((query-replace-to-history-variable nil))
|
|
341 (query-replace-read-from "Query replace regexp" t)))
|
56350
|
342 (to (list (read-from-minibuffer
|
56355
|
343 (format "Query replace regexp %s with eval: "
|
|
344 (query-replace-descr from))
|
56350
|
345 nil nil t query-replace-to-history-variable from t))))
|
25167
|
346 ;; We make TO a list because replace-match-string-symbols requires one,
|
|
347 ;; and the user might enter a single token.
|
|
348 (replace-match-string-symbols to)
|
49958
|
349 (list from (car to) current-prefix-arg
|
|
350 (if (and transient-mark-mode mark-active)
|
|
351 (region-beginning))
|
|
352 (if (and transient-mark-mode mark-active)
|
56360
|
353 (region-end))))))
|
27391
|
354 (perform-replace regexp (cons 'replace-eval-replacement to-expr)
|
53778
|
355 t 'literal delimited nil nil start end))
|
25167
|
356
|
28706
|
357 (defun map-query-replace-regexp (regexp to-strings &optional n start end)
|
260
|
358 "Replace some matches for REGEXP with various strings, in rotation.
|
29051
|
359 The second argument TO-STRINGS contains the replacement strings,
|
|
360 separated by spaces. Third arg DELIMITED (prefix arg if interactive),
|
|
361 if non-nil, means replace only matches surrounded by word boundaries.
|
|
362 This command works like `query-replace-regexp' except that each
|
|
363 successive replacement uses the next successive replacement string,
|
260
|
364 wrapping around from the last such string to the first.
|
|
365
|
20248
|
366 In Transient Mark mode, if the mark is active, operate on the contents
|
|
367 of the region. Otherwise, operate from point to the end of the buffer.
|
|
368
|
260
|
369 Non-interactively, TO-STRINGS may be a list of replacement strings.
|
|
370
|
8935
|
371 If `query-replace-interactive' is non-nil, the last incremental search
|
|
372 regexp is used as REGEXP--you don't have to specify it with the minibuffer.
|
|
373
|
260
|
374 A prefix argument N says to use each replacement string N times
|
28706
|
375 before rotating to the next.
|
|
376 Fourth and fifth arg START and END specify the region to operate on."
|
864
|
377 (interactive
|
56350
|
378 (let* ((from (if query-replace-interactive
|
8935
|
379 (car regexp-search-ring)
|
|
380 (read-from-minibuffer "Map query replace (regexp): "
|
|
381 nil nil nil
|
19551
|
382 'query-replace-history nil t)))
|
56350
|
383 (to (read-from-minibuffer
|
864
|
384 (format "Query replace %s with (space-separated strings): "
|
56355
|
385 (query-replace-descr from))
|
864
|
386 nil nil nil
|
56350
|
387 'query-replace-history from t)))
|
50030
|
388 (list from to
|
|
389 (and current-prefix-arg
|
|
390 (prefix-numeric-value current-prefix-arg))
|
49958
|
391 (if (and transient-mark-mode mark-active)
|
|
392 (region-beginning))
|
|
393 (if (and transient-mark-mode mark-active)
|
|
394 (region-end)))))
|
260
|
395 (let (replacements)
|
|
396 (if (listp to-strings)
|
|
397 (setq replacements to-strings)
|
|
398 (while (/= (length to-strings) 0)
|
|
399 (if (string-match " " to-strings)
|
|
400 (setq replacements
|
|
401 (append replacements
|
|
402 (list (substring to-strings 0
|
|
403 (string-match " " to-strings))))
|
|
404 to-strings (substring to-strings
|
|
405 (1+ (string-match " " to-strings))))
|
|
406 (setq replacements (append replacements (list to-strings))
|
|
407 to-strings ""))))
|
40254
|
408 (perform-replace regexp replacements t t nil n nil start end)))
|
260
|
409
|
28706
|
410 (defun replace-string (from-string to-string &optional delimited start end)
|
260
|
411 "Replace occurrences of FROM-STRING with TO-STRING.
|
|
412 Preserve case in each match if `case-replace' and `case-fold-search'
|
|
413 are non-nil and FROM-STRING has no uppercase letters.
|
10104
|
414 \(Preserving case means that if the string matched is all caps, or capitalized,
|
|
415 then its replacement is upcased or capitalized.)
|
|
416
|
20248
|
417 In Transient Mark mode, if the mark is active, operate on the contents
|
|
418 of the region. Otherwise, operate from point to the end of the buffer.
|
|
419
|
6707
|
420 Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
|
260
|
421 only matches surrounded by word boundaries.
|
28706
|
422 Fourth and fifth arg START and END specify the region to operate on.
|
260
|
423
|
8935
|
424 If `query-replace-interactive' is non-nil, the last incremental search
|
|
425 string is used as FROM-STRING--you don't have to specify it with the
|
|
426 minibuffer.
|
|
427
|
260
|
428 This function is usually the wrong thing to use in a Lisp program.
|
|
429 What you probably want is a loop like this:
|
6707
|
430 (while (search-forward FROM-STRING nil t)
|
|
431 (replace-match TO-STRING nil t))
|
17211
|
432 which will run faster and will not set the mark or print anything.
|
|
433 \(You may need a more complex loop if FROM-STRING can match the null string
|
|
434 and TO-STRING is also null.)"
|
49958
|
435 (interactive
|
|
436 (let ((common
|
63150
|
437 (query-replace-read-args
|
60174
|
438 (if (and transient-mark-mode mark-active)
|
|
439 "Replace string in region"
|
|
440 "Replace string")
|
|
441 nil)))
|
49958
|
442 (list (nth 0 common) (nth 1 common) (nth 2 common)
|
|
443 (if (and transient-mark-mode mark-active)
|
|
444 (region-beginning))
|
|
445 (if (and transient-mark-mode mark-active)
|
|
446 (region-end)))))
|
40254
|
447 (perform-replace from-string to-string nil nil delimited nil nil start end))
|
260
|
448
|
28706
|
449 (defun replace-regexp (regexp to-string &optional delimited start end)
|
260
|
450 "Replace things after point matching REGEXP with TO-STRING.
|
6707
|
451 Preserve case in each match if `case-replace' and `case-fold-search'
|
260
|
452 are non-nil and REGEXP has no uppercase letters.
|
28706
|
453
|
|
454 In Transient Mark mode, if the mark is active, operate on the contents
|
|
455 of the region. Otherwise, operate from point to the end of the buffer.
|
|
456
|
6707
|
457 Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
|
260
|
458 only matches surrounded by word boundaries.
|
28706
|
459 Fourth and fifth arg START and END specify the region to operate on.
|
|
460
|
6707
|
461 In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
|
|
462 and `\\=\\N' (where N is a digit) stands for
|
56228
|
463 whatever what matched the Nth `\\(...\\)' in REGEXP.
|
|
464 `\\?' lets you edit the replacement text in the minibuffer
|
|
465 at the given position for each replacement.
|
|
466
|
|
467 In interactive calls, the replacement text may contain `\\,'
|
|
468 followed by a Lisp expression used as part of the replacement
|
|
469 text. Inside of that expression, `\\&' is a string denoting the
|
|
470 whole match, `\\N' a partial matches, `\\#&' and `\\#N' the
|
|
471 respective numeric values from `string-to-number', and `\\#'
|
|
472 itself for `replace-count', the number of replacements occured so
|
|
473 far.
|
|
474
|
|
475 If your Lisp expression is an identifier and the next letter in
|
|
476 the replacement string would be interpreted as part of it, you
|
|
477 can wrap it with an expression like `\\,(or \\#)'. Incidentally,
|
|
478 for this particular case you may also enter `\\#' in the
|
|
479 replacement text directly.
|
|
480
|
|
481 When using those Lisp features interactively in the replacement
|
|
482 text, TO-STRING is actually made a list instead of a string.
|
|
483 Use \\[repeat-complex-command] after this command for details.
|
260
|
484
|
8935
|
485 If `query-replace-interactive' is non-nil, the last incremental search
|
|
486 regexp is used as REGEXP--you don't have to specify it with the minibuffer.
|
|
487
|
260
|
488 This function is usually the wrong thing to use in a Lisp program.
|
|
489 What you probably want is a loop like this:
|
|
490 (while (re-search-forward REGEXP nil t)
|
6707
|
491 (replace-match TO-STRING nil nil))
|
260
|
492 which will run faster and will not set the mark or print anything."
|
49958
|
493 (interactive
|
|
494 (let ((common
|
63150
|
495 (query-replace-read-args
|
60174
|
496 (if (and transient-mark-mode mark-active)
|
63150
|
497 "Replace regexp in region"
|
|
498 "Replace regexp")
|
60174
|
499 t)))
|
49958
|
500 (list (nth 0 common) (nth 1 common) (nth 2 common)
|
|
501 (if (and transient-mark-mode mark-active)
|
|
502 (region-beginning))
|
|
503 (if (and transient-mark-mode mark-active)
|
|
504 (region-end)))))
|
40254
|
505 (perform-replace regexp to-string nil t delimited nil nil start end))
|
32036
|
506
|
2408
|
507
|
|
508 (defvar regexp-history nil
|
|
509 "History list for some commands that read regular expressions.")
|
260
|
510
|
32036
|
511
|
2571
|
512 (defalias 'delete-non-matching-lines 'keep-lines)
|
32036
|
513 (defalias 'delete-matching-lines 'flush-lines)
|
|
514 (defalias 'count-matches 'how-many)
|
|
515
|
|
516
|
|
517 (defun keep-lines-read-args (prompt)
|
|
518 "Read arguments for `keep-lines' and friends.
|
|
519 Prompt for a regexp with PROMPT.
|
38040
|
520 Value is a list, (REGEXP)."
|
|
521 (list (read-from-minibuffer prompt nil nil nil
|
63779
|
522 'regexp-history nil t)
|
|
523 nil nil t))
|
32036
|
524
|
63779
|
525 (defun keep-lines (regexp &optional rstart rend interactive)
|
61
|
526 "Delete all lines except those containing matches for REGEXP.
|
|
527 A match split across lines preserves all the lines it lies in.
|
63779
|
528 When called from Lisp (and usually interactively as well, see below)
|
|
529 applies to all lines starting after point.
|
23457
|
530
|
|
531 If REGEXP contains upper case characters (excluding those preceded by `\\'),
|
32036
|
532 the matching is case-sensitive.
|
|
533
|
|
534 Second and third arg RSTART and REND specify the region to operate on.
|
63779
|
535 This command operates on (the accessible part of) all lines whose
|
|
536 accessible part is entirely contained in the region determined by RSTART
|
|
537 and REND. (A newline ending a line counts as part of that line.)
|
32036
|
538
|
38040
|
539 Interactively, in Transient Mark mode when the mark is active, operate
|
63779
|
540 on all lines whose accessible part is entirely contained in the region.
|
|
541 Otherwise, the command applies to all lines starting after point.
|
|
542 When calling this function from Lisp, you can pretend that it was
|
|
543 called interactively by passing a non-nil INTERACTIVE argument.
|
|
544
|
|
545 This function starts looking for the next match from the end of
|
|
546 the previous match. Hence, it ignores matches that overlap
|
|
547 a previously found match."
|
38040
|
548
|
32036
|
549 (interactive
|
46519
|
550 (progn
|
|
551 (barf-if-buffer-read-only)
|
|
552 (keep-lines-read-args "Keep lines (containing match for regexp): ")))
|
32036
|
553 (if rstart
|
46335
|
554 (progn
|
|
555 (goto-char (min rstart rend))
|
63779
|
556 (setq rend
|
|
557 (progn
|
|
558 (save-excursion
|
|
559 (goto-char (max rstart rend))
|
|
560 (unless (or (bolp) (eobp))
|
|
561 (forward-line 0))
|
|
562 (point-marker)))))
|
|
563 (if (and interactive transient-mark-mode mark-active)
|
38040
|
564 (setq rstart (region-beginning)
|
63779
|
565 rend (progn
|
|
566 (goto-char (region-end))
|
|
567 (unless (or (bolp) (eobp))
|
|
568 (forward-line 0))
|
|
569 (point-marker)))
|
38040
|
570 (setq rstart (point)
|
|
571 rend (point-max-marker)))
|
|
572 (goto-char rstart))
|
61
|
573 (save-excursion
|
|
574 (or (bolp) (forward-line 1))
|
23457
|
575 (let ((start (point))
|
|
576 (case-fold-search (and case-fold-search
|
|
577 (isearch-no-upper-case-p regexp t))))
|
32036
|
578 (while (< (point) rend)
|
61
|
579 ;; Start is first char not preserved by previous match.
|
32036
|
580 (if (not (re-search-forward regexp rend 'move))
|
|
581 (delete-region start rend)
|
61
|
582 (let ((end (save-excursion (goto-char (match-beginning 0))
|
63779
|
583 (forward-line 0)
|
61
|
584 (point))))
|
|
585 ;; Now end is first char preserved by the new match.
|
|
586 (if (< start end)
|
|
587 (delete-region start end))))
|
46693
|
588
|
32036
|
589 (setq start (save-excursion (forward-line 1) (point)))
|
61
|
590 ;; If the match was empty, avoid matching again at same place.
|
32036
|
591 (and (< (point) rend)
|
|
592 (= (match-beginning 0) (match-end 0))
|
63779
|
593 (forward-char 1)))))
|
|
594 (set-marker rend nil)
|
|
595 nil)
|
61
|
596
|
32036
|
597
|
63779
|
598 (defun flush-lines (regexp &optional rstart rend interactive)
|
|
599 "Delete lines containing matches for REGEXP.
|
|
600 When called from Lisp (and usually when called interactively as
|
|
601 well, see below), applies to the part of the buffer after point.
|
|
602 The line point is in is deleted if and only if it contains a
|
|
603 match for regexp starting after point.
|
23457
|
604
|
|
605 If REGEXP contains upper case characters (excluding those preceded by `\\'),
|
32036
|
606 the matching is case-sensitive.
|
|
607
|
|
608 Second and third arg RSTART and REND specify the region to operate on.
|
63779
|
609 Lines partially contained in this region are deleted if and only if
|
|
610 they contain a match entirely contained in it.
|
32036
|
611
|
38040
|
612 Interactively, in Transient Mark mode when the mark is active, operate
|
|
613 on the contents of the region. Otherwise, operate from point to the
|
63779
|
614 end of (the accessible portion of) the buffer. When calling this function
|
|
615 from Lisp, you can pretend that it was called interactively by passing
|
|
616 a non-nil INTERACTIVE argument.
|
|
617
|
|
618 If a match is split across lines, all the lines it lies in are deleted.
|
|
619 They are deleted _before_ looking for the next match. Hence, a match
|
|
620 starting on the same line at which another match ended is ignored."
|
38040
|
621
|
32036
|
622 (interactive
|
46519
|
623 (progn
|
|
624 (barf-if-buffer-read-only)
|
|
625 (keep-lines-read-args "Flush lines (containing match for regexp): ")))
|
32036
|
626 (if rstart
|
46335
|
627 (progn
|
|
628 (goto-char (min rstart rend))
|
|
629 (setq rend (copy-marker (max rstart rend))))
|
63779
|
630 (if (and interactive transient-mark-mode mark-active)
|
38040
|
631 (setq rstart (region-beginning)
|
|
632 rend (copy-marker (region-end)))
|
|
633 (setq rstart (point)
|
|
634 rend (point-max-marker)))
|
|
635 (goto-char rstart))
|
23457
|
636 (let ((case-fold-search (and case-fold-search
|
|
637 (isearch-no-upper-case-p regexp t))))
|
|
638 (save-excursion
|
32036
|
639 (while (and (< (point) rend)
|
|
640 (re-search-forward regexp rend t))
|
23457
|
641 (delete-region (save-excursion (goto-char (match-beginning 0))
|
63779
|
642 (forward-line 0)
|
23457
|
643 (point))
|
63779
|
644 (progn (forward-line 1) (point))))))
|
|
645 (set-marker rend nil)
|
|
646 nil)
|
61
|
647
|
32036
|
648
|
63779
|
649 (defun how-many (regexp &optional rstart rend interactive)
|
|
650 "Print and return number of matches for REGEXP following point.
|
|
651 When called from Lisp and INTERACTIVE is omitted or nil, just return
|
|
652 the number, do not print it; if INTERACTIVE is t, the function behaves
|
|
653 in all respects has if it had been called interactively.
|
23457
|
654
|
|
655 If REGEXP contains upper case characters (excluding those preceded by `\\'),
|
32036
|
656 the matching is case-sensitive.
|
|
657
|
|
658 Second and third arg RSTART and REND specify the region to operate on.
|
|
659
|
38040
|
660 Interactively, in Transient Mark mode when the mark is active, operate
|
|
661 on the contents of the region. Otherwise, operate from point to the
|
63779
|
662 end of (the accessible portion of) the buffer.
|
|
663
|
|
664 This function starts looking for the next match from the end of
|
|
665 the previous match. Hence, it ignores matches that overlap
|
|
666 a previously found match."
|
38040
|
667
|
32036
|
668 (interactive
|
|
669 (keep-lines-read-args "How many matches for (regexp): "))
|
37832
|
670 (save-excursion
|
|
671 (if rstart
|
63779
|
672 (progn
|
|
673 (goto-char (min rstart rend))
|
|
674 (setq rend (max rstart rend)))
|
|
675 (if (and interactive transient-mark-mode mark-active)
|
38040
|
676 (setq rstart (region-beginning)
|
63779
|
677 rend (region-end))
|
38040
|
678 (setq rstart (point)
|
63779
|
679 rend (point-max)))
|
38040
|
680 (goto-char rstart))
|
37832
|
681 (let ((count 0)
|
|
682 opoint
|
|
683 (case-fold-search (and case-fold-search
|
|
684 (isearch-no-upper-case-p regexp t))))
|
|
685 (while (and (< (point) rend)
|
|
686 (progn (setq opoint (point))
|
|
687 (re-search-forward regexp rend t)))
|
|
688 (if (= opoint (point))
|
|
689 (forward-char 1)
|
|
690 (setq count (1+ count))))
|
63779
|
691 (when interactive (message "%d occurrence%s"
|
|
692 count
|
|
693 (if (= count 1) "" "s")))
|
|
694 count)))
|
32036
|
695
|
2408
|
696
|
37832
|
697 (defvar occur-mode-map
|
|
698 (let ((map (make-sparse-keymap)))
|
67187
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
699 ;; We use this alternative name, so we can use \\[occur-mode-mouse-goto].
|
37832
|
700 (define-key map [mouse-2] 'occur-mode-mouse-goto)
|
|
701 (define-key map "\C-c\C-c" 'occur-mode-goto-occurrence)
|
|
702 (define-key map "\C-m" 'occur-mode-goto-occurrence)
|
45444
84e0e49bfb75
(occur-engine): Increment globalcount all at once after searching a buffer.
Colin Walters <walters@gnu.org>
diff
changeset
|
703 (define-key map "o" 'occur-mode-goto-occurrence-other-window)
|
42294
|
704 (define-key map "\C-o" 'occur-mode-display-occurrence)
|
37832
|
705 (define-key map "\M-n" 'occur-next)
|
|
706 (define-key map "\M-p" 'occur-prev)
|
46693
|
707 (define-key map "r" 'occur-rename-buffer)
|
|
708 (define-key map "c" 'clone-buffer)
|
37832
|
709 (define-key map "g" 'revert-buffer)
|
46693
|
710 (define-key map "q" 'quit-window)
|
|
711 (define-key map "z" 'kill-this-buffer)
|
57023
|
712 (define-key map "\C-c\C-f" 'next-error-follow-minor-mode)
|
37832
|
713 map)
|
|
714 "Keymap for `occur-mode'.")
|
61
|
715
|
44924
|
716 (defvar occur-revert-arguments nil
|
|
717 "Arguments to pass to `occur-1' to revert an Occur mode buffer.
|
|
718 See `occur-revert-function'.")
|
61
|
719
|
47111
|
720 (defcustom occur-mode-hook '(turn-on-font-lock)
|
|
721 "Hook run when entering Occur mode."
|
|
722 :type 'hook
|
|
723 :group 'matching)
|
|
724
|
|
725 (defcustom occur-hook nil
|
63970
|
726 "Hook run by Occur when there are any matches."
|
45444
84e0e49bfb75
(occur-engine): Increment globalcount all at once after searching a buffer.
Colin Walters <walters@gnu.org>
diff
changeset
|
727 :type 'hook
|
84e0e49bfb75
(occur-engine): Increment globalcount all at once after searching a buffer.
Colin Walters <walters@gnu.org>
diff
changeset
|
728 :group 'matching)
|
84e0e49bfb75
(occur-engine): Increment globalcount all at once after searching a buffer.
Colin Walters <walters@gnu.org>
diff
changeset
|
729
|
17655
|
730 (put 'occur-mode 'mode-class 'special)
|
41329
|
731 (defun occur-mode ()
|
61
|
732 "Major mode for output from \\[occur].
|
10266
a44beb55d3e1
(occur-mode-map): Bind C-m and `return' to occur-mode-goto-occurrence.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
733 \\<occur-mode-map>Move point to one of the items in this buffer, then use
|
a44beb55d3e1
(occur-mode-map): Bind C-m and `return' to occur-mode-goto-occurrence.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
734 \\[occur-mode-goto-occurrence] to go to the occurrence that the item refers to.
|
a44beb55d3e1
(occur-mode-map): Bind C-m and `return' to occur-mode-goto-occurrence.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
735 Alternatively, click \\[occur-mode-mouse-goto] on an item to go to it.
|
a44beb55d3e1
(occur-mode-map): Bind C-m and `return' to occur-mode-goto-occurrence.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
736
|
61
|
737 \\{occur-mode-map}"
|
47130
|
738 (interactive)
|
41329
|
739 (kill-all-local-variables)
|
|
740 (use-local-map occur-mode-map)
|
|
741 (setq major-mode 'occur-mode)
|
|
742 (setq mode-name "Occur")
|
37832
|
743 (set (make-local-variable 'revert-buffer-function) 'occur-revert-function)
|
47111
|
744 (make-local-variable 'occur-revert-arguments)
|
47375
fe8ca2be9fde
(occur-mode): Add font-lock-defontify to change-major-mode-hook.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
745 (add-hook 'change-major-mode-hook 'font-lock-defontify nil t)
|
55067
|
746 (setq next-error-function 'occur-next-error)
|
62737
|
747 (run-mode-hooks 'occur-mode-hook))
|
61
|
748
|
16864
|
749 (defun occur-revert-function (ignore1 ignore2)
|
44924
|
750 "Handle `revert-buffer' for Occur mode buffers."
|
45265
|
751 (apply 'occur-1 (append occur-revert-arguments (list (buffer-name)))))
|
16864
|
752
|
6596
|
753 (defun occur-mode-find-occurrence ()
|
44924
|
754 (let ((pos (get-text-property (point) 'occur-target)))
|
|
755 (unless pos
|
44794
|
756 (error "No occurrence on this line"))
|
44924
|
757 (unless (buffer-live-p (marker-buffer pos))
|
|
758 (error "Buffer for this occurrence was killed"))
|
|
759 pos))
|
6596
|
760
|
67187
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
761 (defalias 'occur-mode-mouse-goto 'occur-mode-goto-occurrence)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
762 (defun occur-mode-goto-occurrence (&optional event)
|
6596
|
763 "Go to the occurrence the current line describes."
|
67187
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
764 (interactive (list last-nonmenu-event))
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
765 (let ((pos
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
766 (if (null event)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
767 ;; Actually `event-end' works correctly with a nil argument as
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
768 ;; well, so we could dispense with this test, but let's not
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
769 ;; rely on this undocumented behavior.
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
770 (occur-mode-find-occurrence)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
771 (with-current-buffer (window-buffer (posn-window (event-end event)))
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
772 (save-excursion
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
773 (goto-char (posn-point (event-end event)))
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
774 (occur-mode-find-occurrence)))))
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
775 same-window-buffer-names
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
776 same-window-regexps)
|
67179
cfc0110bc143
* replace.el (occur-mode-goto-occurrence): Pop, don't switch.
Chong Yidong <cyd@stupidchicken.com>
diff
changeset
|
777 (pop-to-buffer (marker-buffer pos))
|
44924
|
778 (goto-char pos)))
|
18918
|
779
|
42604
|
780 (defun occur-mode-goto-occurrence-other-window ()
|
|
781 "Go to the occurrence the current line describes, in another window."
|
|
782 (interactive)
|
44924
|
783 (let ((pos (occur-mode-find-occurrence)))
|
|
784 (switch-to-buffer-other-window (marker-buffer pos))
|
|
785 (goto-char pos)))
|
42604
|
786
|
42294
|
787 (defun occur-mode-display-occurrence ()
|
|
788 "Display in another window the occurrence the current line describes."
|
|
789 (interactive)
|
44924
|
790 (let ((pos (occur-mode-find-occurrence))
|
|
791 window
|
|
792 ;; Bind these to ensure `display-buffer' puts it in another window.
|
42294
|
793 same-window-buffer-names
|
44924
|
794 same-window-regexps)
|
|
795 (setq window (display-buffer (marker-buffer pos)))
|
42294
|
796 ;; This is the way to set point in the proper window.
|
|
797 (save-selected-window
|
|
798 (select-window window)
|
44924
|
799 (goto-char pos))))
|
42294
|
800
|
47593
|
801 (defun occur-find-match (n search message)
|
18918
|
802 (if (not n) (setq n 1))
|
|
803 (let ((r))
|
|
804 (while (> n 0)
|
47593
|
805 (setq r (funcall search (point) 'occur-match))
|
|
806 (and r
|
|
807 (get-text-property r 'occur-match)
|
|
808 (setq r (funcall search r 'occur-match)))
|
18918
|
809 (if r
|
47593
|
810 (goto-char r)
|
|
811 (error message))
|
18918
|
812 (setq n (1- n)))))
|
|
813
|
47593
|
814 (defun occur-next (&optional n)
|
|
815 "Move to the Nth (default 1) next match in an Occur mode buffer."
|
|
816 (interactive "p")
|
|
817 (occur-find-match n #'next-single-property-change "No more matches"))
|
|
818
|
18918
|
819 (defun occur-prev (&optional n)
|
44924
|
820 "Move to the Nth (default 1) previous match in an Occur mode buffer."
|
18918
|
821 (interactive "p")
|
47593
|
822 (occur-find-match n #'previous-single-property-change "No earlier matches"))
|
55067
|
823
|
|
824 (defun occur-next-error (&optional argp reset)
|
|
825 "Move to the Nth (default 1) next match in an Occur mode buffer.
|
|
826 Compatibility function for \\[next-error] invocations."
|
|
827 (interactive "p")
|
58625
|
828 ;; we need to run occur-find-match from within the Occur buffer
|
58995
|
829 (with-current-buffer
|
59290
285e069cecd2
(occur-1): If the output buffer is also an input, don't kill it, rename it.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
830 ;; Choose the buffer and make it current.
|
58625
|
831 (if (next-error-buffer-p (current-buffer))
|
|
832 (current-buffer)
|
59290
285e069cecd2
(occur-1): If the output buffer is also an input, don't kill it, rename it.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
833 (next-error-find-buffer nil nil
|
285e069cecd2
(occur-1): If the output buffer is also an input, don't kill it, rename it.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
834 (lambda ()
|
285e069cecd2
(occur-1): If the output buffer is also an input, don't kill it, rename it.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
835 (eq major-mode 'occur-mode))))
|
58995
|
836
|
|
837 (goto-char (cond (reset (point-min))
|
|
838 ((< argp 0) (line-beginning-position))
|
67180
|
839 ((> argp 0) (line-end-position))
|
|
840 ((point))))
|
58625
|
841 (occur-find-match
|
58995
|
842 (abs argp)
|
|
843 (if (> 0 argp)
|
58625
|
844 #'previous-single-property-change
|
|
845 #'next-single-property-change)
|
|
846 "No more matches")
|
|
847 ;; In case the *Occur* buffer is visible in a nonselected window.
|
|
848 (set-window-point (get-buffer-window (current-buffer)) (point))
|
|
849 (occur-mode-goto-occurrence)))
|
2408
|
850
|
58987
|
851 (defface match
|
|
852 '((((class color) (min-colors 88) (background light))
|
|
853 :background "Tan")
|
|
854 (((class color) (min-colors 88) (background dark))
|
64503
791fa2059b5e
(match): Use slightly more light RoyalBlue3 instead of dark RoyalBlue4.
Juri Linkov <juri@jurta.org>
diff
changeset
|
855 :background "RoyalBlue3")
|
58987
|
856 (((class color) (min-colors 8))
|
|
857 :background "blue" :foreground "white")
|
|
858 (((type tty) (class mono))
|
|
859 :inverse-video t)
|
|
860 (t :background "gray"))
|
|
861 "Face used to highlight matches permanently."
|
|
862 :group 'matching
|
59996
|
863 :version "22.1")
|
58987
|
864
|
17664
|
865 (defcustom list-matching-lines-default-context-lines 0
|
29051
|
866 "*Default number of context lines included around `list-matching-lines' matches.
|
|
867 A negative number means to include that many lines before the match.
|
17664
|
868 A positive number means to include that many lines both before and after."
|
|
869 :type 'integer
|
|
870 :group 'matching)
|
61
|
871
|
2571
|
872 (defalias 'list-matching-lines 'occur)
|
61
|
873
|
58987
|
874 (defcustom list-matching-lines-face 'match
|
29051
|
875 "*Face used by \\[list-matching-lines] to show the text that matches.
|
44794
|
876 If the value is nil, don't highlight the matching portions specially."
|
|
877 :type 'face
|
|
878 :group 'matching)
|
|
879
|
|
880 (defcustom list-matching-lines-buffer-name-face 'underline
|
|
881 "*Face used by \\[list-matching-lines] to show the names of buffers.
|
|
882 If the value is nil, don't highlight the buffer names specially."
|
|
883 :type 'face
|
|
884 :group 'matching)
|
|
885
|
66756
|
886 (defcustom occur-excluded-properties
|
|
887 '(read-only invisible intangible field mouse-face help-echo local-map keymap
|
|
888 yank-handler follow-link)
|
|
889 "*Text properties to discard when copying lines to the *Occur* buffer.
|
|
890 The value should be a list of text properties to discard or t,
|
|
891 which means to discard all text properties."
|
|
892 :type '(choice (const :tag "All" t) (repeat symbol))
|
|
893 :group 'matching
|
|
894 :version "22.1")
|
|
895
|
58741
|
896 (defun occur-accumulate-lines (count &optional keep-props)
|
44794
|
897 (save-excursion
|
|
898 (let ((forwardp (> count 0))
|
58995
|
899 result beg end)
|
44794
|
900 (while (not (or (zerop count)
|
|
901 (if forwardp
|
|
902 (eobp)
|
|
903 (bobp))))
|
45176
|
904 (setq count (+ count (if forwardp -1 1)))
|
58995
|
905 (setq beg (line-beginning-position)
|
|
906 end (line-end-position))
|
59570
|
907 (if (and keep-props (if (boundp 'jit-lock-mode) jit-lock-mode)
|
58995
|
908 (text-property-not-all beg end 'fontified t))
|
59570
|
909 (if (fboundp 'jit-lock-fontify-now)
|
|
910 (jit-lock-fontify-now beg end)))
|
44794
|
911 (push
|
66756
|
912 (if (and keep-props (not (eq occur-excluded-properties t)))
|
|
913 (let ((str (buffer-substring beg end)))
|
|
914 (remove-list-of-text-properties
|
|
915 0 (length str) occur-excluded-properties str)
|
|
916 str)
|
|
917 (buffer-substring-no-properties beg end))
|
44794
|
918 result)
|
|
919 (forward-line (if forwardp 1 -1)))
|
|
920 (nreverse result))))
|
|
921
|
|
922 (defun occur-read-primary-args ()
|
|
923 (list (let* ((default (car regexp-history))
|
|
924 (input
|
|
925 (read-from-minibuffer
|
|
926 (if default
|
65680
|
927 (format "List lines matching regexp (default %s): "
|
56355
|
928 (query-replace-descr default))
|
44794
|
929 "List lines matching regexp: ")
|
|
930 nil
|
|
931 nil
|
|
932 nil
|
56449
84df5471b01e
(occur-read-primary-args): Pass default to read-from-minibuffer.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
933 'regexp-history
|
84df5471b01e
(occur-read-primary-args): Pass default to read-from-minibuffer.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
934 default)))
|
44794
|
935 (if (equal input "")
|
|
936 default
|
|
937 input))
|
45308
|
938 (when current-prefix-arg
|
|
939 (prefix-numeric-value current-prefix-arg))))
|
16818
|
940
|
64135
fe83c61c82da
(occur-rename-buffer): Use `generate-new-buffer' also when called
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
941 (defun occur-rename-buffer (&optional unique-p interactive-p)
|
46693
|
942 "Rename the current *Occur* buffer to *Occur: original-buffer-name*.
|
64135
fe83c61c82da
(occur-rename-buffer): Use `generate-new-buffer' also when called
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
943 Here `original-buffer-name' is the buffer name were Occur was originally run.
|
fe83c61c82da
(occur-rename-buffer): Use `generate-new-buffer' also when called
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
944 When given the prefix argument, or called non-interactively, the renaming
|
fe83c61c82da
(occur-rename-buffer): Use `generate-new-buffer' also when called
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
945 will not clobber the existing buffer(s) of that name, but use
|
fe83c61c82da
(occur-rename-buffer): Use `generate-new-buffer' also when called
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
946 `generate-new-buffer-name' instead. You can add this to `occur-hook'
|
fe83c61c82da
(occur-rename-buffer): Use `generate-new-buffer' also when called
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
947 if you always want a separate *Occur* buffer for each buffer where you
|
fe83c61c82da
(occur-rename-buffer): Use `generate-new-buffer' also when called
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
948 invoke `occur'."
|
fe83c61c82da
(occur-rename-buffer): Use `generate-new-buffer' also when called
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
949 (interactive "P\np")
|
46693
|
950 (with-current-buffer
|
|
951 (if (eq major-mode 'occur-mode) (current-buffer) (get-buffer "*Occur*"))
|
|
952 (rename-buffer (concat "*Occur: "
|
|
953 (mapconcat #'buffer-name
|
|
954 (car (cddr occur-revert-arguments)) "/")
|
|
955 "*")
|
64135
fe83c61c82da
(occur-rename-buffer): Use `generate-new-buffer' also when called
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
956 (or unique-p (not interactive-p)))))
|
46693
|
957
|
61
|
958 (defun occur (regexp &optional nlines)
|
1427
|
959 "Show all lines in the current buffer containing a match for REGEXP.
|
63779
|
960 This function can not handle matches that span more than one line.
|
260
|
961
|
|
962 Each line is displayed with NLINES lines before and after, or -NLINES
|
|
963 before if NLINES is negative.
|
|
964 NLINES defaults to `list-matching-lines-default-context-lines'.
|
61
|
965 Interactively it is the prefix arg.
|
|
966
|
2408
|
967 The lines are shown in a buffer named `*Occur*'.
|
61
|
968 It serves as a menu to find any of the occurrences in this buffer.
|
17655
|
969 \\<occur-mode-map>\\[describe-mode] in that buffer will explain how.
|
17638
9ece72836276
(occur): If regexp has uppercase in it, match it case-sensitively.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
970
|
17655
|
971 If REGEXP contains upper case characters (excluding those preceded by `\\'),
|
|
972 the matching is case-sensitive."
|
44794
|
973 (interactive (occur-read-primary-args))
|
|
974 (occur-1 regexp nlines (list (current-buffer))))
|
|
975
|
|
976 (defun multi-occur (bufs regexp &optional nlines)
|
|
977 "Show all lines in buffers BUFS containing a match for REGEXP.
|
|
978 This function acts on multiple buffers; otherwise, it is exactly like
|
68504
|
979 `occur'. When you invoke this command interactively, you must specify
|
|
980 the buffer names that you want, one by one."
|
15040
|
981 (interactive
|
44794
|
982 (cons
|
47204
|
983 (let* ((bufs (list (read-buffer "First buffer to search: "
|
|
984 (current-buffer) t)))
|
|
985 (buf nil)
|
|
986 (ido-ignore-item-temp-list bufs))
|
44794
|
987 (while (not (string-equal
|
49597
|
988 (setq buf (read-buffer
|
47204
|
989 (if (eq read-buffer-function 'ido-read-buffer)
|
|
990 "Next buffer to search (C-j to end): "
|
|
991 "Next buffer to search (RET to end): ")
|
|
992 nil t))
|
44794
|
993 ""))
|
47204
|
994 (add-to-list 'bufs buf)
|
|
995 (setq ido-ignore-item-temp-list bufs))
|
44794
|
996 (nreverse (mapcar #'get-buffer bufs)))
|
|
997 (occur-read-primary-args)))
|
|
998 (occur-1 regexp nlines bufs))
|
|
999
|
68504
|
1000 (defun multi-occur-in-matching-buffers (bufregexp regexp &optional allbufs)
|
|
1001 "Show all lines matching REGEXP in buffers specified by BUFREGEXP.
|
|
1002 Normally BUFREGEXP matches against each buffer's visited file name,
|
|
1003 but if you specify a prefix argument, it matches against the buffer name.
|
44794
|
1004 See also `multi-occur'."
|
|
1005 (interactive
|
|
1006 (cons
|
|
1007 (let* ((default (car regexp-history))
|
|
1008 (input
|
|
1009 (read-from-minibuffer
|
68536
|
1010 (if current-prefix-arg
|
68504
|
1011 "List lines in buffers whose names match regexp: "
|
|
1012 "List lines in buffers whose filenames match regexp: ")
|
44794
|
1013 nil
|
|
1014 nil
|
|
1015 nil
|
|
1016 'regexp-history)))
|
|
1017 (if (equal input "")
|
|
1018 default
|
|
1019 input))
|
|
1020 (occur-read-primary-args)))
|
|
1021 (when bufregexp
|
68536
|
1022 (occur-1 regexp nil
|
44794
|
1023 (delq nil
|
|
1024 (mapcar (lambda (buf)
|
68504
|
1025 (when (if allbufs
|
|
1026 (string-match bufregexp
|
|
1027 (buffer-name buf))
|
|
1028 (and (buffer-file-name buf)
|
|
1029 (string-match bufregexp
|
|
1030 (buffer-file-name buf))))
|
44794
|
1031 buf))
|
|
1032 (buffer-list))))))
|
|
1033
|
45265
|
1034 (defun occur-1 (regexp nlines bufs &optional buf-name)
|
|
1035 (unless buf-name
|
|
1036 (setq buf-name "*Occur*"))
|
59290
285e069cecd2
(occur-1): If the output buffer is also an input, don't kill it, rename it.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
1037 (let (occur-buf
|
45079
|
1038 (active-bufs (delq nil (mapcar #'(lambda (buf)
|
|
1039 (when (buffer-live-p buf) buf))
|
|
1040 bufs))))
|
|
1041 ;; Handle the case where one of the buffers we're searching is the
|
59290
285e069cecd2
(occur-1): If the output buffer is also an input, don't kill it, rename it.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
1042 ;; output buffer. Just rename it.
|
285e069cecd2
(occur-1): If the output buffer is also an input, don't kill it, rename it.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
1043 (when (member buf-name (mapcar 'buffer-name active-bufs))
|
285e069cecd2
(occur-1): If the output buffer is also an input, don't kill it, rename it.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
1044 (with-current-buffer (get-buffer buf-name)
|
285e069cecd2
(occur-1): If the output buffer is also an input, don't kill it, rename it.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
1045 (rename-uniquely)))
|
285e069cecd2
(occur-1): If the output buffer is also an input, don't kill it, rename it.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
1046
|
285e069cecd2
(occur-1): If the output buffer is also an input, don't kill it, rename it.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
1047 ;; Now find or create the output buffer.
|
285e069cecd2
(occur-1): If the output buffer is also an input, don't kill it, rename it.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
1048 ;; If we just renamed that buffer, we will make a new one here.
|
285e069cecd2
(occur-1): If the output buffer is also an input, don't kill it, rename it.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
1049 (setq occur-buf (get-buffer-create buf-name))
|
285e069cecd2
(occur-1): If the output buffer is also an input, don't kill it, rename it.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
1050
|
44794
|
1051 (with-current-buffer occur-buf
|
|
1052 (occur-mode)
|
62147
|
1053 (let ((inhibit-read-only t))
|
|
1054 (erase-buffer)
|
|
1055 (let ((count (occur-engine
|
|
1056 regexp active-bufs occur-buf
|
|
1057 (or nlines list-matching-lines-default-context-lines)
|
|
1058 (and case-fold-search
|
|
1059 (isearch-no-upper-case-p regexp t))
|
|
1060 list-matching-lines-buffer-name-face
|
66756
|
1061 nil list-matching-lines-face
|
|
1062 (not (eq occur-excluded-properties t)))))
|
62147
|
1063 (let* ((bufcount (length active-bufs))
|
|
1064 (diff (- (length bufs) bufcount)))
|
|
1065 (message "Searched %d buffer%s%s; %s match%s for `%s'"
|
|
1066 bufcount (if (= bufcount 1) "" "s")
|
|
1067 (if (zerop diff) "" (format " (%d killed)" diff))
|
|
1068 (if (zerop count) "no" (format "%d" count))
|
|
1069 (if (= count 1) "" "es")
|
|
1070 regexp))
|
|
1071 (setq occur-revert-arguments (list regexp nlines bufs))
|
63970
|
1072 (if (= count 0)
|
|
1073 (kill-buffer occur-buf)
|
|
1074 (display-buffer occur-buf)
|
|
1075 (setq next-error-last-buffer occur-buf)
|
|
1076 (setq buffer-read-only t)
|
|
1077 (set-buffer-modified-p nil)
|
|
1078 (run-hooks 'occur-hook)))))))
|
18991
|
1079
|
44924
|
1080 (defun occur-engine-add-prefix (lines)
|
|
1081 (mapcar
|
|
1082 #'(lambda (line)
|
47532
|
1083 (concat " :" line "\n"))
|
44924
|
1084 lines))
|
|
1085
|
|
1086 (defun occur-engine (regexp buffers out-buf nlines case-fold-search
|
|
1087 title-face prefix-face match-face keep-props)
|
|
1088 (with-current-buffer out-buf
|
48276
|
1089 (let ((globalcount 0)
|
64823
|
1090 ;; Don't generate undo entries for creation of the initial contents.
|
|
1091 (buffer-undo-list t)
|
48276
|
1092 (coding nil))
|
44924
|
1093 ;; Map over all the buffers
|
|
1094 (dolist (buf buffers)
|
|
1095 (when (buffer-live-p buf)
|
|
1096 (let ((matches 0) ;; count of matched lines
|
|
1097 (lines 1) ;; line count
|
|
1098 (matchbeg 0)
|
|
1099 (origpt nil)
|
|
1100 (begpt nil)
|
|
1101 (endpt nil)
|
|
1102 (marker nil)
|
|
1103 (curstring "")
|
70349
|
1104 (inhibit-field-text-motion t)
|
44924
|
1105 (headerpt (with-current-buffer out-buf (point))))
|
67187
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1106 (with-current-buffer buf
|
48276
|
1107 (or coding
|
|
1108 ;; Set CODING only if the current buffer locally
|
|
1109 ;; binds buffer-file-coding-system.
|
|
1110 (not (local-variable-p 'buffer-file-coding-system))
|
|
1111 (setq coding buffer-file-coding-system))
|
44794
|
1112 (save-excursion
|
44924
|
1113 (goto-char (point-min)) ;; begin searching in the buffer
|
|
1114 (while (not (eobp))
|
|
1115 (setq origpt (point))
|
|
1116 (when (setq endpt (re-search-forward regexp nil t))
|
|
1117 (setq matches (1+ matches)) ;; increment match count
|
56350
|
1118 (setq matchbeg (match-beginning 0))
|
44924
|
1119 (setq lines (+ lines (1- (count-lines origpt endpt))))
|
58995
|
1120 (save-excursion
|
|
1121 (goto-char matchbeg)
|
|
1122 (setq begpt (line-beginning-position)
|
|
1123 endpt (line-end-position)))
|
44924
|
1124 (setq marker (make-marker))
|
|
1125 (set-marker marker matchbeg)
|
59570
|
1126 (if (and keep-props
|
|
1127 (if (boundp 'jit-lock-mode) jit-lock-mode)
|
58995
|
1128 (text-property-not-all begpt endpt 'fontified t))
|
59570
|
1129 (if (fboundp 'jit-lock-fontify-now)
|
|
1130 (jit-lock-fontify-now begpt endpt)))
|
66756
|
1131 (if (and keep-props (not (eq occur-excluded-properties t)))
|
|
1132 (progn
|
|
1133 (setq curstring (buffer-substring begpt endpt))
|
|
1134 (remove-list-of-text-properties
|
|
1135 0 (length curstring) occur-excluded-properties curstring))
|
|
1136 (setq curstring (buffer-substring-no-properties begpt endpt)))
|
|
1137 ;; Highlight the matches
|
44924
|
1138 (let ((len (length curstring))
|
|
1139 (start 0))
|
|
1140 (while (and (< start len)
|
|
1141 (string-match regexp curstring start))
|
58995
|
1142 (add-text-properties
|
|
1143 (match-beginning 0) (match-end 0)
|
|
1144 (append
|
|
1145 `(occur-match t)
|
|
1146 (when match-face
|
|
1147 ;; Use `face' rather than `font-lock-face' here
|
|
1148 ;; so as to override faces copied from the buffer.
|
|
1149 `(face ,match-face)))
|
|
1150 curstring)
|
44924
|
1151 (setq start (match-end 0))))
|
|
1152 ;; Generate the string to insert for this match
|
|
1153 (let* ((out-line
|
|
1154 (concat
|
47532
|
1155 ;; Using 7 digits aligns tabs properly.
|
66473
|
1156 (apply #'propertize (format "%7d:" lines)
|
44924
|
1157 (append
|
|
1158 (when prefix-face
|
45689
|
1159 `(font-lock-face prefix-face))
|
66473
|
1160 `(occur-prefix t mouse-face (highlight)
|
66372
|
1161 occur-target ,marker follow-link t
|
|
1162 help-echo "mouse-2: go to this occurrence")))
|
58995
|
1163 ;; We don't put `mouse-face' on the newline,
|
|
1164 ;; because that loses. And don't put it
|
|
1165 ;; on context lines to reduce flicker.
|
66473
|
1166 (propertize curstring 'mouse-face (list 'highlight)
|
66372
|
1167 'occur-target marker
|
|
1168 'follow-link t
|
|
1169 'help-echo
|
|
1170 "mouse-2: go to this occurrence")
|
66720
|
1171 ;; Add marker at eol, but no mouse props.
|
|
1172 (propertize "\n" 'occur-target marker)))
|
44924
|
1173 (data
|
|
1174 (if (= nlines 0)
|
|
1175 ;; The simple display style
|
|
1176 out-line
|
|
1177 ;; The complex multi-line display
|
|
1178 ;; style. Generate a list of lines,
|
|
1179 ;; concatenate them all together.
|
|
1180 (apply #'concat
|
|
1181 (nconc
|
56520
|
1182 (occur-engine-add-prefix (nreverse (cdr (occur-accumulate-lines (- (1+ (abs nlines))) keep-props))))
|
44924
|
1183 (list out-line)
|
56520
|
1184 (if (> nlines 0)
|
|
1185 (occur-engine-add-prefix
|
|
1186 (cdr (occur-accumulate-lines (1+ nlines) keep-props)))))))))
|
44924
|
1187 ;; Actually insert the match display data
|
|
1188 (with-current-buffer out-buf
|
|
1189 (let ((beg (point))
|
|
1190 (end (progn (insert data) (point))))
|
|
1191 (unless (= nlines 0)
|
66372
|
1192 (insert "-------\n")))))
|
44924
|
1193 (goto-char endpt))
|
45265
|
1194 (if endpt
|
|
1195 (progn
|
|
1196 (setq lines (1+ lines))
|
|
1197 ;; On to the next match...
|
|
1198 (forward-line 1))
|
|
1199 (goto-char (point-max))))))
|
44924
|
1200 (when (not (zerop matches)) ;; is the count zero?
|
45444
84e0e49bfb75
(occur-engine): Increment globalcount all at once after searching a buffer.
Colin Walters <walters@gnu.org>
diff
changeset
|
1201 (setq globalcount (+ globalcount matches))
|
44924
|
1202 (with-current-buffer out-buf
|
|
1203 (goto-char headerpt)
|
|
1204 (let ((beg (point))
|
|
1205 end)
|
54778
edec41928fc8
* replace.el (occur-engine): Distinguish between one and several
John Paul Wallington <jpw@pobox.com>
diff
changeset
|
1206 (insert (format "%d match%s for \"%s\" in buffer: %s\n"
|
edec41928fc8
* replace.el (occur-engine): Distinguish between one and several
John Paul Wallington <jpw@pobox.com>
diff
changeset
|
1207 matches (if (= matches 1) "" "es")
|
edec41928fc8
* replace.el (occur-engine): Distinguish between one and several
John Paul Wallington <jpw@pobox.com>
diff
changeset
|
1208 regexp (buffer-name buf)))
|
44924
|
1209 (setq end (point))
|
|
1210 (add-text-properties beg end
|
|
1211 (append
|
|
1212 (when title-face
|
45689
|
1213 `(font-lock-face ,title-face))
|
|
1214 `(occur-title ,buf))))
|
44924
|
1215 (goto-char (point-min)))))))
|
48276
|
1216 (if coding
|
|
1217 ;; CODING is buffer-file-coding-system of the first buffer
|
|
1218 ;; that locally binds it. Let's use it also for the output
|
|
1219 ;; buffer.
|
|
1220 (set-buffer-file-coding-system coding))
|
44924
|
1221 ;; Return the number of matches
|
|
1222 globalcount)))
|
18991
|
1223
|
61
|
1224
|
2080
|
1225 ;; It would be nice to use \\[...], but there is no reasonable way
|
|
1226 ;; to make that display both SPC and Y.
|
61
|
1227 (defconst query-replace-help
|
|
1228 "Type Space or `y' to replace one match, Delete or `n' to skip to next,
|
5337
|
1229 RET or `q' to exit, Period to replace one match and exit,
|
61
|
1230 Comma to replace but not move point immediately,
|
|
1231 C-r to enter recursive edit (\\[exit-recursive-edit] to get out again),
|
|
1232 C-w to delete match and recursive edit,
|
|
1233 C-l to clear the screen, redisplay, and offer same replacement again,
|
|
1234 ! to replace all remaining matches with no more questions,
|
28801
|
1235 ^ to move point back to previous match,
|
|
1236 E to edit the replacement string"
|
38036
|
1237 "Help message while in `query-replace'.")
|
61
|
1238
|
67187
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1239 (defvar query-replace-map
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1240 (let ((map (make-sparse-keymap)))
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1241 (define-key map " " 'act)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1242 (define-key map "\d" 'skip)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1243 (define-key map [delete] 'skip)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1244 (define-key map [backspace] 'skip)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1245 (define-key map "y" 'act)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1246 (define-key map "n" 'skip)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1247 (define-key map "Y" 'act)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1248 (define-key map "N" 'skip)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1249 (define-key map "e" 'edit-replacement)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1250 (define-key map "E" 'edit-replacement)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1251 (define-key map "," 'act-and-show)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1252 (define-key map "q" 'exit)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1253 (define-key map "\r" 'exit)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1254 (define-key map [return] 'exit)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1255 (define-key map "." 'act-and-exit)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1256 (define-key map "\C-r" 'edit)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1257 (define-key map "\C-w" 'delete-and-edit)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1258 (define-key map "\C-l" 'recenter)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1259 (define-key map "!" 'automatic)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1260 (define-key map "^" 'backup)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1261 (define-key map "\C-h" 'help)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1262 (define-key map [f1] 'help)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1263 (define-key map [help] 'help)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1264 (define-key map "?" 'help)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1265 (define-key map "\C-g" 'quit)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1266 (define-key map "\C-]" 'quit)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1267 (define-key map "\e" 'exit-prefix)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1268 (define-key map [escape] 'exit-prefix)
|
805356939662
(query-replace-map): Move initialization into declaration.
Stefan Monnier <monnier@iro.umontreal.ca>
diff
changeset
|
1269 map)
|
2080
|
1270 "Keymap that defines the responses to questions in `query-replace'.
|
|
1271 The \"bindings\" in this map are not commands; they are answers.
|
|
1272 The valid answers include `act', `skip', `act-and-show',
|
|
1273 `exit', `act-and-exit', `edit', `delete-and-edit', `recenter',
|
10057
|
1274 `automatic', `backup', `exit-prefix', and `help'.")
|
2080
|
1275
|
25167
|
1276 (defun replace-match-string-symbols (n)
|
29051
|
1277 "Process a list (and any sub-lists), expanding certain symbols.
|
|
1278 Symbol Expands To
|
|
1279 N (match-string N) (where N is a string of digits)
|
|
1280 #N (string-to-number (match-string N))
|
|
1281 & (match-string 0)
|
|
1282 #& (string-to-number (match-string 0))
|
56148
|
1283 # replace-count
|
29051
|
1284
|
|
1285 Note that these symbols must be preceeded by a backslash in order to
|
72095
|
1286 type them using Lisp syntax."
|
|
1287 (while (consp n)
|
25167
|
1288 (cond
|
|
1289 ((consp (car n))
|
|
1290 (replace-match-string-symbols (car n))) ;Process sub-list
|
|
1291 ((symbolp (car n))
|
|
1292 (let ((name (symbol-name (car n))))
|
|
1293 (cond
|
|
1294 ((string-match "^[0-9]+$" name)
|
|
1295 (setcar n (list 'match-string (string-to-number name))))
|
|
1296 ((string-match "^#[0-9]+$" name)
|
|
1297 (setcar n (list 'string-to-number
|
|
1298 (list 'match-string
|
|
1299 (string-to-number (substring name 1))))))
|
|
1300 ((string= "&" name)
|
|
1301 (setcar n '(match-string 0)))
|
|
1302 ((string= "#&" name)
|
56148
|
1303 (setcar n '(string-to-number (match-string 0))))
|
|
1304 ((string= "#" name)
|
|
1305 (setcar n 'replace-count))))))
|
25167
|
1306 (setq n (cdr n))))
|
|
1307
|
|
1308 (defun replace-eval-replacement (expression replace-count)
|
|
1309 (let ((replacement (eval expression)))
|
|
1310 (if (stringp replacement)
|
|
1311 replacement
|
|
1312 (prin1-to-string replacement t))))
|
|
1313
|
56148
|
1314 (defun replace-quote (replacement)
|
|
1315 "Quote a replacement string.
|
|
1316 This just doubles all backslashes in REPLACEMENT and
|
|
1317 returns the resulting string. If REPLACEMENT is not
|
|
1318 a string, it is first passed through `prin1-to-string'
|
|
1319 with the `noescape' argument set.
|
|
1320
|
|
1321 `match-data' is preserved across the call."
|
|
1322 (save-match-data
|
|
1323 (replace-regexp-in-string "\\\\" "\\\\"
|
|
1324 (if (stringp replacement)
|
|
1325 replacement
|
|
1326 (prin1-to-string replacement t))
|
|
1327 t t)))
|
|
1328
|
25167
|
1329 (defun replace-loop-through-replacements (data replace-count)
|
|
1330 ;; DATA is a vector contaning the following values:
|
|
1331 ;; 0 next-rotate-count
|
|
1332 ;; 1 repeat-count
|
|
1333 ;; 2 next-replacement
|
|
1334 ;; 3 replacements
|
|
1335 (if (= (aref data 0) replace-count)
|
|
1336 (progn
|
|
1337 (aset data 0 (+ replace-count (aref data 1)))
|
|
1338 (let ((next (cdr (aref data 2))))
|
|
1339 (aset data 2 (if (consp next) next (aref data 3))))))
|
|
1340 (car (aref data 2)))
|
|
1341
|
56228
|
1342 (defun replace-match-data (integers reuse &optional new)
|
|
1343 "Like `match-data', but markers in REUSE get invalidated.
|
|
1344 If NEW is non-NIL, it is set and returned instead of fresh data,
|
|
1345 but coerced to the correct value of INTEGERS."
|
|
1346 (or (and new
|
|
1347 (progn
|
|
1348 (set-match-data new)
|
|
1349 (and (eq new reuse)
|
|
1350 (eq (null integers) (markerp (car reuse)))
|
|
1351 new)))
|
63150
|
1352 (match-data integers reuse t)))
|
56228
|
1353
|
|
1354 (defun replace-match-maybe-edit (newtext fixedcase literal noedit match-data)
|
|
1355 "Make a replacement with `replace-match', editing `\\?'.
|
58913
|
1356 NEWTEXT, FIXEDCASE, LITERAL are just passed on. If NOEDIT is true, no
|
56228
|
1357 check for `\\?' is made to save time. MATCH-DATA is used for the
|
|
1358 replacement. In case editing is done, it is changed to use markers.
|
|
1359
|
|
1360 The return value is non-NIL if there has been no `\\?' or NOEDIT was
|
|
1361 passed in. If LITERAL is set, no checking is done, anyway."
|
|
1362 (unless (or literal noedit)
|
|
1363 (setq noedit t)
|
|
1364 (while (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\(\\\\\\?\\)"
|
|
1365 newtext)
|
|
1366 (setq newtext
|
62458
|
1367 (read-string "Edit replacement string: "
|
|
1368 (prog1
|
|
1369 (cons
|
|
1370 (replace-match "" t t newtext 3)
|
|
1371 (1+ (match-beginning 3)))
|
|
1372 (setq match-data
|
|
1373 (replace-match-data
|
|
1374 nil match-data match-data))))
|
56228
|
1375 noedit nil)))
|
|
1376 (set-match-data match-data)
|
|
1377 (replace-match newtext fixedcase literal)
|
|
1378 noedit)
|
|
1379
|
46693
|
1380 (defun perform-replace (from-string replacements
|
61
|
1381 query-flag regexp-flag delimited-flag
|
40254
|
1382 &optional repeat-count map start end)
|
61
|
1383 "Subroutine of `query-replace'. Its complexity handles interactive queries.
|
|
1384 Don't use this in your own program unless you want to query and set the mark
|
|
1385 just as `query-replace' does. Instead, write a simple loop like this:
|
38675
|
1386
|
|
1387 (while (re-search-forward \"foo[ \\t]+bar\" nil t)
|
61
|
1388 (replace-match \"foobar\" nil nil))
|
38675
|
1389
|
|
1390 which will run faster and probably do exactly what you want. Please
|
|
1391 see the documentation of `replace-match' to find out how to simulate
|
45529
|
1392 `case-replace'.
|
|
1393
|
|
1394 This function returns nil if and only if there were no matches to
|
|
1395 make, or the user didn't cancel the call."
|
2080
|
1396 (or map (setq map query-replace-map))
|
16631
|
1397 (and query-flag minibuffer-auto-raise
|
|
1398 (raise-frame (window-frame (minibuffer-window))))
|
61
|
1399 (let ((nocasify (not (and case-fold-search case-replace
|
|
1400 (string-equal from-string
|
|
1401 (downcase from-string)))))
|
25039
|
1402 (case-fold-search (and case-fold-search
|
|
1403 (string-equal from-string
|
|
1404 (downcase from-string))))
|
53778
|
1405 (literal (or (not regexp-flag) (eq regexp-flag 'literal)))
|
61
|
1406 (search-function (if regexp-flag 're-search-forward 'search-forward))
|
|
1407 (search-string from-string)
|
732
|
1408 (real-match-data nil) ; the match data for the current match
|
61
|
1409 (next-replacement nil)
|
56228
|
1410 (noedit nil)
|
61
|
1411 (keep-going t)
|
|
1412 (stack nil)
|
|
1413 (replace-count 0)
|
18433
|
1414 (nonempty-match nil)
|
|
1415
|
20248
|
1416 ;; If non-nil, it is marker saying where in the buffer to stop.
|
|
1417 (limit nil)
|
|
1418
|
18433
|
1419 ;; Data for the next match. If a cons, it has the same format as
|
|
1420 ;; (match-data); otherwise it is t if a match is possible at point.
|
16725
|
1421 (match-again t)
|
18433
|
1422
|
7258
|
1423 (message
|
|
1424 (if query-flag
|
|
1425 (substitute-command-keys
|
|
1426 "Query replacing %s with %s: (\\<query-replace-map>\\[help] for help) "))))
|
20248
|
1427
|
|
1428 ;; If region is active, in Transient Mark mode, operate on region.
|
28706
|
1429 (when start
|
|
1430 (setq limit (copy-marker (max start end)))
|
|
1431 (goto-char (min start end))
|
|
1432 (deactivate-mark))
|
25167
|
1433
|
|
1434 ;; REPLACEMENTS is either a string, a list of strings, or a cons cell
|
|
1435 ;; containing a function and its first argument. The function is
|
|
1436 ;; called to generate each replacement like this:
|
|
1437 ;; (funcall (car replacements) (cdr replacements) replace-count)
|
|
1438 ;; It must return a string.
|
|
1439 (cond
|
|
1440 ((stringp replacements)
|
|
1441 (setq next-replacement replacements
|
|
1442 replacements nil))
|
|
1443 ((stringp (car replacements)) ; If it isn't a string, it must be a cons
|
|
1444 (or repeat-count (setq repeat-count 1))
|
|
1445 (setq replacements (cons 'replace-loop-through-replacements
|
|
1446 (vector repeat-count repeat-count
|
|
1447 replacements replacements)))))
|
|
1448
|
61
|
1449 (if delimited-flag
|
|
1450 (setq search-function 're-search-forward
|
|
1451 search-string (concat "\\b"
|
|
1452 (if regexp-flag from-string
|
|
1453 (regexp-quote from-string))
|
|
1454 "\\b")))
|
58973
|
1455 (when query-replace-lazy-highlight
|
60713
|
1456 (setq isearch-lazy-highlight-last-string nil))
|
58914
|
1457
|
61
|
1458 (push-mark)
|
|
1459 (undo-boundary)
|
5393
|
1460 (unwind-protect
|
|
1461 ;; Loop finding occurrences that perhaps should be replaced.
|
|
1462 (while (and keep-going
|
56006
21eb4b5cef9a
(perform-replace): Use `limit' to terminate the while-loop explicitly.
Juri Linkov <juri@jurta.org>
diff
changeset
|
1463 (not (or (eobp) (and limit (>= (point) limit))))
|
18433
|
1464 ;; Use the next match if it is already known;
|
|
1465 ;; otherwise, search for a match after moving forward
|
|
1466 ;; one char if progress is required.
|
|
1467 (setq real-match-data
|
|
1468 (if (consp match-again)
|
|
1469 (progn (goto-char (nth 1 match-again))
|
56228
|
1470 (replace-match-data t
|
|
1471 real-match-data
|
|
1472 match-again))
|
18433
|
1473 (and (or match-again
|
29952
|
1474 ;; MATCH-AGAIN non-nil means we
|
|
1475 ;; accept an adjacent match. If
|
|
1476 ;; we don't, move one char to the
|
|
1477 ;; right. This takes us a
|
|
1478 ;; character too far at the end,
|
|
1479 ;; but this is undone after the
|
|
1480 ;; while-loop.
|
56006
21eb4b5cef9a
(perform-replace): Use `limit' to terminate the while-loop explicitly.
Juri Linkov <juri@jurta.org>
diff
changeset
|
1481 (progn
|
21eb4b5cef9a
(perform-replace): Use `limit' to terminate the while-loop explicitly.
Juri Linkov <juri@jurta.org>
diff
changeset
|
1482 (forward-char 1)
|
21eb4b5cef9a
(perform-replace): Use `limit' to terminate the while-loop explicitly.
Juri Linkov <juri@jurta.org>
diff
changeset
|
1483 (not (or (eobp)
|
21eb4b5cef9a
(perform-replace): Use `limit' to terminate the while-loop explicitly.
Juri Linkov <juri@jurta.org>
diff
changeset
|
1484 (and limit (>= (point) limit))))))
|
20248
|
1485 (funcall search-function search-string limit t)
|
18433
|
1486 ;; For speed, use only integers and
|
|
1487 ;; reuse the list used last time.
|
56228
|
1488 (replace-match-data t real-match-data)))))
|
67839
|
1489
|
|
1490 ;; Record whether the match is nonempty, to avoid an infinite loop
|
|
1491 ;; repeatedly matching the same empty string.
|
|
1492 (setq nonempty-match
|
|
1493 (/= (nth 0 real-match-data) (nth 1 real-match-data)))
|
|
1494
|
|
1495 ;; If the match is empty, record that the next one can't be
|
|
1496 ;; adjacent.
|
|
1497
|
|
1498 ;; Otherwise, if matching a regular expression, do the next
|
|
1499 ;; match now, since the replacement for this match may
|
|
1500 ;; affect whether the next match is adjacent to this one.
|
|
1501 ;; If that match is empty, don't use it.
|
|
1502 (setq match-again
|
|
1503 (and nonempty-match
|
|
1504 (or (not regexp-flag)
|
|
1505 (and (looking-at search-string)
|
|
1506 (let ((match (match-data)))
|
|
1507 (and (/= (nth 0 match) (nth 1 match))
|
|
1508 match))))))
|
|
1509
|
40925
|
1510 ;; Optionally ignore matches that have a read-only property.
|
|
1511 (unless (and query-replace-skip-read-only
|
|
1512 (text-property-not-all
|
67839
|
1513 (nth 0 real-match-data) (nth 1 real-match-data)
|
40925
|
1514 'read-only nil))
|
732
|
1515
|
40925
|
1516 ;; Calculate the replacement string, if necessary.
|
|
1517 (when replacements
|
|
1518 (set-match-data real-match-data)
|
|
1519 (setq next-replacement
|
|
1520 (funcall (car replacements) (cdr replacements)
|
56228
|
1521 replace-count)
|
|
1522 noedit nil))
|
40925
|
1523 (if (not query-flag)
|
56262
|
1524 (let ((inhibit-read-only
|
|
1525 query-replace-skip-read-only))
|
58913
|
1526 (unless (or literal noedit)
|
60713
|
1527 (replace-highlight
|
|
1528 (nth 0 real-match-data) (nth 1 real-match-data)
|
|
1529 start end search-string
|
|
1530 (or delimited-flag regexp-flag) case-fold-search))
|
56228
|
1531 (setq noedit
|
|
1532 (replace-match-maybe-edit
|
|
1533 next-replacement nocasify literal
|
|
1534 noedit real-match-data)
|
|
1535 replace-count (1+ replace-count)))
|
40925
|
1536 (undo-boundary)
|
|
1537 (let (done replaced key def)
|
|
1538 ;; Loop reading commands until one of them sets done,
|
56228
|
1539 ;; which means it has finished handling this
|
|
1540 ;; occurrence. Any command that sets `done' should
|
|
1541 ;; leave behind proper match data for the stack.
|
|
1542 ;; Commands not setting `done' need to adjust
|
|
1543 ;; `real-match-data'.
|
40925
|
1544 (while (not done)
|
|
1545 (set-match-data real-match-data)
|
60713
|
1546 (replace-highlight
|
|
1547 (match-beginning 0) (match-end 0)
|
|
1548 start end search-string
|
|
1549 (or delimited-flag regexp-flag) case-fold-search)
|
40925
|
1550 ;; Bind message-log-max so we don't fill up the message log
|
|
1551 ;; with a bunch of identical messages.
|
|
1552 (let ((message-log-max nil))
|
57023
|
1553 (message message
|
|
1554 (query-replace-descr from-string)
|
|
1555 (query-replace-descr next-replacement)))
|
40925
|
1556 (setq key (read-event))
|
|
1557 ;; Necessary in case something happens during read-event
|
|
1558 ;; that clobbers the match data.
|
|
1559 (set-match-data real-match-data)
|
|
1560 (setq key (vector key))
|
|
1561 (setq def (lookup-key map key))
|
|
1562 ;; Restore the match data while we process the command.
|
|
1563 (cond ((eq def 'help)
|
|
1564 (with-output-to-temp-buffer "*Help*"
|
|
1565 (princ
|
|
1566 (concat "Query replacing "
|
|
1567 (if regexp-flag "regexp " "")
|
|
1568 from-string " with "
|
|
1569 next-replacement ".\n\n"
|
|
1570 (substitute-command-keys
|
|
1571 query-replace-help)))
|
|
1572 (with-current-buffer standard-output
|
|
1573 (help-mode))))
|
|
1574 ((eq def 'exit)
|
|
1575 (setq keep-going nil)
|
|
1576 (setq done t))
|
|
1577 ((eq def 'backup)
|
|
1578 (if stack
|
45529
|
1579 (let ((elt (pop stack)))
|
56228
|
1580 (goto-char (nth 0 elt))
|
|
1581 (setq replaced (nth 1 elt)
|
|
1582 real-match-data
|
|
1583 (replace-match-data
|
|
1584 t real-match-data
|
|
1585 (nth 2 elt))))
|
40925
|
1586 (message "No previous match")
|
|
1587 (ding 'no-terminate)
|
|
1588 (sit-for 1)))
|
|
1589 ((eq def 'act)
|
|
1590 (or replaced
|
56228
|
1591 (setq noedit
|
|
1592 (replace-match-maybe-edit
|
|
1593 next-replacement nocasify literal
|
|
1594 noedit real-match-data)
|
|
1595 replace-count (1+ replace-count)))
|
40925
|
1596 (setq done t replaced t))
|
|
1597 ((eq def 'act-and-exit)
|
|
1598 (or replaced
|
56228
|
1599 (setq noedit
|
56273
|
1600 (replace-match-maybe-edit
|
56228
|
1601 next-replacement nocasify literal
|
|
1602 noedit real-match-data)
|
|
1603 replace-count (1+ replace-count)))
|
40925
|
1604 (setq keep-going nil)
|
|
1605 (setq done t replaced t))
|
|
1606 ((eq def 'act-and-show)
|
|
1607 (if (not replaced)
|
56228
|
1608 (setq noedit
|
|
1609 (replace-match-maybe-edit
|
|
1610 next-replacement nocasify literal
|
|
1611 noedit real-match-data)
|
|
1612 replace-count (1+ replace-count)
|
|
1613 real-match-data (replace-match-data
|
|
1614 t real-match-data)
|
|
1615 replaced t)))
|
40925
|
1616 ((eq def 'automatic)
|
|
1617 (or replaced
|
56228
|
1618 (setq noedit
|
|
1619 (replace-match-maybe-edit
|
|
1620 next-replacement nocasify literal
|
|
1621 noedit real-match-data)
|
|
1622 replace-count (1+ replace-count)))
|
40925
|
1623 (setq done t query-flag nil replaced t))
|
|
1624 ((eq def 'skip)
|
|
1625 (setq done t))
|
|
1626 ((eq def 'recenter)
|
|
1627 (recenter nil))
|
|
1628 ((eq def 'edit)
|
|
1629 (let ((opos (point-marker)))
|
56228
|
1630 (setq real-match-data (replace-match-data
|
|
1631 nil real-match-data
|
|
1632 real-match-data))
|
40925
|
1633 (goto-char (match-beginning 0))
|
|
1634 (save-excursion
|
44138
|
1635 (save-window-excursion
|
|
1636 (recursive-edit)))
|
56228
|
1637 (goto-char opos)
|
|
1638 (set-marker opos nil))
|
40925
|
1639 ;; Before we make the replacement,
|
|
1640 ;; decide whether the search string
|
|
1641 ;; can match again just after this match.
|
|
1642 (if (and regexp-flag nonempty-match)
|
|
1643 (setq match-again (and (looking-at search-string)
|
|
1644 (match-data)))))
|
|
1645 ;; Edit replacement.
|
|
1646 ((eq def 'edit-replacement)
|
56228
|
1647 (setq real-match-data (replace-match-data
|
|
1648 nil real-match-data
|
|
1649 real-match-data)
|
|
1650 next-replacement
|
62458
|
1651 (read-string "Edit replacement string: "
|
|
1652 next-replacement)
|
56228
|
1653 noedit nil)
|
|
1654 (if replaced
|
|
1655 (set-match-data real-match-data)
|
|
1656 (setq noedit
|
|
1657 (replace-match-maybe-edit
|
|
1658 next-replacement nocasify literal noedit
|
|
1659 real-match-data)
|
|
1660 replaced t))
|
40925
|
1661 (setq done t))
|
46693
|
1662
|
40925
|
1663 ((eq def 'delete-and-edit)
|
56228
|
1664 (replace-match "" t t)
|
|
1665 (setq real-match-data (replace-match-data
|
|
1666 nil real-match-data))
|
|
1667 (replace-dehighlight)
|
|
1668 (save-excursion (recursive-edit))
|
40925
|
1669 (setq replaced t))
|
|
1670 ;; Note: we do not need to treat `exit-prefix'
|
|
1671 ;; specially here, since we reread
|
|
1672 ;; any unrecognized character.
|
|
1673 (t
|
|
1674 (setq this-command 'mode-exited)
|
|
1675 (setq keep-going nil)
|
|
1676 (setq unread-command-events
|
|
1677 (append (listify-key-sequence key)
|
|
1678 unread-command-events))
|
58914
|
1679 (setq done t)))
|
58973
|
1680 (when query-replace-lazy-highlight
|
|
1681 ;; Force lazy rehighlighting only after replacements
|
58914
|
1682 (if (not (memq def '(skip backup)))
|
58973
|
1683 (setq isearch-lazy-highlight-last-string nil))))
|
40925
|
1684 ;; Record previous position for ^ when we move on.
|
|
1685 ;; Change markers to numbers in the match data
|
|
1686 ;; since lots of markers slow down editing.
|
56228
|
1687 (push (list (point) replaced
|
63779
|
1688 ;;; If the replacement has already happened, all we need is the
|
|
1689 ;;; current match start and end. We could get this with a trivial
|
|
1690 ;;; match like
|
|
1691 ;;; (save-excursion (goto-char (match-beginning 0))
|
|
1692 ;;; (search-forward (match-string 0))
|
|
1693 ;;; (match-data t))
|
|
1694 ;;; if we really wanted to avoid manually constructing match data.
|
|
1695 ;;; Adding current-buffer is necessary so that match-data calls can
|
|
1696 ;;; return markers which are appropriate for editing.
|
56228
|
1697 (if replaced
|
|
1698 (list
|
|
1699 (match-beginning 0)
|
|
1700 (match-end 0)
|
|
1701 (current-buffer))
|
|
1702 (match-data t)))
|
|
1703 stack)))))
|
29952
|
1704
|
|
1705 ;; The code preventing adjacent regexp matches in the condition
|
|
1706 ;; of the while-loop above will haven taken us one character
|
|
1707 ;; beyond the last replacement. Undo that.
|
|
1708 (when (and regexp-flag (not match-again) (> replace-count 0))
|
|
1709 (backward-char 1))
|
46693
|
1710
|
5393
|
1711 (replace-dehighlight))
|
10157
|
1712 (or unread-command-events
|
|
1713 (message "Replaced %d occurrence%s"
|
|
1714 replace-count
|
|
1715 (if (= replace-count 1) "" "s")))
|
|
1716 (and keep-going stack)))
|
61
|
1717
|
5393
|
1718 (defvar replace-overlay nil)
|
|
1719
|
60713
|
1720 (defun replace-highlight (match-beg match-end range-beg range-end
|
|
1721 string regexp case-fold)
|
58973
|
1722 (if query-replace-highlight
|
|
1723 (if replace-overlay
|
60101
|
1724 (move-overlay replace-overlay match-beg match-end (current-buffer))
|
|
1725 (setq replace-overlay (make-overlay match-beg match-end))
|
67426
|
1726 (overlay-put replace-overlay 'priority 1001) ;higher than lazy overlays
|
58973
|
1727 (overlay-put replace-overlay 'face 'query-replace)))
|
60713
|
1728 (if query-replace-lazy-highlight
|
|
1729 (let ((isearch-string string)
|
|
1730 (isearch-regexp regexp)
|
|
1731 (isearch-case-fold-search case-fold))
|
|
1732 (isearch-lazy-highlight-new-loop range-beg range-end))))
|
5393
|
1733
|
58973
|
1734 (defun replace-dehighlight ()
|
|
1735 (when replace-overlay
|
|
1736 (delete-overlay replace-overlay))
|
|
1737 (when query-replace-lazy-highlight
|
60713
|
1738 (lazy-highlight-cleanup lazy-highlight-cleanup)
|
58973
|
1739 (setq isearch-lazy-highlight-last-string nil)))
|
5393
|
1740
|
56355
|
1741 ;; arch-tag: 16b4cd61-fd40-497b-b86f-b667c4cf88e4
|
658
|
1742 ;;; replace.el ends here
|