aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/replace.el
diff options
context:
space:
mode:
authorMiles Bader2004-06-29 16:46:06 +0000
committerMiles Bader2004-06-29 16:46:06 +0000
commit12483a9413619e286efc673a2b277d85cebf3b0c (patch)
treed489e0fa758c0d51d792d42140cbeafa4aede31b /lisp/replace.el
parentc786a8ae1c5e84d0f0903d516dd0fc190dc1193c (diff)
parent619b6adbd2b96accbbf18051bf69149a029557ee (diff)
downloademacs-12483a9413619e286efc673a2b277d85cebf3b0c.tar.gz
emacs-12483a9413619e286efc673a2b277d85cebf3b0c.zip
Revision: miles@gnu.org--gnu-2004/emacs--unicode--0--patch-17
Merge from emacs--cvs-trunk--0 Patches applied: * miles@gnu.org--gnu-2004/emacs--cvs-trunk--0--patch-417 - miles@gnu.org--gnu-2004/emacs--cvs-trunk--0--patch-419 Update from CVS * miles@gnu.org--gnu-2004/emacs--cvs-trunk--0--patch-420 Tweak permissions * miles@gnu.org--gnu-2004/emacs--cvs-trunk--0--patch-421 - miles@gnu.org--gnu-2004/emacs--cvs-trunk--0--patch-430 Update from CVS
Diffstat (limited to 'lisp/replace.el')
-rw-r--r--lisp/replace.el318
1 files changed, 216 insertions, 102 deletions
diff --git a/lisp/replace.el b/lisp/replace.el
index 89f55c2829e..c2305cdecc6 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -95,6 +95,35 @@ strings or patterns."
95 (setq to (read-from-minibuffer (format "%s %s with: " string from) 95 (setq to (read-from-minibuffer (format "%s %s with: " string from)
96 nil nil nil 96 nil nil nil
97 query-replace-to-history-variable from t))) 97 query-replace-to-history-variable from t)))
98 (when (and regexp-flag
99 (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" to))
100 (let (pos list char)
101 (while
102 (progn
103 (setq pos (match-end 0))
104 (push (substring to 0 (- pos 2)) list)
105 (setq char (aref to (1- pos))
106 to (substring to pos))
107 (cond ((eq char ?\#)
108 (push '(number-to-string replace-count) list))
109 ((eq char ?\,)
110 (setq pos (read-from-string to))
111 (push `(replace-quote ,(car pos)) list)
112 (setq to (substring
113 to (+ (cdr pos)
114 ;; Swallow a space after a symbol
115 ;; if there is a space.
116 (if (string-match
117 "^[^])\"] "
118 (substring to (1- (cdr pos))))
119 1 0))))))
120 (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" to)))
121 (setq to (nreverse (delete "" (cons to list)))))
122 (replace-match-string-symbols to)
123 (setq to (cons 'replace-eval-replacement
124 (if (> (length to) 1)
125 (cons 'concat to)
126 (car to)))))
98 (list from to current-prefix-arg))) 127 (list from to current-prefix-arg)))
99 128
100(defun query-replace (from-string to-string &optional delimited start end) 129(defun query-replace (from-string to-string &optional delimited start end)
@@ -163,59 +192,35 @@ Fourth and fifth arg START and END specify the region to operate on.
163In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP, 192In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
164and `\\=\\N' (where N is a digit) stands for 193and `\\=\\N' (where N is a digit) stands for
165whatever what matched the Nth `\\(...\\)' in REGEXP. 194whatever what matched the Nth `\\(...\\)' in REGEXP.
166 195`\\?' lets you edit the replacement text in the minibuffer
167When this function is called interactively, the replacement text 196at the given position for each replacement.
168can also contain `\\,' followed by a Lisp expression. The escaped 197
169shorthands for `query-replace-regexp-eval' are also valid 198In interactive calls, the replacement text can contain `\\,'
170here: within the Lisp expression, you can use `\\&' for the whole 199followed by a Lisp expression. Each
171match string, `\\N' for partial matches, `\\#&' and `\\#N' for 200replacement evaluates that expression to compute the replacement
172the respective numeric values, and `\\#' for `replace-count'. 201string. Inside of that expression, `\\&' is a string denoting the
173 202whole match as a sting, `\\N' for a partial match, `\\#&' and `\\#N'
174If your Lisp expression is an identifier and the next 203for the whole or a partial match converted to a number with
175letter in the replacement string would be interpreted as part of it, 204`string-to-number', and `\\#' itself for the number of replacements
176you can wrap it with an expression like `\\,(or \\#)'. Incidentally, 205done so far (starting with zero).
177for this particular case you may also enter `\\#' in the replacement 206
178text directly. 207If the replacement expression is a symbol, write a space after it
179 208to terminate it. One space there, if any, will be discarded.
180When you use `\\,' or `\\#' in the replacement, TO-STRING actually 209
181becomes a list with expanded shorthands. 210When using those Lisp features interactively in the replacement
182Use \\[repeat-complex-command] after this command to see details." 211text, TO-STRING is actually made a list instead of a string.
212Use \\[repeat-complex-command] after this command for details."
183 (interactive 213 (interactive
184 (let ((common 214 (let ((common
185 (query-replace-read-args "Query replace regexp" t))) 215 (query-replace-read-args "Query replace regexp" t)))
186 (list 216 (list (nth 0 common) (nth 1 common) (nth 2 common)
187 (nth 0 common) 217 ;; These are done separately here
188 (if (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" 218 ;; so that command-history will record these expressions
189 (nth 1 common)) 219 ;; rather than the values they had this time.
190 (let ((to-string (nth 1 common)) pos to-expr char prompt) 220 (if (and transient-mark-mode mark-active)
191 (while (string-match 221 (region-beginning))
192 "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" 222 (if (and transient-mark-mode mark-active)
193 to-string) 223 (region-end)))))
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)) 224 (perform-replace regexp to-string t t delimited nil nil start end))
220 225
221(define-key esc-map [?\C-%] 'query-replace-regexp) 226(define-key esc-map [?\C-%] 'query-replace-regexp)
@@ -374,7 +379,27 @@ Fourth and fifth arg START and END specify the region to operate on.
374 379
375In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP, 380In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
376and `\\=\\N' (where N is a digit) stands for 381and `\\=\\N' (where N is a digit) stands for
377 whatever what matched the Nth `\\(...\\)' in REGEXP. 382whatever what matched the Nth `\\(...\\)' in REGEXP.
383`\\?' lets you edit the replacement text in the minibuffer
384at the given position for each replacement.
385
386In interactive calls, the replacement text may contain `\\,'
387followed by a Lisp expression used as part of the replacement
388text. Inside of that expression, `\\&' is a string denoting the
389whole match, `\\N' a partial matches, `\\#&' and `\\#N' the
390respective numeric values from `string-to-number', and `\\#'
391itself for `replace-count', the number of replacements occured so
392far.
393
394If your Lisp expression is an identifier and the next letter in
395the replacement string would be interpreted as part of it, you
396can wrap it with an expression like `\\,(or \\#)'. Incidentally,
397for this particular case you may also enter `\\#' in the
398replacement text directly.
399
400When using those Lisp features interactively in the replacement
401text, TO-STRING is actually made a list instead of a string.
402Use \\[repeat-complex-command] after this command for details.
378 403
379If `query-replace-interactive' is non-nil, the last incremental search 404If `query-replace-interactive' is non-nil, the last incremental search
380regexp is used as REGEXP--you don't have to specify it with the minibuffer. 405regexp is used as REGEXP--you don't have to specify it with the minibuffer.
@@ -1115,6 +1140,49 @@ with the `noescape' argument set.
1115 (aset data 2 (if (consp next) next (aref data 3)))))) 1140 (aset data 2 (if (consp next) next (aref data 3))))))
1116 (car (aref data 2))) 1141 (car (aref data 2)))
1117 1142
1143(defun replace-match-data (integers reuse &optional new)
1144 "Like `match-data', but markers in REUSE get invalidated.
1145If NEW is non-NIL, it is set and returned instead of fresh data,
1146but coerced to the correct value of INTEGERS."
1147 (or (and new
1148 (progn
1149 (set-match-data new)
1150 (and (eq new reuse)
1151 (eq (null integers) (markerp (car reuse)))
1152 new)))
1153 (match-data integers
1154 (prog1 reuse
1155 (while reuse
1156 (if (markerp (car reuse))
1157 (set-marker (car reuse) nil))
1158 (setq reuse (cdr reuse)))))))
1159
1160(defun replace-match-maybe-edit (newtext fixedcase literal noedit match-data)
1161 "Make a replacement with `replace-match', editing `\\?'.
1162NEXTEXT, FIXEDCASE, LITERAL are just passed on. If NOEDIT is true, no
1163check for `\\?' is made to save time. MATCH-DATA is used for the
1164replacement. In case editing is done, it is changed to use markers.
1165
1166The return value is non-NIL if there has been no `\\?' or NOEDIT was
1167passed in. If LITERAL is set, no checking is done, anyway."
1168 (unless (or literal noedit)
1169 (setq noedit t)
1170 (while (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\(\\\\\\?\\)"
1171 newtext)
1172 (setq newtext
1173 (read-input "Edit replacement string: "
1174 (prog1
1175 (cons
1176 (replace-match "" t t newtext 3)
1177 (1+ (match-beginning 3)))
1178 (setq match-data
1179 (replace-match-data
1180 nil match-data match-data))))
1181 noedit nil)))
1182 (set-match-data match-data)
1183 (replace-match newtext fixedcase literal)
1184 noedit)
1185
1118(defun perform-replace (from-string replacements 1186(defun perform-replace (from-string replacements
1119 query-flag regexp-flag delimited-flag 1187 query-flag regexp-flag delimited-flag
1120 &optional repeat-count map start end) 1188 &optional repeat-count map start end)
@@ -1145,6 +1213,7 @@ make, or the user didn't cancel the call."
1145 (search-string from-string) 1213 (search-string from-string)
1146 (real-match-data nil) ; the match data for the current match 1214 (real-match-data nil) ; the match data for the current match
1147 (next-replacement nil) 1215 (next-replacement nil)
1216 (noedit nil)
1148 (keep-going t) 1217 (keep-going t)
1149 (stack nil) 1218 (stack nil)
1150 (replace-count 0) 1219 (replace-count 0)
@@ -1201,7 +1270,9 @@ make, or the user didn't cancel the call."
1201 (setq real-match-data 1270 (setq real-match-data
1202 (if (consp match-again) 1271 (if (consp match-again)
1203 (progn (goto-char (nth 1 match-again)) 1272 (progn (goto-char (nth 1 match-again))
1204 match-again) 1273 (replace-match-data t
1274 real-match-data
1275 match-again))
1205 (and (or match-again 1276 (and (or match-again
1206 ;; MATCH-AGAIN non-nil means we 1277 ;; MATCH-AGAIN non-nil means we
1207 ;; accept an adjacent match. If 1278 ;; accept an adjacent match. If
@@ -1217,7 +1288,7 @@ make, or the user didn't cancel the call."
1217 (funcall search-function search-string limit t) 1288 (funcall search-function search-string limit t)
1218 ;; For speed, use only integers and 1289 ;; For speed, use only integers and
1219 ;; reuse the list used last time. 1290 ;; reuse the list used last time.
1220 (match-data t real-match-data))))) 1291 (replace-match-data t real-match-data)))))
1221 ;; Optionally ignore matches that have a read-only property. 1292 ;; Optionally ignore matches that have a read-only property.
1222 (unless (and query-replace-skip-read-only 1293 (unless (and query-replace-skip-read-only
1223 (text-property-not-all 1294 (text-property-not-all
@@ -1249,16 +1320,27 @@ make, or the user didn't cancel the call."
1249 (set-match-data real-match-data) 1320 (set-match-data real-match-data)
1250 (setq next-replacement 1321 (setq next-replacement
1251 (funcall (car replacements) (cdr replacements) 1322 (funcall (car replacements) (cdr replacements)
1252 replace-count))) 1323 replace-count)
1324 noedit nil))
1253 (if (not query-flag) 1325 (if (not query-flag)
1254 (let ((inhibit-read-only query-replace-skip-read-only)) 1326 (let ((inhibit-read-only
1255 (set-match-data real-match-data) 1327 query-replace-skip-read-only))
1256 (replace-match next-replacement nocasify literal) 1328 (unless noedit
1257 (setq replace-count (1+ replace-count))) 1329 (replace-highlight (nth 0 real-match-data)
1330 (nth 1 real-match-data)))
1331 (setq noedit
1332 (replace-match-maybe-edit
1333 next-replacement nocasify literal
1334 noedit real-match-data)
1335 replace-count (1+ replace-count)))
1258 (undo-boundary) 1336 (undo-boundary)
1259 (let (done replaced key def) 1337 (let (done replaced key def)
1260 ;; Loop reading commands until one of them sets done, 1338 ;; Loop reading commands until one of them sets done,
1261 ;; which means it has finished handling this occurrence. 1339 ;; which means it has finished handling this
1340 ;; occurrence. Any command that sets `done' should
1341 ;; leave behind proper match data for the stack.
1342 ;; Commands not setting `done' need to adjust
1343 ;; `real-match-data'.
1262 (while (not done) 1344 (while (not done)
1263 (set-match-data real-match-data) 1345 (set-match-data real-match-data)
1264 (replace-highlight (match-beginning 0) (match-end 0)) 1346 (replace-highlight (match-beginning 0) (match-end 0))
@@ -1290,37 +1372,49 @@ make, or the user didn't cancel the call."
1290 ((eq def 'backup) 1372 ((eq def 'backup)
1291 (if stack 1373 (if stack
1292 (let ((elt (pop stack))) 1374 (let ((elt (pop stack)))
1293 (goto-char (car elt)) 1375 (goto-char (nth 0 elt))
1294 (setq replaced (eq t (cdr elt))) 1376 (setq replaced (nth 1 elt)
1295 (or replaced 1377 real-match-data
1296 (set-match-data (cdr elt)))) 1378 (replace-match-data
1379 t real-match-data
1380 (nth 2 elt))))
1297 (message "No previous match") 1381 (message "No previous match")
1298 (ding 'no-terminate) 1382 (ding 'no-terminate)
1299 (sit-for 1))) 1383 (sit-for 1)))
1300 ((eq def 'act) 1384 ((eq def 'act)
1301 (or replaced 1385 (or replaced
1302 (progn 1386 (setq noedit
1303 (replace-match next-replacement nocasify literal) 1387 (replace-match-maybe-edit
1304 (setq replace-count (1+ replace-count)))) 1388 next-replacement nocasify literal
1389 noedit real-match-data)
1390 replace-count (1+ replace-count)))
1305 (setq done t replaced t)) 1391 (setq done t replaced t))
1306 ((eq def 'act-and-exit) 1392 ((eq def 'act-and-exit)
1307 (or replaced 1393 (or replaced
1308 (progn 1394 (setq noedit
1309 (replace-match next-replacement nocasify literal) 1395 (replace-match-maybe-edit
1310 (setq replace-count (1+ replace-count)))) 1396 next-replacement nocasify literal
1397 noedit real-match-data)
1398 replace-count (1+ replace-count)))
1311 (setq keep-going nil) 1399 (setq keep-going nil)
1312 (setq done t replaced t)) 1400 (setq done t replaced t))
1313 ((eq def 'act-and-show) 1401 ((eq def 'act-and-show)
1314 (if (not replaced) 1402 (if (not replaced)
1315 (progn 1403 (setq noedit
1316 (replace-match next-replacement nocasify literal) 1404 (replace-match-maybe-edit
1317 (setq replace-count (1+ replace-count)) 1405 next-replacement nocasify literal
1318 (setq replaced t)))) 1406 noedit real-match-data)
1407 replace-count (1+ replace-count)
1408 real-match-data (replace-match-data
1409 t real-match-data)
1410 replaced t)))
1319 ((eq def 'automatic) 1411 ((eq def 'automatic)
1320 (or replaced 1412 (or replaced
1321 (progn 1413 (setq noedit
1322 (replace-match next-replacement nocasify literal) 1414 (replace-match-maybe-edit
1323 (setq replace-count (1+ replace-count)))) 1415 next-replacement nocasify literal
1416 noedit real-match-data)
1417 replace-count (1+ replace-count)))
1324 (setq done t query-flag nil replaced t)) 1418 (setq done t query-flag nil replaced t))
1325 ((eq def 'skip) 1419 ((eq def 'skip)
1326 (setq done t)) 1420 (setq done t))
@@ -1328,36 +1422,45 @@ make, or the user didn't cancel the call."
1328 (recenter nil)) 1422 (recenter nil))
1329 ((eq def 'edit) 1423 ((eq def 'edit)
1330 (let ((opos (point-marker))) 1424 (let ((opos (point-marker)))
1425 (setq real-match-data (replace-match-data
1426 nil real-match-data
1427 real-match-data))
1331 (goto-char (match-beginning 0)) 1428 (goto-char (match-beginning 0))
1332 (save-excursion 1429 (save-excursion
1333 (funcall search-function search-string limit t)
1334 (setq real-match-data (match-data)))
1335 (save-excursion
1336 (save-window-excursion 1430 (save-window-excursion
1337 (recursive-edit))) 1431 (recursive-edit)))
1338 (goto-char opos)) 1432 (goto-char opos)
1339 (set-match-data real-match-data) 1433 (set-marker opos nil))
1340 ;; Before we make the replacement, 1434 ;; Before we make the replacement,
1341 ;; decide whether the search string 1435 ;; decide whether the search string
1342 ;; can match again just after this match. 1436 ;; can match again just after this match.
1343 (if (and regexp-flag nonempty-match) 1437 (if (and regexp-flag nonempty-match)
1344 (setq match-again (and (looking-at search-string) 1438 (setq match-again (and (looking-at search-string)
1345 (match-data))))) 1439 (match-data)))))
1346
1347 ;; Edit replacement. 1440 ;; Edit replacement.
1348 ((eq def 'edit-replacement) 1441 ((eq def 'edit-replacement)
1349 (setq next-replacement 1442 (setq real-match-data (replace-match-data
1443 nil real-match-data
1444 real-match-data)
1445 next-replacement
1350 (read-input "Edit replacement string: " 1446 (read-input "Edit replacement string: "
1351 next-replacement)) 1447 next-replacement)
1352 (or replaced 1448 noedit nil)
1353 (replace-match next-replacement nocasify literal)) 1449 (if replaced
1450 (set-match-data real-match-data)
1451 (setq noedit
1452 (replace-match-maybe-edit
1453 next-replacement nocasify literal noedit
1454 real-match-data)
1455 replaced t))
1354 (setq done t)) 1456 (setq done t))
1355 1457
1356 ((eq def 'delete-and-edit) 1458 ((eq def 'delete-and-edit)
1357 (delete-region (match-beginning 0) (match-end 0)) 1459 (replace-match "" t t)
1358 (set-match-data 1460 (setq real-match-data (replace-match-data
1359 (prog1 (match-data) 1461 nil real-match-data))
1360 (save-excursion (recursive-edit)))) 1462 (replace-dehighlight)
1463 (save-excursion (recursive-edit))
1361 (setq replaced t)) 1464 (setq replaced t))
1362 ;; Note: we do not need to treat `exit-prefix' 1465 ;; Note: we do not need to treat `exit-prefix'
1363 ;; specially here, since we reread 1466 ;; specially here, since we reread
@@ -1372,10 +1475,23 @@ make, or the user didn't cancel the call."
1372 ;; Record previous position for ^ when we move on. 1475 ;; Record previous position for ^ when we move on.
1373 ;; Change markers to numbers in the match data 1476 ;; Change markers to numbers in the match data
1374 ;; since lots of markers slow down editing. 1477 ;; since lots of markers slow down editing.
1375 (setq stack 1478 (push (list (point) replaced
1376 (cons (cons (point) 1479;;; If the replacement has already happened, all we need is the
1377 (or replaced (match-data t))) 1480;;; current match start and end. We could get this with a trivial
1378 stack)))))) 1481;;; match like
1482;;; (save-excursion (goto-char (match-beginning 0))
1483;;; (search-forward (match-string 0))
1484;;; (match-data t))
1485;;; if we really wanted to avoid manually constructing match data.
1486;;; Adding current-buffer is necessary so that match-data calls can
1487;;; return markers which are appropriate for editing.
1488 (if replaced
1489 (list
1490 (match-beginning 0)
1491 (match-end 0)
1492 (current-buffer))
1493 (match-data t)))
1494 stack)))))
1379 1495
1380 ;; The code preventing adjacent regexp matches in the condition 1496 ;; The code preventing adjacent regexp matches in the condition
1381 ;; of the while-loop above will haven taken us one character 1497 ;; of the while-loop above will haven taken us one character
@@ -1405,14 +1521,12 @@ make, or the user didn't cancel the call."
1405 1521
1406(defun replace-highlight (start end) 1522(defun replace-highlight (start end)
1407 (and query-replace-highlight 1523 (and query-replace-highlight
1408 (progn 1524 (if replace-overlay
1409 (or replace-overlay 1525 (move-overlay replace-overlay start end (current-buffer))
1410 (progn 1526 (setq replace-overlay (make-overlay start end))
1411 (setq replace-overlay (make-overlay start end)) 1527 (overlay-put replace-overlay 'face
1412 (overlay-put replace-overlay 'face 1528 (if (facep 'query-replace)
1413 (if (facep 'query-replace) 1529 'query-replace 'region)))))
1414 'query-replace 'region))))
1415 (move-overlay replace-overlay start end (current-buffer)))))
1416 1530
1417;;; arch-tag: 16b4cd61-fd40-497b-b86f-b667c4cf88e4 1531;;; arch-tag: 16b4cd61-fd40-497b-b86f-b667c4cf88e4
1418;;; replace.el ends here 1532;;; replace.el ends here