1 |
;;; replace.el --- replace commands for Emacs |
;;; replace.el --- replace commands for Emacs |
2 |
|
|
3 |
;; Copyright (C) 1985, 86, 87, 92, 94, 96, 1997, 2000, 2001, 2002 |
;; Copyright (C) 1985, 86, 87, 92, 94, 96, 1997, 2000, 2001, 2002, |
4 |
;; Free Software Foundation, Inc. |
;; 2003, 2004 Free Software Foundation, Inc. |
5 |
|
|
6 |
;; Maintainer: FSF |
;; Maintainer: FSF |
7 |
|
|
81 |
query-replace-from-history-variable |
query-replace-from-history-variable |
82 |
nil t))) |
nil t))) |
83 |
;; Warn if user types \n or \t, but don't reject the input. |
;; Warn if user types \n or \t, but don't reject the input. |
84 |
(if (string-match "\\\\[nt]" from) |
(and regexp-flag |
85 |
(let ((match (match-string 0 from))) |
(string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\(\\\\[nt]\\)" from) |
86 |
(cond |
(let ((match (match-string 3 from))) |
87 |
((string= match "\\n") |
(cond |
88 |
(message "Note: `\\n' here doesn't match a newline; to do that, type C-q C-j instead")) |
((string= match "\\n") |
89 |
((string= match "\\t") |
(message "Note: `\\n' here doesn't match a newline; to do that, type C-q C-j instead")) |
90 |
(message "Note: `\\t' here doesn't match a tab; to do that, just type TAB"))) |
((string= match "\\t") |
91 |
(sit-for 2)))) |
(message "Note: `\\t' here doesn't match a tab; to do that, just type TAB"))) |
92 |
|
(sit-for 2)))) |
93 |
|
|
94 |
(save-excursion |
(save-excursion |
95 |
(setq to (read-from-minibuffer (format "%s %s with: " string from) |
(setq to (read-from-minibuffer (format "%s %s with: " string from) |
162 |
|
|
163 |
In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP, |
In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP, |
164 |
and `\\=\\N' (where N is a digit) stands for |
and `\\=\\N' (where N is a digit) stands for |
165 |
whatever what matched the Nth `\\(...\\)' in REGEXP." |
whatever what matched the Nth `\\(...\\)' in REGEXP. |
166 |
|
|
167 |
|
When this function is called interactively, the replacement text |
168 |
|
can also contain `\\,' followed by a Lisp expression. The escaped |
169 |
|
shorthands for `query-replace-regexp-eval' are also valid |
170 |
|
here: within the Lisp expression, you can use `\\&' for the whole |
171 |
|
match string, `\\N' for partial matches, `\\#&' and `\\#N' for |
172 |
|
the respective numeric values, and `\\#' for `replace-count'. |
173 |
|
|
174 |
|
If your Lisp expression is an identifier and the next |
175 |
|
letter in the replacement string would be interpreted as part of it, |
176 |
|
you can wrap it with an expression like `\\,(or \\#)'. Incidentally, |
177 |
|
for this particular case you may also enter `\\#' in the replacement |
178 |
|
text directly. |
179 |
|
|
180 |
|
When you use `\\,' or `\\#' in the replacement, TO-STRING actually |
181 |
|
becomes a list with expanded shorthands. |
182 |
|
Use \\[repeat-complex-command] after this command to see details." |
183 |
(interactive |
(interactive |
184 |
(let ((common |
(let ((common |
185 |
(query-replace-read-args "Query replace regexp" t))) |
(query-replace-read-args "Query replace regexp" t))) |
186 |
(list (nth 0 common) (nth 1 common) (nth 2 common) |
(list |
187 |
;; These are done separately here |
(nth 0 common) |
188 |
;; so that command-history will record these expressions |
(if (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" |
189 |
;; rather than the values they had this time. |
(nth 1 common)) |
190 |
(if (and transient-mark-mode mark-active) |
(let ((to-string (nth 1 common)) pos to-expr char prompt) |
191 |
(region-beginning)) |
(while (string-match |
192 |
(if (and transient-mark-mode mark-active) |
"\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" |
193 |
(region-end))))) |
to-string) |
194 |
|
(setq pos (match-end 0)) |
195 |
|
(push (substring to-string 0 (- pos 2)) to-expr) |
196 |
|
(setq char (aref to-string (1- pos)) |
197 |
|
to-string (substring to-string pos)) |
198 |
|
(cond ((eq char ?\#) |
199 |
|
(push '(number-to-string replace-count) to-expr)) |
200 |
|
((eq char ?\,) |
201 |
|
(setq pos (read-from-string to-string)) |
202 |
|
(push `(replace-quote ,(car pos)) to-expr) |
203 |
|
(setq to-string (substring to-string (cdr pos)))))) |
204 |
|
(setq to-expr (nreverse (delete "" (cons to-string to-expr)))) |
205 |
|
(replace-match-string-symbols to-expr) |
206 |
|
(cons 'replace-eval-replacement |
207 |
|
(if (> (length to-expr) 1) |
208 |
|
(cons 'concat to-expr) |
209 |
|
(car to-expr)))) |
210 |
|
(nth 1 common)) |
211 |
|
(nth 2 common) |
212 |
|
;; These are done separately here |
213 |
|
;; so that command-history will record these expressions |
214 |
|
;; rather than the values they had this time. |
215 |
|
(if (and transient-mark-mode mark-active) |
216 |
|
(region-beginning)) |
217 |
|
(if (and transient-mark-mode mark-active) |
218 |
|
(region-end))))) |
219 |
(perform-replace regexp to-string t t delimited nil nil start end)) |
(perform-replace regexp to-string t t delimited nil nil start end)) |
220 |
|
|
221 |
(define-key esc-map [?\C-%] 'query-replace-regexp) |
(define-key esc-map [?\C-%] 'query-replace-regexp) |
222 |
|
|
223 |
(defun query-replace-regexp-eval (regexp to-expr &optional delimited start end) |
(defun query-replace-regexp-eval (regexp to-expr &optional delimited start end) |
234 |
`\\0' to stand for whatever matched the whole of REGEXP, and `\\N' (where |
`\\0' to stand for whatever matched the whole of REGEXP, and `\\N' (where |
235 |
N is a digit) to stand for whatever matched the Nth `\\(...\\)' in REGEXP. |
N is a digit) to stand for whatever matched the Nth `\\(...\\)' in REGEXP. |
236 |
Use `\\#&' or `\\#N' if you want a number instead of a string. |
Use `\\#&' or `\\#N' if you want a number instead of a string. |
237 |
|
In interactive use, `\\#' in itself stands for `replace-count'. |
238 |
|
|
239 |
In Transient Mark mode, if the mark is active, operate on the contents |
In Transient Mark mode, if the mark is active, operate on the contents |
240 |
of the region. Otherwise, operate from point to the end of the buffer. |
of the region. Otherwise, operate from point to the end of the buffer. |
1056 |
#N (string-to-number (match-string N)) |
#N (string-to-number (match-string N)) |
1057 |
& (match-string 0) |
& (match-string 0) |
1058 |
#& (string-to-number (match-string 0)) |
#& (string-to-number (match-string 0)) |
1059 |
|
# replace-count |
1060 |
|
|
1061 |
Note that these symbols must be preceeded by a backslash in order to |
Note that these symbols must be preceeded by a backslash in order to |
1062 |
type them." |
type them." |
1076 |
((string= "&" name) |
((string= "&" name) |
1077 |
(setcar n '(match-string 0))) |
(setcar n '(match-string 0))) |
1078 |
((string= "#&" name) |
((string= "#&" name) |
1079 |
(setcar n '(string-to-number (match-string 0)))))))) |
(setcar n '(string-to-number (match-string 0)))) |
1080 |
|
((string= "#" name) |
1081 |
|
(setcar n 'replace-count)))))) |
1082 |
(setq n (cdr n)))) |
(setq n (cdr n)))) |
1083 |
|
|
1084 |
(defun replace-eval-replacement (expression replace-count) |
(defun replace-eval-replacement (expression replace-count) |
1087 |
replacement |
replacement |
1088 |
(prin1-to-string replacement t)))) |
(prin1-to-string replacement t)))) |
1089 |
|
|
1090 |
|
(defun replace-quote (replacement) |
1091 |
|
"Quote a replacement string. |
1092 |
|
This just doubles all backslashes in REPLACEMENT and |
1093 |
|
returns the resulting string. If REPLACEMENT is not |
1094 |
|
a string, it is first passed through `prin1-to-string' |
1095 |
|
with the `noescape' argument set. |
1096 |
|
|
1097 |
|
`match-data' is preserved across the call." |
1098 |
|
(save-match-data |
1099 |
|
(replace-regexp-in-string "\\\\" "\\\\" |
1100 |
|
(if (stringp replacement) |
1101 |
|
replacement |
1102 |
|
(prin1-to-string replacement t)) |
1103 |
|
t t))) |
1104 |
|
|
1105 |
(defun replace-loop-through-replacements (data replace-count) |
(defun replace-loop-through-replacements (data replace-count) |
1106 |
;; DATA is a vector contaning the following values: |
;; DATA is a vector contaning the following values: |
1107 |
;; 0 next-rotate-count |
;; 0 next-rotate-count |