Mercurial > hg > xemacs-beta
annotate lisp/replace.el @ 5855:0bddb59072b6
Look for cased character classes when deciding on case-fold-search, #'isearch
lisp/ChangeLog addition:
2015-03-11 Aidan Kehoe <kehoea@parhasard.net>
* isearch-mode.el:
* isearch-mode.el (isearch-fix-case):
Use the new #'no-case-regexp-p function if treating ISEARCH-STRING
as a regular expression; otherwise, use the [[:upper:]] character
class.
* isearch-mode.el (isearch-no-upper-case-p): Removed.
* isearch-mode.el (with-caps-disable-folding): Removed.
These two haven't been used since 1998.
* occur.el (occur-1):
Use #'no-case-regexp-p here.
* replace.el (perform-replace):
Don't use #'no-upper-case-p, use #'no-case-regexp-p or
(string-match "[[:upper:]]" ...) as appropriate.
* simple.el:
* simple.el (no-upper-case-p): Removed. This did two different
things, and its secondary function (examining regular expressions)
just became much more complicated; move the regular expression
functionality to its own function, use character classes when
examining non-regular-expressions instead.
The code to look for character classes, and the design decision
that this should be done, are from GNU, thank you Stefan Monnier.
* simple.el (no-case-regexp-p): New.
Given a REGEXP, return non-nil if it has nothing to suggest an
interactive user wants a case-sensitive search.
* simple.el (with-search-caps-disable-folding):
* simple.el (with-interactive-search-caps-disable-folding):
Update both these macros to use #'no-case-regexp-p.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Wed, 11 Mar 2015 18:06:15 +0000 |
parents | c6b1500299a7 |
children | bbe4146603db |
rev | line source |
---|---|
428 | 1 ;;; replace.el --- search and replace commands for XEmacs. |
2 | |
5686
c6b1500299a7
recenter-top-bottom synced from GNU and new default for C-l
Mats Lidell <mats.lidell@cag.se>
parents:
5473
diff
changeset
|
3 ;; Copyright (C) 1985-7, 1992, 1994, 1997, 2003, 2012 Free Software Foundation, Inc. |
428 | 4 |
5 ;; Maintainer: XEmacs Development Team | |
6 ;; Keywords: dumped, matching | |
7 | |
8 ;; This file is part of XEmacs. | |
9 | |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
3000
diff
changeset
|
10 ;; XEmacs is free software: you can redistribute it and/or modify it |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
3000
diff
changeset
|
11 ;; under the terms of the GNU General Public License as published by the |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
3000
diff
changeset
|
12 ;; Free Software Foundation, either version 3 of the License, or (at your |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
3000
diff
changeset
|
13 ;; option) any later version. |
428 | 14 |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
3000
diff
changeset
|
15 ;; XEmacs is distributed in the hope that it will be useful, but WITHOUT |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
3000
diff
changeset
|
16 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
3000
diff
changeset
|
17 ;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
3000
diff
changeset
|
18 ;; for more details. |
428 | 19 |
20 ;; You should have received a copy of the GNU General Public License | |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
3000
diff
changeset
|
21 ;; along with XEmacs. If not, see <http://www.gnu.org/licenses/>. |
428 | 22 |
23 ;;; Synched up with: FSF 19.34 [Partially]. | |
24 | |
25 ;;; Commentary: | |
26 | |
27 ;; This file is dumped with XEmacs. | |
28 | |
29 ;; This package supplies the string and regular-expression replace functions | |
30 ;; documented in the XEmacs Reference Manual. | |
31 | |
32 ;; All the gettext calls are for XEmacs I18N3 message catalog support. | |
33 ;; (This is hopelessly broken and we should remove it. -sb) | |
34 | |
35 ;;; Code: | |
36 | |
37 (defvar case-replace t "\ | |
38 *Non-nil means `query-replace' should preserve case in replacements. | |
39 What this means is that `query-replace' will change the case of the | |
40 replacement text so that it matches the text that was replaced. | |
41 If this variable is nil, the replacement text will be inserted | |
42 exactly as it was specified by the user, irrespective of the case | |
43 of the text that was replaced. | |
44 | |
45 Note that this flag has no effect if `case-fold-search' is nil, | |
46 or if the replacement text has any uppercase letters in it.") | |
47 | |
48 (defvar query-replace-history nil) | |
49 | |
50 (defvar query-replace-interactive nil | |
51 "Non-nil means `query-replace' uses the last search string. | |
52 That becomes the \"string to replace\".") | |
53 | |
54 (defvar replace-search-function | |
55 (lambda (str limit) | |
56 (search-forward str limit t)) | |
444 | 57 "Function used by perform-replace to search forward for a string. It will be |
428 | 58 called with two arguments: the string to search for and a limit bounding the |
59 search.") | |
60 | |
61 (defvar replace-re-search-function | |
62 (lambda (regexp limit) | |
63 (re-search-forward regexp limit t)) | |
64 "Function used by perform-replace to search forward for a regular | |
65 expression. It will be called with two arguments: the regexp to search for and | |
66 a limit bounding the search.") | |
67 | |
68 (defun query-replace-read-args (string regexp-flag) | |
69 (let (from to) | |
70 (if query-replace-interactive | |
71 (setq from (car (if regexp-flag regexp-search-ring search-ring))) | |
72 (setq from (read-from-minibuffer (format "%s: " (gettext string)) | |
73 nil nil nil | |
74 'query-replace-history))) | |
75 (setq to (read-from-minibuffer (format "%s %s with: " (gettext string) | |
76 from) | |
77 nil nil nil | |
78 'query-replace-history)) | |
79 (list from to current-prefix-arg))) | |
80 | |
81 ;; As per suggestion from Per Abrahamsen, limit replacement to the region | |
82 ;; if the region is active. | |
83 (defun query-replace (from-string to-string &optional delimited) | |
84 "Replace some occurrences of FROM-STRING with TO-STRING. | |
85 As each match is found, the user must type a character saying | |
86 what to do with it. For directions, type \\[help-command] at that time. | |
87 | |
88 If `query-replace-interactive' is non-nil, the last incremental search | |
89 string is used as FROM-STRING--you don't have to specify it with the | |
90 minibuffer. | |
91 | |
92 Preserves case in each replacement if `case-replace' and `case-fold-search' | |
93 are non-nil and FROM-STRING has no uppercase letters. | |
94 \(Preserving case means that if the string matched is all caps, or capitalized, | |
95 then its replacement is upcased or capitalized.) | |
96 | |
97 Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace | |
98 only matches surrounded by word boundaries. | |
99 | |
100 To customize possible responses, change the \"bindings\" in `query-replace-map'." | |
101 (interactive (query-replace-read-args "Query replace" nil)) | |
102 (perform-replace from-string to-string t nil delimited)) | |
103 | |
104 (defun query-replace-regexp (regexp to-string &optional delimited) | |
105 "Replace some things after point matching REGEXP with TO-STRING. | |
106 As each match is found, the user must type a character saying | |
107 what to do with it. For directions, type \\[help-command] at that time. | |
108 | |
109 If `query-replace-interactive' is non-nil, the last incremental search | |
110 regexp is used as REGEXP--you don't have to specify it with the | |
111 minibuffer. | |
112 | |
113 Preserves case in each replacement if `case-replace' and `case-fold-search' | |
114 are non-nil and REGEXP has no uppercase letters. | |
115 Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace | |
116 only matches surrounded by word boundaries. | |
117 In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP, | |
118 and `\\=\\N' (where N is a digit) stands for | |
119 whatever what matched the Nth `\\(...\\)' in REGEXP." | |
120 (interactive (query-replace-read-args "Query replace regexp" t)) | |
121 (perform-replace regexp to-string t t delimited)) | |
122 | |
123 ;;#### Not patently useful | |
124 (defun map-query-replace-regexp (regexp to-strings &optional arg) | |
125 "Replace some matches for REGEXP with various strings, in rotation. | |
126 The second argument TO-STRINGS contains the replacement strings, separated | |
127 by spaces. This command works like `query-replace-regexp' except | |
128 that each successive replacement uses the next successive replacement string, | |
129 wrapping around from the last such string to the first. | |
130 | |
131 Non-interactively, TO-STRINGS may be a list of replacement strings. | |
132 | |
133 If `query-replace-interactive' is non-nil, the last incremental search | |
134 regexp is used as REGEXP--you don't have to specify it with the minibuffer. | |
135 | |
136 A prefix argument N says to use each replacement string N times | |
137 before rotating to the next." | |
138 (interactive | |
139 (let (from to) | |
140 (setq from (if query-replace-interactive | |
141 (car regexp-search-ring) | |
142 (read-from-minibuffer "Map query replace (regexp): " | |
143 nil nil nil | |
144 'query-replace-history))) | |
145 (setq to (read-from-minibuffer | |
146 (format "Query replace %s with (space-separated strings): " | |
147 from) | |
148 nil nil nil | |
149 'query-replace-history)) | |
150 (list from to current-prefix-arg))) | |
151 (let (replacements) | |
152 (if (listp to-strings) | |
153 (setq replacements to-strings) | |
5366
f00192e1cd49
Examining the result of #'length: `eql', not `=', it's better style & cheaper
Aidan Kehoe <kehoea@parhasard.net>
parents:
3000
diff
changeset
|
154 (while (not (eql (length to-strings) 0)) |
428 | 155 (if (string-match " " to-strings) |
156 (setq replacements | |
157 (append replacements | |
158 (list (substring to-strings 0 | |
159 (string-match " " to-strings)))) | |
160 to-strings (substring to-strings | |
161 (1+ (string-match " " to-strings)))) | |
162 (setq replacements (append replacements (list to-strings)) | |
163 to-strings "")))) | |
164 (perform-replace regexp replacements t t nil arg))) | |
165 | |
166 (defun replace-string (from-string to-string &optional delimited) | |
167 "Replace occurrences of FROM-STRING with TO-STRING. | |
168 Preserve case in each match if `case-replace' and `case-fold-search' | |
169 are non-nil and FROM-STRING has no uppercase letters. | |
170 \(Preserving case means that if the string matched is all caps, or capitalized, | |
171 then its replacement is upcased or capitalized.) | |
172 | |
173 Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace | |
174 only matches surrounded by word boundaries. | |
175 | |
176 If `query-replace-interactive' is non-nil, the last incremental search | |
177 string is used as FROM-STRING--you don't have to specify it with the | |
178 minibuffer. | |
179 | |
180 This function is usually the wrong thing to use in a Lisp program. | |
181 What you probably want is a loop like this: | |
182 (while (search-forward FROM-STRING nil t) | |
183 (replace-match TO-STRING nil t)) | |
184 which will run faster and will not set the mark or print anything." | |
185 (interactive (query-replace-read-args "Replace string" nil)) | |
186 (perform-replace from-string to-string nil nil delimited)) | |
187 | |
188 (defun replace-regexp (regexp to-string &optional delimited) | |
189 "Replace things after point matching REGEXP with TO-STRING. | |
190 Preserve case in each match if `case-replace' and `case-fold-search' | |
191 are non-nil and REGEXP has no uppercase letters. | |
192 \(Preserving case means that if the string matched is all caps, or capitalized, | |
193 then its replacement is upcased or capitalized.) | |
194 | |
195 Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace | |
196 only matches surrounded by word boundaries. | |
197 In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP, | |
198 and `\\=\\N' (where N is a digit) stands for | |
199 whatever what matched the Nth `\\(...\\)' in REGEXP. | |
200 | |
201 If `query-replace-interactive' is non-nil, the last incremental search | |
202 regexp is used as REGEXP--you don't have to specify it with the minibuffer. | |
203 | |
204 This function is usually the wrong thing to use in a Lisp program. | |
205 What you probably want is a loop like this: | |
206 (while (re-search-forward REGEXP nil t) | |
207 (replace-match TO-STRING nil nil)) | |
208 which will run faster and will not set the mark or print anything." | |
209 (interactive (query-replace-read-args "Replace regexp" t)) | |
210 (perform-replace regexp to-string nil t delimited)) | |
211 | |
212 | |
1069 | 213 |
214 ;; gse wonders: Is there a better place for this to go? Might other packages | |
215 ;; want to use it? | |
428 | 216 (defvar regexp-history nil |
217 "History list for some commands that read regular expressions.") | |
218 | |
1069 | 219 (defun operate-on-non-matching-lines (regexp delete kill &optional beg end) |
220 "Internal function used by delete-non-matching-lines, | |
221 kill-non-matching-lines, and copy-matching-lines. | |
222 | |
223 REGEXP is a regular expression to *not* match when performing | |
224 operations. | |
225 | |
226 If DELETE is non-nil, the lines of text are deleted. It doesn't make | |
227 sense to set this to nil if KILL is nil -- nothing will happen. | |
228 | |
229 If KILL is non-nil, the lines of text are stored in the kill ring (as | |
230 one block of text). | |
231 | |
232 BEG and END, if non-nil, specify the start and end locations to work | |
233 within. If these are nil, point and point-max are used. | |
234 | |
235 A match split across lines preserves all the lines it lies in. | |
236 Applies to all lines after point. | |
237 | |
238 Returns the number of lines matched." | |
239 (with-search-caps-disable-folding regexp t | |
240 (save-excursion | |
241 ;; Move to a beginning point if specified. | |
242 (when beg (goto-char beg)) | |
243 ;; Always start on the beginning of a line. | |
244 (or (bolp) (forward-line 1)) | |
245 | |
246 (let ((matched-text nil) | |
247 (curmatch-start (point)) | |
2610 | 248 (limit (copy-marker (point-max))) |
249 (matched-text-buffer (generate-new-buffer " *matched-text*")) | |
250 lines-matched) | |
1069 | 251 ;; Limit search if limits were specified. |
252 (when end (setq limit (copy-marker end))) | |
253 | |
254 ;; Search. Stop if we are at end of buffer or outside the | |
255 ;; limit. | |
256 (while (not (or | |
257 (eobp) | |
258 (and limit (>= (point) limit)))) | |
259 ;; curmatch-start is first char not preserved by previous match. | |
260 (if (not (re-search-forward regexp limit 'move)) | |
261 (let ((curmatch-end limit)) | |
2610 | 262 (append-to-buffer matched-text-buffer curmatch-start curmatch-end) |
1069 | 263 (if delete (delete-region curmatch-start curmatch-end))) |
264 (let ((curmatch-end (save-excursion (goto-char (match-beginning 0)) | |
2610 | 265 (beginning-of-line) |
266 (point)))) | |
1069 | 267 ;; Now curmatch-end is first char preserved by the new match. |
268 (if (< curmatch-start curmatch-end) | |
269 (progn | |
2610 | 270 (append-to-buffer matched-text-buffer curmatch-start curmatch-end) |
1069 | 271 (if delete (delete-region curmatch-start curmatch-end)))))) |
272 (setq curmatch-start (save-excursion (forward-line 1) | |
2610 | 273 (point))) |
1069 | 274 ;; If the match was empty, avoid matching again at same place. |
275 (and (not (eobp)) (= (match-beginning 0) (match-end 0)) | |
276 (forward-char 1))) | |
277 | |
278 ;; If any lines were matched and KILL is non-nil, insert the | |
279 ;; matched lines into the kill ring. | |
2610 | 280 (setq matched-text (buffer-string matched-text-buffer)) |
1069 | 281 (if (and matched-text kill) (kill-new matched-text)) |
282 | |
283 ;; Return the number of matched lines. | |
2610 | 284 (setq lines-matched |
285 (with-current-buffer matched-text-buffer | |
286 (count-lines (point-min) (point-max)))) | |
287 (kill-buffer matched-text-buffer) | |
288 lines-matched)))) | |
1069 | 289 |
428 | 290 (define-function 'keep-lines 'delete-non-matching-lines) |
291 (defun delete-non-matching-lines (regexp) | |
1069 | 292 "Delete lines that do not match REGEXP, from point to the end of the |
293 buffer (or within the region, if it is active)." | |
428 | 294 (interactive (list (read-from-minibuffer |
295 "Keep lines (containing match for regexp): " | |
296 nil nil nil 'regexp-history))) | |
1069 | 297 (let ((beg nil) |
298 (end nil) | |
299 (count nil)) | |
300 (when (region-active-p) | |
301 (setq beg (region-beginning)) | |
302 (setq end (region-end))) | |
303 (setq count (operate-on-non-matching-lines regexp t nil beg end)) | |
1476 | 304 (when (interactive-p) |
305 (message "%i lines deleted" count)))) | |
1069 | 306 |
307 (defun kill-non-matching-lines (regexp) | |
308 "Delete the lines that do not match REGEXP, from point to the end of | |
309 the buffer (or within the region, if it is active). The deleted lines | |
310 are placed in the kill ring as one block of text." | |
311 (interactive (list (read-from-minibuffer | |
312 "Kill non-matching lines (regexp): " | |
313 nil nil nil 'regexp-history))) | |
314 (let ((beg nil) | |
315 (end nil) | |
316 (count nil)) | |
317 (when (region-active-p) | |
318 (setq beg (region-beginning)) | |
319 (setq end (region-end))) | |
320 (setq count (operate-on-non-matching-lines regexp t t beg end)) | |
1476 | 321 (when (interactive-p) |
322 (message "%i lines killed" count)))) | |
1069 | 323 |
324 (defun copy-non-matching-lines (regexp) | |
325 "Find all lines that do not match REGEXP from point to the end of the | |
326 buffer (or within the region, if it is active), and place them in the | |
327 kill ring as one block of text." | |
328 (interactive (list (read-from-minibuffer | |
329 "Copy non-matching lines (regexp): " | |
330 nil nil nil 'regexp-history))) | |
331 (let ((beg nil) | |
332 (end nil) | |
333 (count nil)) | |
334 (when (region-active-p) | |
335 (setq beg (region-beginning)) | |
336 (setq end (region-end))) | |
337 (setq count (operate-on-non-matching-lines regexp nil t beg end)) | |
1476 | 338 (when (interactive-p) |
339 (message "%i lines copied" count)))) | |
1069 | 340 |
341 (defun operate-on-matching-lines (regexp delete kill &optional beg end) | |
342 "Internal function used by delete-matching-lines, kill-matching-lines, | |
343 and copy-matching-lines. | |
344 | |
345 If DELETE is non-nil, the lines of text are deleted. It doesn't make | |
346 sense to set this to nil if KILL is nil -- nothing will happen. | |
347 | |
348 If KILL is non-nil, the lines of text are stored in the kill ring (as | |
349 one block of text). | |
350 | |
351 BEG and END, if non-nil, specify the start and end locations to work | |
352 within. If these are nil, point and point-max are used. | |
353 | |
354 If a match is split across lines, all the lines it lies in are deleted. | |
355 Applies to lines after point. | |
356 Returns the number of lines matched." | |
357 (with-search-caps-disable-folding regexp t | |
428 | 358 (save-excursion |
1069 | 359 (let ((matched-text nil) |
360 (curmatch-start nil) | |
361 (curmatch-end nil) | |
2610 | 362 (limit nil) |
363 (matched-text-buffer (generate-new-buffer " *matched-text*")) | |
364 lines-matched) | |
1069 | 365 ;; Limit search if limits were specified. |
366 (when beg (goto-char beg)) | |
367 (when end (setq limit (copy-marker end))) | |
368 | |
369 (while (and (not (eobp)) | |
370 (re-search-forward regexp limit t)) | |
371 (setq curmatch-start (save-excursion (goto-char (match-beginning 0)) | |
372 (beginning-of-line) | |
373 (point))) | |
374 (setq curmatch-end (progn (forward-line 1) (point))) | |
2610 | 375 (append-to-buffer matched-text-buffer curmatch-start curmatch-end) |
1069 | 376 (if delete (delete-region curmatch-start curmatch-end))) |
2610 | 377 (setq matched-text (buffer-string matched-text-buffer)) |
1069 | 378 (if (and matched-text kill) (kill-new matched-text)) |
379 | |
380 ;; Return the number of matched lines. | |
2610 | 381 (setq lines-matched |
382 (with-current-buffer matched-text-buffer | |
383 (count-lines (point-min) (point-max)))) | |
384 (kill-buffer matched-text-buffer) | |
385 lines-matched)))) | |
428 | 386 |
387 (define-function 'flush-lines 'delete-matching-lines) | |
388 (defun delete-matching-lines (regexp) | |
1069 | 389 "Delete the lines that match REGEXP, from point to the end of the |
390 buffer (or within the region, if it is active)." | |
428 | 391 (interactive (list (read-from-minibuffer |
392 "Flush lines (containing match for regexp): " | |
393 nil nil nil 'regexp-history))) | |
1069 | 394 (let ((beg nil) |
395 (end nil) | |
396 (count nil)) | |
397 (when (region-active-p) | |
398 (setq beg (region-beginning)) | |
399 (setq end (region-end))) | |
400 (setq count (operate-on-matching-lines regexp t nil beg end)) | |
1476 | 401 (when (interactive-p) |
402 (message "%i lines deleted" count)))) | |
1069 | 403 |
404 (defun kill-matching-lines (regexp) | |
405 "Delete the lines that match REGEXP, from point to the end of the | |
406 buffer (or within the region, if it is active). The deleted lines are | |
407 placed in the kill ring as one block of text." | |
408 (interactive (list (read-from-minibuffer | |
409 "Kill lines (containing match for regexp): " | |
410 nil nil nil 'regexp-history))) | |
411 (let ((beg nil) | |
412 (end nil) | |
413 (count nil)) | |
414 (when (region-active-p) | |
415 (setq beg (region-beginning)) | |
416 (setq end (region-end))) | |
417 (setq count (operate-on-matching-lines regexp t t beg end)) | |
1476 | 418 (when (interactive-p) |
419 (message "%i lines killed" count)))) | |
1069 | 420 |
421 (defun copy-matching-lines (regexp) | |
422 "Find all lines that match REGEXP from point to the end of the | |
423 buffer (or within the region, if it is active), and place them in the | |
424 kill ring as one block of text." | |
425 (interactive (list (read-from-minibuffer | |
426 "Copy lines (containing match for regexp): " | |
427 nil nil nil 'regexp-history))) | |
428 (let ((beg nil) | |
429 (end nil) | |
430 (count nil)) | |
431 (when (region-active-p) | |
432 (setq beg (region-beginning)) | |
433 (setq end (region-end))) | |
434 (setq count (operate-on-matching-lines regexp nil t beg end)) | |
1476 | 435 (when (interactive-p) |
436 (message "%i lines copied" count)))) | |
428 | 437 |
438 (define-function 'how-many 'count-matches) | |
439 (defun count-matches (regexp) | |
440 "Print number of matches for REGEXP following point." | |
441 (interactive (list (read-from-minibuffer | |
442 "How many matches for (regexp): " | |
443 nil nil nil 'regexp-history))) | |
444 (with-interactive-search-caps-disable-folding regexp t | |
445 (let ((count 0) opoint) | |
446 (save-excursion | |
447 (while (and (not (eobp)) | |
448 (progn (setq opoint (point)) | |
449 (re-search-forward regexp nil t))) | |
450 (if (= opoint (point)) | |
451 (forward-char 1) | |
452 (setq count (1+ count)))) | |
453 (message "%d occurrences" count))))) | |
454 | |
455 | |
3000 | 456 ;;; occur code moved to occur.el |
428 | 457 |
458 ;; It would be nice to use \\[...], but there is no reasonable way | |
459 ;; to make that display both SPC and Y. | |
460 (defconst query-replace-help | |
444 | 461 "Type Space or `y' to replace one match, Delete or `n' to skip to next, |
428 | 462 RET or `q' to exit, Period to replace one match and exit, |
463 Comma to replace but not move point immediately, | |
464 C-r to enter recursive edit (\\[exit-recursive-edit] to get out again), | |
465 C-w to delete match and recursive edit, | |
466 C-l to clear the frame, redisplay, and offer same replacement again, | |
467 ! to replace all remaining matches with no more questions, | |
468 ^ to move point back to previous match." | |
444 | 469 |
428 | 470 "Help message while in query-replace") |
471 | |
472 (defvar query-replace-map nil | |
473 "Keymap that defines the responses to questions in `query-replace'. | |
474 The \"bindings\" in this map are not commands; they are answers. | |
475 The valid answers include `act', `skip', `act-and-show', | |
476 `exit', `act-and-exit', `edit', `delete-and-edit', `recenter', | |
477 `automatic', `backup', `exit-prefix', and `help'.") | |
478 | |
479 ;; Why does it seem that ever file has a different method of doing this? | |
480 (if query-replace-map | |
481 nil | |
482 (let ((map (make-sparse-keymap))) | |
483 (set-keymap-name map 'query-replace-map) | |
484 (define-key map " " 'act) | |
485 (define-key map "\d" 'skip) | |
486 (define-key map [delete] 'skip) | |
487 (define-key map [backspace] 'skip) | |
488 (define-key map "y" 'act) | |
489 (define-key map "n" 'skip) | |
490 (define-key map "Y" 'act) | |
491 (define-key map "N" 'skip) | |
492 (define-key map "," 'act-and-show) | |
493 (define-key map [escape] 'exit) | |
494 (define-key map "q" 'exit) | |
495 (define-key map [return] 'exit) | |
496 (define-key map "." 'act-and-exit) | |
497 (define-key map "\C-r" 'edit) | |
498 (define-key map "\C-w" 'delete-and-edit) | |
499 (define-key map "\C-l" 'recenter) | |
500 (define-key map "!" 'automatic) | |
501 (define-key map "^" 'backup) | |
502 (define-key map [(control h)] 'help) ;; XEmacs change | |
503 (define-key map [f1] 'help) | |
504 (define-key map [help] 'help) | |
505 (define-key map "?" 'help) | |
506 (define-key map "\C-g" 'quit) | |
507 (define-key map "\C-]" 'quit) | |
508 ;FSFmacs (define-key map "\e" 'exit-prefix) | |
509 (define-key map [escape] 'exit-prefix) | |
444 | 510 |
428 | 511 (setq query-replace-map map))) |
512 | |
513 ;; isearch-mode is dumped, so don't autoload. | |
514 ;(autoload 'isearch-highlight "isearch") | |
515 | |
516 ;; XEmacs | |
517 (defun perform-replace-next-event (event) | |
442 | 518 (if search-highlight |
428 | 519 (let ((aborted t)) |
520 (unwind-protect | |
521 (progn | |
522 (if (match-beginning 0) | |
523 (isearch-highlight (match-beginning 0) (match-end 0))) | |
524 (next-command-event event) | |
525 (setq aborted nil)) | |
526 (isearch-dehighlight aborted))) | |
527 (next-command-event event))) | |
528 | |
529 (defun perform-replace (from-string replacements | |
530 query-flag regexp-flag delimited-flag | |
531 &optional repeat-count map) | |
532 "Subroutine of `query-replace'. Its complexity handles interactive queries. | |
533 Don't use this in your own program unless you want to query and set the mark | |
534 just as `query-replace' does. Instead, write a simple loop like this: | |
535 (while (re-search-forward \"foo[ \t]+bar\" nil t) | |
536 (replace-match \"foobar\" nil nil)) | |
537 which will run faster and probably do exactly what you want. | |
444 | 538 When searching for a match, this function uses |
539 `replace-search-function' and `replace-re-search-function'." | |
428 | 540 (or map (setq map query-replace-map)) |
541 (let* ((event (make-event)) | |
542 (nocasify (not (and case-fold-search case-replace | |
543 (string-equal from-string | |
544 (downcase from-string))))) | |
545 (literal (not regexp-flag)) | |
444 | 546 (search-function (if regexp-flag |
547 replace-re-search-function | |
428 | 548 replace-search-function)) |
549 (search-string from-string) | |
550 (real-match-data nil) ; the match data for the current match | |
551 (next-replacement nil) | |
552 (replacement-index 0) | |
553 (keep-going t) | |
554 (stack nil) | |
555 (next-rotate-count 0) | |
556 (replace-count 0) | |
557 (lastrepl nil) ;Position after last match considered. | |
558 ;; If non-nil, it is marker saying where in the buffer to | |
559 ;; stop. | |
560 (limit nil) | |
561 (match-again t) | |
5686
c6b1500299a7
recenter-top-bottom synced from GNU and new default for C-l
Mats Lidell <mats.lidell@cag.se>
parents:
5473
diff
changeset
|
562 (recenter-last-op nil) ; Start cycling order with initial position. |
428 | 563 ;; XEmacs addition |
564 (qr-case-fold-search | |
565 (if (and case-fold-search search-caps-disable-folding) | |
5855
0bddb59072b6
Look for cased character classes when deciding on case-fold-search, #'isearch
Aidan Kehoe <kehoea@parhasard.net>
parents:
5686
diff
changeset
|
566 (if regexp-flag |
0bddb59072b6
Look for cased character classes when deciding on case-fold-search, #'isearch
Aidan Kehoe <kehoea@parhasard.net>
parents:
5686
diff
changeset
|
567 (no-case-regexp-p search-string) |
0bddb59072b6
Look for cased character classes when deciding on case-fold-search, #'isearch
Aidan Kehoe <kehoea@parhasard.net>
parents:
5686
diff
changeset
|
568 (save-match-data |
0bddb59072b6
Look for cased character classes when deciding on case-fold-search, #'isearch
Aidan Kehoe <kehoea@parhasard.net>
parents:
5686
diff
changeset
|
569 (let (case-fold-search) |
0bddb59072b6
Look for cased character classes when deciding on case-fold-search, #'isearch
Aidan Kehoe <kehoea@parhasard.net>
parents:
5686
diff
changeset
|
570 (not (string-match "[[:upper:]]" search-string))))) |
428 | 571 case-fold-search)) |
572 (message | |
573 (if query-flag | |
574 (substitute-command-keys | |
575 "Query replacing %s with %s: (\\<query-replace-map>\\[help] for help) ")))) | |
576 ;; If the region is active, operate on region. | |
577 (when (region-active-p) | |
578 ;; Original Per Abrahamsen's code simply narrowed the region, | |
579 ;; thus providing a visual indication of the search boundary. | |
580 ;; Stallman, on the other hand, handles it like this. | |
581 (setq limit (copy-marker (region-end))) | |
582 (goto-char (region-beginning)) | |
583 (zmacs-deactivate-region)) | |
584 (if (stringp replacements) | |
585 (setq next-replacement replacements) | |
586 (or repeat-count (setq repeat-count 1))) | |
587 (if delimited-flag | |
588 (setq search-function replace-re-search-function | |
589 search-string (concat "\\b" | |
590 (if regexp-flag from-string | |
591 (regexp-quote from-string)) | |
592 "\\b"))) | |
593 (push-mark) | |
594 (undo-boundary) | |
595 (unwind-protect | |
596 ;; Loop finding occurrences that perhaps should be replaced. | |
597 (while (and keep-going | |
598 (not (eobp)) | |
599 (or (null limit) (< (point) limit)) | |
600 (let ((case-fold-search qr-case-fold-search)) | |
601 (funcall search-function search-string limit)) | |
602 ;; If the search string matches immediately after | |
603 ;; the previous match, but it did not match there | |
604 ;; before the replacement was done, ignore the match. | |
605 (if (or (eq lastrepl (point)) | |
606 (and regexp-flag | |
607 (eq lastrepl (match-beginning 0)) | |
608 (not match-again))) | |
609 (if (or (eobp) | |
610 (and limit (>= (point) limit))) | |
611 nil | |
444 | 612 ;; Don't replace the null string |
428 | 613 ;; right after end of previous replacement. |
614 (forward-char 1) | |
615 (let ((case-fold-search qr-case-fold-search)) | |
616 (funcall search-function search-string limit))) | |
617 t)) | |
618 | |
619 ;; Save the data associated with the real match. | |
620 (setq real-match-data (match-data)) | |
621 | |
622 ;; Before we make the replacement, decide whether the search string | |
623 ;; can match again just after this match. | |
624 (if regexp-flag | |
444 | 625 (progn |
428 | 626 (setq match-again (looking-at search-string)) |
627 ;; XEmacs addition | |
628 (store-match-data real-match-data))) | |
629 ;; If time for a change, advance to next replacement string. | |
630 (if (and (listp replacements) | |
631 (= next-rotate-count replace-count)) | |
632 (progn | |
633 (setq next-rotate-count | |
634 (+ next-rotate-count repeat-count)) | |
635 (setq next-replacement (nth replacement-index replacements)) | |
636 (setq replacement-index (% (1+ replacement-index) (length replacements))))) | |
637 (if (not query-flag) | |
638 (progn | |
639 (store-match-data real-match-data) | |
640 (replace-match next-replacement nocasify literal) | |
641 (setq replace-count (1+ replace-count))) | |
642 (undo-boundary) | |
643 (let ((help-form | |
644 '(concat (format "Query replacing %s%s with %s.\n\n" | |
645 (if regexp-flag (gettext "regexp ") "") | |
646 from-string next-replacement) | |
647 (substitute-command-keys query-replace-help))) | |
648 done replaced def) | |
649 ;; Loop reading commands until one of them sets done, | |
650 ;; which means it has finished handling this occurrence. | |
651 (while (not done) | |
652 ;; Don't fill up the message log | |
653 ;; with a bunch of identical messages. | |
654 ;; XEmacs change | |
655 (display-message 'prompt | |
656 (format message from-string next-replacement)) | |
657 (perform-replace-next-event event) | |
658 (setq def (lookup-key map (vector event))) | |
659 ;; Restore the match data while we process the command. | |
660 (store-match-data real-match-data) | |
661 (cond ((eq def 'help) | |
662 (with-output-to-temp-buffer (gettext "*Help*") | |
663 (princ (concat | |
664 (format "Query replacing %s%s with %s.\n\n" | |
665 (if regexp-flag "regexp " "") | |
666 from-string next-replacement) | |
667 (substitute-command-keys | |
668 query-replace-help))) | |
669 (save-excursion | |
670 (set-buffer standard-output) | |
671 (help-mode)))) | |
672 ((eq def 'exit) | |
673 (setq keep-going nil) | |
674 (setq done t)) | |
675 ((eq def 'backup) | |
676 (if stack | |
677 (let ((elt (car stack))) | |
678 (goto-char (car elt)) | |
679 (setq replaced (eq t (cdr elt))) | |
680 (or replaced | |
681 (store-match-data (cdr elt))) | |
682 (setq stack (cdr stack))) | |
683 (message "No previous match") | |
684 (ding 'no-terminate) | |
685 (sit-for 1))) | |
686 ((eq def 'act) | |
687 (or replaced | |
688 (replace-match next-replacement nocasify literal)) | |
689 (setq done t replaced t)) | |
690 ((eq def 'act-and-exit) | |
691 (or replaced | |
692 (replace-match next-replacement nocasify literal)) | |
693 (setq keep-going nil) | |
694 (setq done t replaced t)) | |
695 ((eq def 'act-and-show) | |
696 (if (not replaced) | |
697 (progn | |
698 (replace-match next-replacement nocasify literal) | |
699 (store-match-data nil) | |
700 (setq replaced t)))) | |
701 ((eq def 'automatic) | |
702 (or replaced | |
703 (replace-match next-replacement nocasify literal)) | |
704 (setq done t query-flag nil replaced t)) | |
705 ((eq def 'skip) | |
706 (setq done t)) | |
707 ((eq def 'recenter) | |
5686
c6b1500299a7
recenter-top-bottom synced from GNU and new default for C-l
Mats Lidell <mats.lidell@cag.se>
parents:
5473
diff
changeset
|
708 ;; `this-command' has the value `query-replace', |
c6b1500299a7
recenter-top-bottom synced from GNU and new default for C-l
Mats Lidell <mats.lidell@cag.se>
parents:
5473
diff
changeset
|
709 ;; so we need to bind it to `recenter-top-bottom' |
c6b1500299a7
recenter-top-bottom synced from GNU and new default for C-l
Mats Lidell <mats.lidell@cag.se>
parents:
5473
diff
changeset
|
710 ;; to allow it to detect a sequence of `C-l'. |
c6b1500299a7
recenter-top-bottom synced from GNU and new default for C-l
Mats Lidell <mats.lidell@cag.se>
parents:
5473
diff
changeset
|
711 (let ((this-command 'recenter-top-bottom) |
c6b1500299a7
recenter-top-bottom synced from GNU and new default for C-l
Mats Lidell <mats.lidell@cag.se>
parents:
5473
diff
changeset
|
712 (last-command 'recenter-top-bottom)) |
c6b1500299a7
recenter-top-bottom synced from GNU and new default for C-l
Mats Lidell <mats.lidell@cag.se>
parents:
5473
diff
changeset
|
713 (recenter-top-bottom))) |
428 | 714 ((eq def 'edit) |
715 (store-match-data | |
716 (prog1 (match-data) | |
717 (save-excursion (recursive-edit)))) | |
718 ;; Before we make the replacement, | |
719 ;; decide whether the search string | |
720 ;; can match again just after this match. | |
721 (if regexp-flag | |
722 (setq match-again (looking-at search-string)))) | |
723 ((eq def 'delete-and-edit) | |
724 (delete-region (match-beginning 0) (match-end 0)) | |
725 (store-match-data (prog1 (match-data) | |
726 (save-excursion (recursive-edit)))) | |
727 (setq replaced t)) | |
728 ;; Note: we do not need to treat `exit-prefix' | |
729 ;; specially here, since we reread | |
730 ;; any unrecognized character. | |
731 (t | |
732 (setq this-command 'mode-exited) | |
733 (setq keep-going nil) | |
734 (setq unread-command-events | |
735 (cons event unread-command-events)) | |
736 (setq done t)))) | |
5686
c6b1500299a7
recenter-top-bottom synced from GNU and new default for C-l
Mats Lidell <mats.lidell@cag.se>
parents:
5473
diff
changeset
|
737 (unless (eq def 'recenter) |
c6b1500299a7
recenter-top-bottom synced from GNU and new default for C-l
Mats Lidell <mats.lidell@cag.se>
parents:
5473
diff
changeset
|
738 ;; Reset recenter cycling order to initial position. |
c6b1500299a7
recenter-top-bottom synced from GNU and new default for C-l
Mats Lidell <mats.lidell@cag.se>
parents:
5473
diff
changeset
|
739 (setq recenter-last-op nil)) |
428 | 740 ;; Record previous position for ^ when we move on. |
741 ;; Change markers to numbers in the match data | |
742 ;; since lots of markers slow down editing. | |
743 (setq stack | |
744 (cons (cons (point) | |
745 (or replaced | |
746 (match-data t))) | |
747 stack)) | |
748 (if replaced (setq replace-count (1+ replace-count))))) | |
749 (setq lastrepl (point))) | |
750 ;; Useless in XEmacs. We handle (de)highlighting through | |
751 ;; perform-replace-next-event. | |
752 ;(replace-dehighlight) | |
753 ) | |
754 (or unread-command-events | |
755 (message "Replaced %d occurrence%s" | |
756 replace-count | |
757 (if (= replace-count 1) "" "s"))) | |
758 (and keep-going stack))) | |
759 | |
760 ;; FSFmacs code: someone should port it. | |
761 | |
762 ;(defvar query-replace-highlight nil | |
763 ; "*Non-nil means to highlight words during query replacement.") | |
764 | |
765 ;(defvar replace-overlay nil) | |
766 | |
767 ;(defun replace-dehighlight () | |
768 ; (and replace-overlay | |
769 ; (progn | |
770 ; (delete-overlay replace-overlay) | |
771 ; (setq replace-overlay nil)))) | |
772 | |
773 ;(defun replace-highlight (start end) | |
774 ; (and query-replace-highlight | |
775 ; (progn | |
776 ; (or replace-overlay | |
777 ; (progn | |
778 ; (setq replace-overlay (make-overlay start end)) | |
779 ; (overlay-put replace-overlay 'face | |
780 ; (if (internal-find-face 'query-replace) | |
781 ; 'query-replace 'region)))) | |
782 ; (move-overlay replace-overlay start end (current-buffer))))) | |
783 | |
784 ;;; replace.el ends here |