mirrored from git://git.sv.gnu.org/emacs.git
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
Copy pathreplace.el
3396 lines (3117 loc) · 136 KB
/
replace.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;;; replace.el --- replace commands for Emacs -*- lexical-binding: t -*-
;; Copyright (C) 1985-1987, 1992, 1994, 1996-1997, 2000-2025 Free
;; Software Foundation, Inc.
;; Maintainer: emacs-devel@gnu.org
;; Package: emacs
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; This package supplies the string and regular-expression replace functions
;; documented in the Emacs user's manual.
;;; Code:
(require 'text-mode)
(eval-when-compile (require 'cl-lib))
(eval-when-compile (require 'subr-x))
(defcustom case-replace t
"Non-nil means `query-replace' should preserve case in replacements."
:type 'boolean
:group 'matching)
(defcustom replace-char-fold nil
"Non-nil means replacement commands should do character folding in matches.
This means, for instance, that \\=' will match a large variety of
Unicode quotes.
This variable affects `query-replace' and `replace-string', but not
`replace-regexp'."
:type 'boolean
:group 'matching
:version "25.1")
(defcustom replace-lax-whitespace nil
"Non-nil means `query-replace' matches a sequence of whitespace chars.
When you enter a space or spaces in the strings to be replaced,
it will match any sequence matched by the regexp `search-whitespace-regexp'."
:type 'boolean
:group 'matching
:version "24.3")
(defcustom replace-regexp-lax-whitespace nil
"Non-nil means `query-replace-regexp' matches a sequence of whitespace chars.
When you enter a space or spaces in the regexps to be replaced,
it will match any sequence matched by the regexp `search-whitespace-regexp'."
:type 'boolean
:group 'matching
:version "24.3")
(defvar query-replace-history nil
"Default history list for `query-replace' commands.
See `query-replace-from-history-variable' and
`query-replace-to-history-variable'.")
(defvar query-replace-defaults nil
"Default values of FROM-STRING and TO-STRING for `query-replace'.
This is a list of cons cells (FROM-STRING . TO-STRING), or nil
if there are no default values.")
(defcustom query-replace-from-to-separator " → "
"String that separates FROM and TO in the history of replacement pairs.
When nil, the pair will not be added to the history (same behavior
as in Emacs 24.5)."
:group 'matching
:type '(choice
(const :tag "Disabled" nil)
string)
:version "25.1")
(defcustom query-replace-from-history-variable 'query-replace-history
"History list to use for the FROM argument of `query-replace' commands.
The value of this variable should be a symbol; that symbol
is used as a variable to hold a history list for the strings
or patterns to be replaced."
:group 'matching
:type 'symbol
:version "20.3")
(defcustom query-replace-to-history-variable 'query-replace-history
"History list to use for the TO argument of `query-replace' commands.
The value of this variable should be a symbol; that symbol
is used as a variable to hold a history list for replacement
strings or patterns."
:group 'matching
:type 'symbol
:version "20.3")
(defcustom query-replace-skip-read-only nil
"Non-nil means `query-replace' and friends ignore read-only matches."
:type 'boolean
:group 'matching
:version "22.1")
(defcustom query-replace-show-replacement t
"Non-nil means show substituted replacement text in the minibuffer.
This variable affects only `query-replace-regexp'."
:type 'boolean
:group 'matching
:version "23.1")
(defcustom query-replace-highlight t
"Non-nil means to highlight matches during query replacement."
:type 'boolean
:group 'matching)
(defcustom query-replace-highlight-submatches t
"Whether to highlight regexp subexpressions during query replacement.
The faces used to do the highlights are named `isearch-group-1',
`isearch-group-2', etc. (By default, only these 2 are defined.)
When there are more matches than faces, then faces are reused from the
beginning, in a cyclical manner, so the `isearch-group-1' face is
isreused for the third match. If you want to use more distinctive colors,
you can define more of these faces using the same numbering scheme."
:type 'boolean
:group 'matching
:version "28.1")
(defcustom query-replace-lazy-highlight t
"Controls the lazy-highlighting during query replacements.
When non-nil, all text in the buffer matching the current match
is highlighted lazily using isearch lazy highlighting (see
`lazy-highlight-initial-delay' and `lazy-highlight-interval')."
:type 'boolean
:group 'lazy-highlight
:group 'matching
:version "22.1")
(defface query-replace
'((t (:inherit isearch)))
"Face for highlighting query replacement matches."
:group 'matching
:version "22.1")
(defvar replace-count 0
"Number of replacements done so far.
See `replace-regexp'.")
(defun query-replace-descr (string)
(setq string (copy-sequence string))
(dotimes (i (length string))
(let ((c (aref string i)))
(cond
((< c ?\s) (add-text-properties
i (1+ i)
`(display ,(propertize (format "^%c" (+ c 64)) 'face 'escape-glyph))
string))
((= c ?\^?) (add-text-properties
i (1+ i)
`(display ,(propertize "^?" 'face 'escape-glyph))
string)))))
string)
(defun query-replace--split-string (string)
"Split string STRING at a substring with property `separator'."
(let* ((length (length string))
(split-pos (text-property-any 0 length 'separator t string)))
(if (not split-pos)
string
(cons (substring string 0 split-pos)
(substring-no-properties
string (or (text-property-not-all
(1+ split-pos) length 'separator t string)
length)
length)))))
(defvar query-replace-read-from-default nil
"Function to get default non-regexp value for `query-replace-read-from'.")
(defvar query-replace-read-from-regexp-default nil
"Function to get default regexp value for `query-replace-read-from'.")
(defun query-replace-read-from-suggestions ()
"Return a list of standard suggestions for `query-replace-read-from'.
By default, the list includes the active region, the identifier
(a.k.a. \"tag\") at point (see Info node `(emacs) Identifier Search'),
the last isearch string, and the last replacement regexp.
`query-replace-read-from' appends the list returned
by this function to the end of values available via
\\<minibuffer-local-map>\\[next-history-element]."
(delq nil (list (when (use-region-p)
(buffer-substring-no-properties
(region-beginning) (region-end)))
(find-tag-default)
(car search-ring)
(car (symbol-value query-replace-from-history-variable)))))
(defun query-replace-read-from (prompt regexp-flag)
"Query and return the `from' argument of a `query-replace' operation.
Prompt with PROMPT. REGEXP-FLAG non-nil means the response should be a regexp.
The return value can also be a pair (FROM . TO) indicating that the user
wants to replace FROM with TO."
(let* ((history-add-new-input nil)
(separator-string
(when query-replace-from-to-separator
;; Check if the first non-whitespace char is displayable
(if (char-displayable-p
(string-to-char (string-replace
" " "" query-replace-from-to-separator)))
query-replace-from-to-separator
" -> ")))
(separator
(when separator-string
(propertize separator-string
'display separator-string
'face 'minibuffer-prompt
'separator t)))
(minibuffer-history
(append
(when separator
(mapcar (lambda (from-to)
(concat (query-replace-descr (car from-to))
separator
(query-replace-descr (cdr from-to))))
query-replace-defaults))
(symbol-value query-replace-from-history-variable)))
(minibuffer-allow-text-properties t) ; separator uses text-properties
(default (when (and query-replace-read-from-default (not regexp-flag))
(funcall query-replace-read-from-default)))
(prompt
(cond ((and query-replace-read-from-regexp-default regexp-flag) prompt)
(default (format-prompt prompt default))
((and query-replace-defaults separator)
(format-prompt prompt (car minibuffer-history)))
(query-replace-defaults
(format-prompt
prompt (format "%s -> %s"
(query-replace-descr
(caar query-replace-defaults))
(query-replace-descr
(cdar query-replace-defaults)))))
(t (format-prompt prompt nil))))
(from
;; The save-excursion here is in case the user marks and copies
;; a region in order to specify the minibuffer input.
;; That should not clobber the region for the query-replace itself.
(save-excursion
(minibuffer-with-setup-hook
(lambda ()
(setq-local text-property-default-nonsticky
(append '((separator . t) (face . t))
text-property-default-nonsticky)))
(if regexp-flag
(read-regexp
(if query-replace-read-from-regexp-default
(string-remove-suffix ": " prompt)
prompt)
query-replace-read-from-regexp-default
'minibuffer-history)
(read-from-minibuffer
prompt nil nil nil nil
(if default
(delete-dups
(cons default (query-replace-read-from-suggestions)))
(query-replace-read-from-suggestions))
t)))))
(to))
(if (and (zerop (length from)) query-replace-defaults (not default))
(cons (caar query-replace-defaults)
(query-replace-compile-replacement
(cdar query-replace-defaults) regexp-flag))
(setq from (or (and (zerop (length from)) default)
(query-replace--split-string from)))
(when (consp from) (setq to (cdr from) from (car from)))
(add-to-history query-replace-from-history-variable from nil t)
;; Warn if user types \n or \t, but don't reject the input.
(and regexp-flag
(string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\(\\\\[nt]\\)" from)
(let ((match (match-string 3 from)))
(cond
((string= match "\\n")
(message "Note: `\\n' here doesn't match a newline; to do that, type C-q C-j instead"))
((string= match "\\t")
(message "Note: `\\t' here doesn't match a tab; to do that, just type TAB")))
(sit-for 2)))
(if (not to)
from
(add-to-history query-replace-to-history-variable to nil t)
(add-to-history 'query-replace-defaults (cons from to) nil t)
(cons from (query-replace-compile-replacement to regexp-flag))))))
(defun query-replace-compile-replacement (to regexp-flag)
"Maybe convert a regexp replacement TO to Lisp.
REGEXP-FLAG non-nil means TO is a regexp.
Returns a list suitable for `perform-replace' if necessary,
the original string if not."
(if (and regexp-flag
(string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" to))
(let (pos list char)
(while
(progn
(setq pos (match-end 0))
(push (substring to 0 (- pos 2)) list)
(setq char (aref to (1- pos))
to (substring to pos))
(cond ((eq char ?\#)
(push '(number-to-string replace-count) list))
((eq char ?\,)
(setq pos (read-from-string to))
(push `(replace-quote ,(car pos)) list)
(let ((end
;; Swallow a space after a symbol
;; if there is a space.
(if (and (or (symbolp (car pos))
;; Swallow a space after 'foo
;; but not after (quote foo).
(and (eq (car-safe (car pos)) 'quote)
(not (= ?\( (aref to 0)))))
(eq (string-search " " to (cdr pos))
(cdr pos)))
(1+ (cdr pos))
(cdr pos))))
(setq to (substring to end)))))
(string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" to)))
(setq to (nreverse (delete "" (cons to list))))
(replace-match-string-symbols to)
(cons #'replace-eval-replacement
(if (cdr to)
(cons 'concat to)
(car to))))
to))
(defun query-replace-read-to (from prompt regexp-flag)
"Query and return the `to' argument of a `query-replace' operation.
Prompt with PROMPT. REGEXP-FLAG non-nil means the response
should a regexp."
(query-replace-compile-replacement
(save-excursion
(let* ((history-add-new-input nil)
(to (read-from-minibuffer
(format "%s %s with: " prompt (query-replace-descr from))
nil nil nil
query-replace-to-history-variable from t)))
(add-to-history query-replace-to-history-variable to nil t)
(add-to-history 'query-replace-defaults (cons from to) nil t)
to))
regexp-flag))
(defun query-replace-read-args (prompt regexp-flag &optional noerror no-highlight)
(unless noerror
(barf-if-buffer-read-only))
(save-mark-and-excursion
(let* ((delimited-flag (and current-prefix-arg
(not (eq current-prefix-arg '-))))
(from (minibuffer-with-setup-hook
(minibuffer-lazy-highlight-setup
:case-fold case-fold-search
:filter (when (use-region-p)
(replace--region-filter
(funcall region-extract-function 'bounds)))
:highlight (and query-replace-lazy-highlight (not no-highlight))
:regexp regexp-flag
:regexp-function (or replace-regexp-function
delimited-flag
(and replace-char-fold
(not regexp-flag)
#'char-fold-to-regexp))
:transform (lambda (string)
(let* ((split (query-replace--split-string string))
(from-string (if (consp split) (car split) split)))
(when (and case-fold-search search-upper-case)
(setq isearch-case-fold-search
(isearch-no-upper-case-p from-string regexp-flag)))
from-string)))
(query-replace-read-from prompt regexp-flag)))
(to (if (consp from) (prog1 (cdr from) (setq from (car from)))
(query-replace-read-to from prompt regexp-flag))))
(list from to
(or delimited-flag
(and (plist-member (text-properties-at 0 from) 'isearch-regexp-function)
(get-text-property 0 'isearch-regexp-function from)))
(and current-prefix-arg (eq current-prefix-arg '-))))))
(defun query-replace (from-string to-string &optional delimited start end backward region-noncontiguous-p)
"Replace some occurrences of FROM-STRING with TO-STRING.
As each match is found, the user must type a character saying
what to do with it. Type SPC or `y' to replace the match,
DEL or `n' to skip and go to the next match. For more directions,
type \\[help-command] at that time.
In Transient Mark mode, if the mark is active, operate on the contents
of the region. Otherwise, operate from point to the end of the buffer's
accessible portion.
In interactive use, the prefix arg (non-nil DELIMITED in
non-interactive use), means replace only matches surrounded by
word boundaries. A negative prefix arg means replace backward.
Use \\<minibuffer-local-map>\\[next-history-element] \
to pull the last incremental search string to the minibuffer
that reads FROM-STRING, or invoke replacements from
incremental search with a key sequence like \\`C-s C-s M-%'
to use its current search string as the string to replace.
Matching is independent of case if both `case-fold-search'
and `search-upper-case' are non-nil and FROM-STRING has no
uppercase letters; if `search-upper-case' is nil, then
whether matching ignores case depends on `case-fold-search'
regardless of whether there are uppercase letters in FROM-STRING.
Replacement transfers the case pattern of the old text to the
new text, if both `case-fold-search' and `case-replace' are
non-nil and FROM-STRING has no uppercase letters.
\(Transferring the case pattern means that if the old text
matched is all caps, or all of its words are capitalized, then its
replacement is respectively upcased or capitalized. For more
details about this, see `replace-match'.)
Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
ignore hidden matches if `search-invisible' is nil, and ignore more
matches using `isearch-filter-predicate'.
If `replace-lax-whitespace' is non-nil, a space or spaces in the string
to be replaced will match a sequence of whitespace chars defined by the
regexp in `search-whitespace-regexp'.
If `replace-char-fold' is non-nil, matching uses character folding,
i.e. it ignores diacritics and other differences between equivalent
character strings.
Fourth and fifth arg START and END specify the region to operate on.
Arguments FROM-STRING, TO-STRING, DELIMITED, START, END, BACKWARD, and
REGION-NONCONTIGUOUS-P are passed to `perform-replace' (which see).
\(TO-STRING is passed to `perform-replace' as REPLACEMENTS and
DELIMITED is passed as DELIMITED-FLAG.)
To customize possible responses, change the bindings in `query-replace-map'."
(declare (interactive-args
(start (use-region-beginning))
(end (use-region-end))
(region-noncontiguous-p (use-region-noncontiguous-p))))
(interactive
(let ((common
(query-replace-read-args
(concat "Query replace"
(if current-prefix-arg
(if (eq current-prefix-arg '-) " backward" " word")
"")
(if (use-region-p) " in region" ""))
nil)))
(list (nth 0 common) (nth 1 common) (nth 2 common)
;; These are done separately here
;; so that command-history will record these expressions
;; rather than the values they had this time.
(use-region-beginning) (use-region-end)
(nth 3 common)
(use-region-noncontiguous-p))))
(perform-replace from-string to-string t nil delimited nil nil start end backward region-noncontiguous-p))
(define-key esc-map "%" 'query-replace)
(defun query-replace-regexp (regexp to-string &optional delimited start end backward region-noncontiguous-p)
"Replace some things after point matching REGEXP with TO-STRING.
As each match is found, the user must type a character saying
what to do with it. Type \\`SPC' or \\`y' to replace the match,
\\`DEL' or \\`n' to skip and go to the next match. For more directions,
type \\[help-command] at that time.
In Transient Mark mode, if the mark is active, operate on the contents
of the region. Otherwise, operate from point to the end of the buffer's
accessible portion.
When invoked interactively, matching a newline with `\\n' will not work;
use \\`C-q C-j' instead. To match a tab character (`\\t'), just press \\`TAB'.
Use \\<minibuffer-local-map>\\[next-history-element] \
to pull the last incremental search regexp to the minibuffer
that reads REGEXP, or invoke replacements from
incremental search with a key sequence like \\`C-M-s C-M-s C-M-%'
to use its current search regexp as the regexp to replace.
Matching is independent of case if both `case-fold-search'
and `search-upper-case' are non-nil and REGEXP has no uppercase
letters; if `search-upper-case' is nil, then whether matching
ignores case depends on `case-fold-search' regardless of whether
there are uppercase letters in REGEXP.
Replacement transfers the case pattern of the old text to the new
text, if both `case-fold-search' and `case-replace' are non-nil
and REGEXP has no uppercase letters. (Transferring the case pattern
means that if the old text matched is all caps, or all of its words
are capitalized, then its replacement is respectively upcased or
capitalized. For more details about this, see `replace-match'.)
Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
ignore hidden matches if `search-invisible' is nil, and ignore more
matches using `isearch-filter-predicate'.
If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp
to be replaced will match a sequence of whitespace chars defined by the
regexp in `search-whitespace-regexp'.
This function is not affected by `replace-char-fold'.
Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
only matches surrounded by word boundaries. A negative prefix arg means
replace backward.
Fourth and fifth arg START and END specify the region to operate on.
In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
and `\\=\\N' (where N is a digit) stands for whatever matched
the Nth `\\(...\\)' (1-based) in REGEXP. The `\\(...\\)' groups are
counted from 1.
`\\?' lets you edit the replacement text in the minibuffer
at the given position for each replacement.
In interactive calls, the replacement text can contain `\\,'
followed by a Lisp expression. Each
replacement evaluates that expression to compute the replacement
string. Inside of that expression, `\\&' is a string denoting the
whole match as a string, `\\N' for a partial match, `\\#&' and `\\#N'
for the whole or a partial match converted to a number with
`string-to-number', and `\\#' itself for the number of replacements
done so far (starting with zero).
If the replacement expression is a symbol, write a space after it
to terminate it. One space there, if any, will be discarded.
When using those Lisp features interactively in the replacement
text, TO-STRING is actually made a list instead of a string.
Use \\[repeat-complex-command] after this command for details.
Arguments REGEXP, TO-STRING, DELIMITED, START, END, BACKWARD, and
REGION-NONCONTIGUOUS-P are passed to `perform-replace' (which see).
\(REGEXP is passed to `perform-replace' as FROM-STRING,
TO-STRING is passed as REPLACEMENTS, and DELIMITED is passed
as DELIMITED-FLAG.)"
(declare (interactive-args
(start (use-region-beginning))
(end (use-region-end))
(region-noncontiguous-p (use-region-noncontiguous-p))))
(interactive
(let ((common
(query-replace-read-args
(concat "Query replace"
(if current-prefix-arg
(if (eq current-prefix-arg '-) " backward" " word")
"")
" regexp"
(if (use-region-p) " in region" ""))
t)))
(list (nth 0 common) (nth 1 common) (nth 2 common)
;; These are done separately here
;; so that command-history will record these expressions
;; rather than the values they had this time.
(use-region-beginning) (use-region-end)
(nth 3 common)
(use-region-noncontiguous-p))))
(perform-replace regexp to-string t t delimited nil nil start end backward region-noncontiguous-p))
(define-key esc-map [?\C-%] 'query-replace-regexp)
(defun map-query-replace-regexp (regexp to-strings &optional n start end region-noncontiguous-p)
"Replace some matches for REGEXP with various strings, in rotation.
The second argument TO-STRINGS contains the replacement strings, separated
by spaces. This command works like `query-replace-regexp' except that
each successive replacement uses the next successive replacement string,
wrapping around from the last such string to the first.
In Transient Mark mode, if the mark is active, operate on the contents
of the region. Otherwise, operate from point to the end of the buffer's
accessible portion.
Non-interactively, TO-STRINGS may be a list of replacement strings.
Interactively, reads the regexp using `read-regexp'.
Use \\<minibuffer-local-map>\\[next-history-element] \
to pull the last incremental search regexp to the minibuffer
that reads REGEXP.
As each match is found, the user must type a character saying
what to do with it. Type SPC or `y' to replace the match,
DEL or `n' to skip and go to the next match. For more directions,
type \\[help-command] at that time.
A prefix argument N says to use each replacement string N times
before rotating to the next.
Fourth and fifth arg START and END specify the region to operate on.
Arguments REGEXP, START, END, and REGION-NONCONTIGUOUS-P are passed to
`perform-replace' (which see)."
(declare (interactive-args
(start (use-region-beginning))
(end (use-region-end))
(region-noncontiguous-p (use-region-noncontiguous-p))))
(interactive
(let* ((from (read-regexp "Map query replace (regexp): " nil
query-replace-from-history-variable))
(to (read-from-minibuffer
(format "Query replace %s with (space-separated strings): "
(query-replace-descr from))
nil nil nil
query-replace-to-history-variable from t)))
(list from to
(and current-prefix-arg
(prefix-numeric-value current-prefix-arg))
(use-region-beginning) (use-region-end)
(use-region-noncontiguous-p))))
(let (replacements)
(if (listp to-strings)
(setq replacements to-strings)
(while (/= (length to-strings) 0)
(if (string-search " " to-strings)
(setq replacements
(append replacements
(list (substring to-strings 0
(string-search " " to-strings))))
to-strings (substring to-strings
(1+ (string-search " " to-strings))))
(setq replacements (append replacements (list to-strings))
to-strings ""))))
(perform-replace regexp replacements t t nil n nil start end nil region-noncontiguous-p)))
(defun replace-string (from-string to-string &optional delimited start end backward region-noncontiguous-p)
"Replace occurrences of FROM-STRING with TO-STRING.
Preserve case in each match if `case-replace' and `case-fold-search'
are non-nil and FROM-STRING has no uppercase letters.
\(Preserving case means that if the string matched is all caps, or capitalized,
then its replacement is upcased or capitalized.)
Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
ignore hidden matches if `search-invisible' is nil, and ignore more
matches using `isearch-filter-predicate'.
If `replace-lax-whitespace' is non-nil, a space or spaces in the string
to be replaced will match a sequence of whitespace chars defined by the
regexp in `search-whitespace-regexp'.
If `replace-char-fold' is non-nil, matching uses character folding,
i.e. it ignores diacritics and other differences between equivalent
character strings.
Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
only matches surrounded by word boundaries. A negative prefix arg means
replace backward.
Operates on the region between START and END (if both are nil, from point
to the end of the buffer). Interactively, if Transient Mark mode is
enabled and the mark is active, operates on the contents of the region;
otherwise from point to the end of the buffer's accessible portion.
Arguments BACKWARD and REGION-NONCONTIGUOUS-P are passed
to `perform-replace' (which see).
Use \\<minibuffer-local-map>\\[next-history-element] \
to pull the last incremental search string to the minibuffer
that reads FROM-STRING.
This function is usually the wrong thing to use in a Lisp program.
What you probably want is a loop like this:
(while (search-forward FROM-STRING nil t)
(replace-match TO-STRING nil t))
which will run faster and will not set the mark or print anything.
\(You may need a more complex loop if FROM-STRING can match the null string
and TO-STRING is also null.)"
(declare (interactive-only
"use `search-forward' and `replace-match' instead.")
(interactive-args
(start (use-region-beginning))
(end (use-region-end))
(region-noncontiguous-p (use-region-noncontiguous-p))))
(interactive
(let ((common
(query-replace-read-args
(concat "Replace"
(if current-prefix-arg
(if (eq current-prefix-arg '-) " backward" " word")
"")
" string"
(if (use-region-p) " in region" ""))
nil)))
(list (nth 0 common) (nth 1 common) (nth 2 common)
(use-region-beginning) (use-region-end)
(nth 3 common)
(use-region-noncontiguous-p))))
(perform-replace from-string to-string nil nil delimited nil nil start end backward region-noncontiguous-p))
(defun replace-regexp (regexp to-string &optional delimited start end backward region-noncontiguous-p)
"Replace things after point matching REGEXP with TO-STRING.
Preserve case in each match if `case-replace' and `case-fold-search'
are non-nil and REGEXP has no uppercase letters.
Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
ignore hidden matches if `search-invisible' is nil, and ignore more
matches using `isearch-filter-predicate'.
If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp
to be replaced will match a sequence of whitespace chars defined by the
regexp in `search-whitespace-regexp'.
This function is not affected by `replace-char-fold'
In Transient Mark mode, if the mark is active, operate on the contents
of the region. Otherwise, operate from point to the end of the buffer's
accessible portion.
Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
only matches surrounded by word boundaries. A negative prefix arg means
replace backward.
Fourth and fifth arg START and END specify the region to operate on.
Arguments BACKWARD and REGION-NONCONTIGUOUS-P are passed
to `perform-replace' (which see).
In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
and `\\=\\N' (where N is a digit) stands for whatever matched
the Nth `\\(...\\)' (1-based) in REGEXP.
`\\?' lets you edit the replacement text in the minibuffer
at the given position for each replacement.
In interactive calls, the replacement text may contain `\\,'
followed by a Lisp expression used as part of the replacement
text. Inside of that expression, `\\&' is a string denoting the
whole match, `\\N' a partial match, `\\#&' and `\\#N' the respective
numeric values from `string-to-number', and `\\#' itself for
`replace-count', the number of replacements occurred so far, starting
from zero.
If your Lisp expression is an identifier and the next letter in
the replacement string would be interpreted as part of it, you
can wrap it with an expression like `\\,(or \\#)'. Incidentally,
for this particular case you may also enter `\\#' in the
replacement text directly.
When using those Lisp features interactively in the replacement
text, TO-STRING is actually made a list instead of a string.
Use \\[repeat-complex-command] after this command for details.
Use \\<minibuffer-local-map>\\[next-history-element] \
to pull the last incremental search regexp to the minibuffer
that reads REGEXP.
This function is usually the wrong thing to use in a Lisp program.
What you probably want is a loop like this:
(while (re-search-forward REGEXP nil t)
(replace-match TO-STRING nil nil))
which will run faster and will not set the mark or print anything."
(declare (interactive-only
"use `re-search-forward' and `replace-match' instead.")
(interactive-args
(start (use-region-beginning))
(end (use-region-end))
(region-noncontiguous-p (use-region-noncontiguous-p))))
(interactive
(let ((common
(query-replace-read-args
(concat "Replace"
(if current-prefix-arg
(if (eq current-prefix-arg '-) " backward" " word")
"")
" regexp"
(if (use-region-p) " in region" ""))
t)))
(list (nth 0 common) (nth 1 common) (nth 2 common)
(use-region-beginning) (use-region-end)
(nth 3 common)
(use-region-noncontiguous-p))))
(perform-replace regexp to-string nil t delimited nil nil start end backward region-noncontiguous-p))
(defvar regexp-history nil
"History list for some commands that read regular expressions.
Maximum length of the history list is determined by the value
of `history-length', which see.")
(defvar occur-highlight-overlays nil
"Overlays used to temporarily highlight occur matches.")
(defvar occur-collect-regexp-history '("\\1")
"History of regexp for occur's collect operation.")
(defcustom read-regexp-defaults-function nil
"Function that provides default regexp(s) for `read-regexp'.
This function should take no arguments and return one of: nil, a
regexp, or a list of regexps. Interactively, `read-regexp' uses
the return value of this function for its DEFAULT argument.
As an example, set this variable to `find-tag-default-as-regexp'
to default to the symbol at point.
To provide different default regexps for different commands,
the function that you set this to can check `this-command'."
:type '(choice
(const :tag "No default regexp reading function" nil)
(const :tag "Latest regexp history" regexp-history-last)
(function-item :tag "Tag at point"
find-tag-default)
(function-item :tag "Tag at point as regexp"
find-tag-default-as-regexp)
(function-item :tag "Tag at point as symbol regexp"
find-tag-default-as-symbol-regexp)
(function :tag "Your choice of function"))
:group 'matching
:version "24.4")
(defun read-regexp-suggestions ()
"Return a list of standard suggestions for `read-regexp'.
By default, the list includes the active region, the identifier
(a.k.a. \"tag\") at point (see Info node `(emacs) Identifier Search'),
the last isearch regexp, the last isearch string, and the last
replacement regexp. `read-regexp' appends the list returned
by this function to the end of values available via
\\<minibuffer-local-map>\\[next-history-element]."
(list
(when (use-region-p)
(buffer-substring-no-properties
(region-beginning) (region-end)))
(find-tag-default-as-regexp)
(find-tag-default-as-symbol-regexp)
(car regexp-search-ring)
(regexp-quote (or (car search-ring) ""))
(car (symbol-value query-replace-from-history-variable))))
(defvar-keymap read-regexp-map
:parent minibuffer-local-map
"M-s c" #'read-regexp-toggle-case-fold)
(defvar read-regexp--case-fold nil)
(defun read-regexp-toggle-case-fold ()
(interactive)
(setq read-regexp--case-fold
(if (or (eq read-regexp--case-fold 'fold)
(and read-regexp--case-fold
(not (eq read-regexp--case-fold 'inhibit-fold))))
'inhibit-fold
'fold))
(minibuffer-message "Case folding is now %s"
(if (eq read-regexp--case-fold 'fold) "on" "off")))
(defun read-regexp (prompt &optional defaults history)
"Read and return a regular expression as a string.
Prompt with the string PROMPT. If PROMPT ends in \":\" (followed by
optional whitespace), use it as-is. Otherwise, add \": \" to the end,
possibly preceded by the default result (see below).
The optional argument DEFAULTS is used to construct the default
return value in case of empty input. DEFAULTS can be nil, a string,
a list of strings, or a symbol.
If DEFAULTS is a string, the function uses it as-is.
If DEFAULTS is a list of strings, the first element is the
default return value, but all the elements are accessible
using the history command \\<minibuffer-local-map>\\[next-history-element].
If DEFAULTS is the symbol `regexp-history-last', the default return
value will be the first element of HISTORY. If HISTORY is omitted or
nil, `regexp-history' is used instead.
If DEFAULTS is a symbol with a function definition, it is called with
no arguments and should return either nil, a string, or a list of
strings, which will be used as above.
Other symbol values for DEFAULTS are ignored.
If `read-regexp-defaults-function' is non-nil, its value is used
instead of DEFAULTS in the two cases described in the last paragraph.
Before using whatever value DEFAULTS yields, the function appends the
standard values from `read-regexp-suggestions' to that value.
If the first element of DEFAULTS is non-nil (and if PROMPT does not end
in \":\", followed by optional whitespace), DEFAULT is added to the prompt.
The optional argument HISTORY is a symbol to use for the history list.
If nil, use `regexp-history'.
If the user has used the \\<read-regexp-map>\\[read-regexp-toggle-case-fold] command to specify case
sensitivity, the returned string will have a text property named
`case-fold' that has a value of either `fold' or
`inhibit-fold'. (It's up to the caller of `read-regexp' to
respect this or not; see `read-regexp-case-fold-search'.)
This command uses the `read-regexp-map' keymap while reading the
regexp from the user."
(let* ((defaults
(if (and defaults (symbolp defaults))
(cond
((eq (or read-regexp-defaults-function defaults)
'regexp-history-last)
(car (symbol-value (or history 'regexp-history))))
((functionp (or read-regexp-defaults-function defaults))
(funcall (or read-regexp-defaults-function defaults))))
defaults))
(default (if (consp defaults) (car defaults) defaults))
(suggestions (if (listp defaults) defaults (list defaults)))
(suggestions (append suggestions (read-regexp-suggestions)))
(suggestions (delete-dups (delq nil (delete "" suggestions))))
;; Do not automatically add default to the history for empty input.
(history-add-new-input nil)
;; `read-regexp--case-fold' dynamically bound and may be
;; altered by `M-c'.
(read-regexp--case-fold case-fold-search)
(input (read-from-minibuffer
(if (string-match-p ":[ \t]*\\'" prompt)
prompt
(format-prompt prompt (and (length> default 0)
(query-replace-descr default))))
nil read-regexp-map
nil (or history 'regexp-history) suggestions t))
(result (if (equal input "")
;; Return the default value when the user enters
;; empty input.
default
input)))
(when result
(add-to-history (or history 'regexp-history) result))
(if (and result
(or (eq read-regexp--case-fold 'fold)
(eq read-regexp--case-fold 'inhibit-fold)))
(propertize result 'case-fold read-regexp--case-fold)
(or result input))))
(defun read-regexp-case-fold-search (regexp)
"Return the value for `case-fold-search' based on REGEXP and current settings.
REGEXP is a string as returned by `read-regexp'."
(let ((fold (get-text-property 0 'case-fold regexp)))
(cond
((eq fold 'fold) t)
((eq fold 'inhibit-fold) nil)
(t case-fold-search))))
(defalias 'delete-non-matching-lines 'keep-lines)
(defalias 'delete-matching-lines 'flush-lines)
(defalias 'count-matches 'how-many)
(defun keep-lines-read-args (prompt)
"Read arguments for `keep-lines' and friends.
Prompt for a regexp with PROMPT.
Value is a list, (REGEXP)."
(list (read-regexp prompt) nil nil t))
(defun keep-lines (regexp &optional rstart rend interactive)
"Delete all lines except those containing matches for REGEXP.
A match split across lines preserves all the lines it lies in.
When called from Lisp (and usually interactively as well, see below)
applies to all lines starting after point.
If REGEXP contains upper case characters (excluding those preceded by `\\')
and `search-upper-case' is non-nil, the matching is case-sensitive.
Second and third arg RSTART and REND specify the region to operate on.
This command operates on (the accessible part of) all lines whose
accessible part is entirely contained in the region determined by RSTART
and REND. (A newline ending a line counts as part of that line.) If RSTART
is non-nil, REND also has to be given.
Interactively, in Transient Mark mode when the mark is active, operate
on all lines whose accessible part is entirely contained in the region.
Otherwise, the command applies to all lines starting after point.
When calling this function from Lisp, you can pretend that it was
called interactively by passing a non-nil INTERACTIVE argument.
This function starts looking for the next match from the end of
the previous match. Hence, it ignores matches that overlap
a previously found match."
(interactive
(progn
(barf-if-buffer-read-only)
(keep-lines-read-args "Keep lines containing match for regexp")))
(if rstart
(progn
(goto-char (min rstart rend))
(setq rend
(progn
(save-excursion
(goto-char (max rstart rend))
(unless (or (bolp) (eobp))
(forward-line 0))
(point-marker)))))
(if (and interactive (use-region-p))
(setq rstart (region-beginning)
rend (progn
(goto-char (region-end))
(unless (or (bolp) (eobp))
(forward-line 0))
(point-marker)))
(setq rstart (point)
rend (point-max-marker)))
(goto-char rstart))
(save-excursion
(or (bolp) (forward-line 1))
(let ((start (point))