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 |
|
|
36 |
|
|
37 |
(defvar query-replace-history nil) |
(defvar query-replace-history nil) |
38 |
|
|
39 |
(defvar query-replace-interactive nil |
(defcustom query-replace-interactive nil |
40 |
"Non-nil means `query-replace' uses the last search string. |
"Non-nil means `query-replace' uses the last search string. |
41 |
That becomes the \"string to replace\".") |
That becomes the \"string to replace\"." |
42 |
|
:type 'boolean |
43 |
|
:group 'matching) |
44 |
|
|
45 |
(defcustom query-replace-from-history-variable 'query-replace-history |
(defcustom query-replace-from-history-variable 'query-replace-history |
46 |
"History list to use for the FROM argument of `query-replace' commands. |
"History list to use for the FROM argument of `query-replace' commands. |
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. |
584 |
(set (make-local-variable 'revert-buffer-function) 'occur-revert-function) |
(set (make-local-variable 'revert-buffer-function) 'occur-revert-function) |
585 |
(make-local-variable 'occur-revert-arguments) |
(make-local-variable 'occur-revert-arguments) |
586 |
(add-hook 'change-major-mode-hook 'font-lock-defontify nil t) |
(add-hook 'change-major-mode-hook 'font-lock-defontify nil t) |
587 |
|
(setq next-error-function 'occur-next-error) |
588 |
(run-hooks 'occur-mode-hook)) |
(run-hooks 'occur-mode-hook)) |
589 |
|
|
590 |
(defun occur-revert-function (ignore1 ignore2) |
(defun occur-revert-function (ignore1 ignore2) |
661 |
"Move to the Nth (default 1) previous match in an Occur mode buffer." |
"Move to the Nth (default 1) previous match in an Occur mode buffer." |
662 |
(interactive "p") |
(interactive "p") |
663 |
(occur-find-match n #'previous-single-property-change "No earlier matches")) |
(occur-find-match n #'previous-single-property-change "No earlier matches")) |
664 |
|
|
665 |
|
(defun occur-next-error (&optional argp reset) |
666 |
|
"Move to the Nth (default 1) next match in an Occur mode buffer. |
667 |
|
Compatibility function for \\[next-error] invocations." |
668 |
|
(interactive "p") |
669 |
|
(when reset |
670 |
|
(occur-find-match 0 #'next-single-property-change "No first match")) |
671 |
|
(occur-find-match |
672 |
|
(prefix-numeric-value argp) |
673 |
|
(if (> 0 (prefix-numeric-value argp)) |
674 |
|
#'previous-single-property-change |
675 |
|
#'next-single-property-change) |
676 |
|
"No more matches") |
677 |
|
(occur-mode-goto-occurrence)) |
678 |
|
|
679 |
|
|
680 |
(defcustom list-matching-lines-default-context-lines 0 |
(defcustom list-matching-lines-default-context-lines 0 |
681 |
"*Default number of context lines included around `list-matching-lines' matches. |
"*Default number of context lines included around `list-matching-lines' matches. |
862 |
(setq occur-revert-arguments (list regexp nlines bufs) |
(setq occur-revert-arguments (list regexp nlines bufs) |
863 |
buffer-read-only t) |
buffer-read-only t) |
864 |
(if (> count 0) |
(if (> count 0) |
865 |
(display-buffer occur-buf) |
(progn |
866 |
|
(display-buffer occur-buf) |
867 |
|
(setq next-error-last-buffer occur-buf)) |
868 |
(kill-buffer occur-buf))) |
(kill-buffer occur-buf))) |
869 |
(run-hooks 'occur-hook)))) |
(run-hooks 'occur-hook)))) |
870 |
|
|
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 |
1194 |
(unwind-protect |
(unwind-protect |
1195 |
;; Loop finding occurrences that perhaps should be replaced. |
;; Loop finding occurrences that perhaps should be replaced. |
1196 |
(while (and keep-going |
(while (and keep-going |
1197 |
(not (eobp)) |
(not (or (eobp) (and limit (>= (point) limit)))) |
1198 |
;; Use the next match if it is already known; |
;; Use the next match if it is already known; |
1199 |
;; otherwise, search for a match after moving forward |
;; otherwise, search for a match after moving forward |
1200 |
;; one char if progress is required. |
;; one char if progress is required. |
1210 |
;; character too far at the end, |
;; character too far at the end, |
1211 |
;; but this is undone after the |
;; but this is undone after the |
1212 |
;; while-loop. |
;; while-loop. |
1213 |
(progn (forward-char 1) (not (eobp)))) |
(progn |
1214 |
|
(forward-char 1) |
1215 |
|
(not (or (eobp) |
1216 |
|
(and limit (>= (point) limit)))))) |
1217 |
(funcall search-function search-string limit t) |
(funcall search-function search-string limit t) |
1218 |
;; For speed, use only integers and |
;; For speed, use only integers and |
1219 |
;; reuse the list used last time. |
;; reuse the list used last time. |