aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTino Calancha2016-02-24 12:35:46 +1100
committerLars Ingebrigtsen2016-02-24 12:35:46 +1100
commite1d749bd7e0d68ab063eae3927caede6039a33cf (patch)
tree3b16fbd693e0184b8c4d5e5322d71f28c903a4e6
parentbbd86c5642bd62c43d72391669f28eaa14459fd5 (diff)
downloademacs-e1d749bd7e0d68ab063eae3927caede6039a33cf.tar.gz
emacs-e1d749bd7e0d68ab063eae3927caede6039a33cf.zip
Allow undoing changes while doing query-replace
* doc/lispref/searching.texi (Search and Replace): Mention undo (bug#21684). * lisp/replace.el (query-replace-help): Document undo. (perform-replace): Implement undo while replacing text.
-rw-r--r--doc/lispref/searching.texi8
-rw-r--r--etc/NEWS5
-rw-r--r--lisp/replace.el117
3 files changed, 121 insertions, 9 deletions
diff --git a/doc/lispref/searching.texi b/doc/lispref/searching.texi
index 1243d720bc3..644716a95c7 100644
--- a/doc/lispref/searching.texi
+++ b/doc/lispref/searching.texi
@@ -1805,6 +1805,14 @@ Answer this question and all subsequent questions in the series with
1805@item backup 1805@item backup
1806Move back to the previous place that a question was asked about. 1806Move back to the previous place that a question was asked about.
1807 1807
1808@item undo
1809Undo last replacement and move back to the place where that
1810replacement was performed.
1811
1812@item undo-all
1813Undo all replacements and move back to the place where the first
1814replacement was performed.
1815
1808@item edit 1816@item edit
1809Enter a recursive edit to deal with this question---instead of any 1817Enter a recursive edit to deal with this question---instead of any
1810other action that would normally be taken. 1818other action that would normally be taken.
diff --git a/etc/NEWS b/etc/NEWS
index 255afde7463..cf121d0eec3 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -435,6 +435,11 @@ is intended for adding to 'kill-emacs-query-functions'.
435in favor of the global `M-s h' bindings introduced in Emacs-23.1. 435in favor of the global `M-s h' bindings introduced in Emacs-23.1.
436They'll disappear soon. 436They'll disappear soon.
437 437
438+++
439** New bindings for 'query-replace-map'.
440`undo', undo the last replacement; bound to `u'.
441`undo-all', undo all replacements; bound to `U'.
442
438 443
439* Changes in Specialized Modes and Packages in Emacs 25.1 444* Changes in Specialized Modes and Packages in Emacs 25.1
440 445
diff --git a/lisp/replace.el b/lisp/replace.el
index 488eff7928a..b7e26c96fc5 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -1824,6 +1824,8 @@ C-w to delete match and recursive edit,
1824C-l to clear the screen, redisplay, and offer same replacement again, 1824C-l to clear the screen, redisplay, and offer same replacement again,
1825! to replace all remaining matches in this buffer with no more questions, 1825! to replace all remaining matches in this buffer with no more questions,
1826^ to move point back to previous match, 1826^ to move point back to previous match,
1827u to undo previous replacement,
1828U to undo all replacements,
1827E to edit the replacement string. 1829E to edit the replacement string.
1828In multi-buffer replacements type `Y' to replace all remaining 1830In multi-buffer replacements type `Y' to replace all remaining
1829matches in all remaining buffers with no more questions, 1831matches in all remaining buffers with no more questions,
@@ -1853,6 +1855,8 @@ in the current buffer."
1853 (define-key map "\C-l" 'recenter) 1855 (define-key map "\C-l" 'recenter)
1854 (define-key map "!" 'automatic) 1856 (define-key map "!" 'automatic)
1855 (define-key map "^" 'backup) 1857 (define-key map "^" 'backup)
1858 (define-key map "u" 'undo)
1859 (define-key map "U" 'undo-all)
1856 (define-key map "\C-h" 'help) 1860 (define-key map "\C-h" 'help)
1857 (define-key map [f1] 'help) 1861 (define-key map [f1] 'help)
1858 (define-key map [help] 'help) 1862 (define-key map [help] 'help)
@@ -1878,7 +1882,7 @@ The valid answers include `act', `skip', `act-and-show',
1878`act-and-exit', `exit', `exit-prefix', `recenter', `scroll-up', 1882`act-and-exit', `exit', `exit-prefix', `recenter', `scroll-up',
1879`scroll-down', `scroll-other-window', `scroll-other-window-down', 1883`scroll-down', `scroll-other-window', `scroll-other-window-down',
1880`edit', `edit-replacement', `delete-and-edit', `automatic', 1884`edit', `edit-replacement', `delete-and-edit', `automatic',
1881`backup', `quit', and `help'. 1885`backup', `undo', `undo-all', `quit', and `help'.
1882 1886
1883This keymap is used by `y-or-n-p' as well as `query-replace'.") 1887This keymap is used by `y-or-n-p' as well as `query-replace'.")
1884 1888
@@ -2132,6 +2136,10 @@ It must return a string."
2132 (noedit nil) 2136 (noedit nil)
2133 (keep-going t) 2137 (keep-going t)
2134 (stack nil) 2138 (stack nil)
2139 (search-string-replaced nil) ; last string matching `from-string'
2140 (next-replacement-replaced nil) ; replacement string
2141 ; (substituted regexp)
2142 (last-was-undo)
2135 (replace-count 0) 2143 (replace-count 0)
2136 (skip-read-only-count 0) 2144 (skip-read-only-count 0)
2137 (skip-filtered-count 0) 2145 (skip-filtered-count 0)
@@ -2328,8 +2336,28 @@ It must return a string."
2328 (match-beginning 0) (match-end 0) 2336 (match-beginning 0) (match-end 0)
2329 start end search-string 2337 start end search-string
2330 regexp-flag delimited-flag case-fold-search backward) 2338 regexp-flag delimited-flag case-fold-search backward)
2331 ;; Bind message-log-max so we don't fill up the message log 2339 ;; Obtain the matched groups: needed only when
2332 ;; with a bunch of identical messages. 2340 ;; regexp-flag non nil.
2341 (when (and last-was-undo regexp-flag)
2342 (setq last-was-undo nil
2343 real-match-data
2344 (save-excursion
2345 (goto-char (match-beginning 0))
2346 (looking-at search-string)
2347 (match-data t real-match-data))))
2348 ;; Matched string and next-replacement-replaced
2349 ;; stored in stack.
2350 (setq search-string-replaced (buffer-substring-no-properties
2351 (match-beginning 0)
2352 (match-end 0))
2353 next-replacement-replaced
2354 (query-replace-descr
2355 (save-match-data
2356 (set-match-data real-match-data)
2357 (match-substitute-replacement
2358 next-replacement nocasify literal))))
2359 ;; Bind message-log-max so we don't fill up the
2360 ;; message log with a bunch of identical messages.
2333 (let ((message-log-max nil) 2361 (let ((message-log-max nil)
2334 (replacement-presentation 2362 (replacement-presentation
2335 (if query-replace-show-replacement 2363 (if query-replace-show-replacement
@@ -2342,8 +2370,8 @@ It must return a string."
2342 (query-replace-descr from-string) 2370 (query-replace-descr from-string)
2343 (query-replace-descr replacement-presentation))) 2371 (query-replace-descr replacement-presentation)))
2344 (setq key (read-event)) 2372 (setq key (read-event))
2345 ;; Necessary in case something happens during read-event 2373 ;; Necessary in case something happens during
2346 ;; that clobbers the match data. 2374 ;; read-event that clobbers the match data.
2347 (set-match-data real-match-data) 2375 (set-match-data real-match-data)
2348 (setq key (vector key)) 2376 (setq key (vector key))
2349 (setq def (lookup-key map key)) 2377 (setq def (lookup-key map key))
@@ -2354,7 +2382,8 @@ It must return a string."
2354 (concat "Query replacing " 2382 (concat "Query replacing "
2355 (if delimited-flag 2383 (if delimited-flag
2356 (or (and (symbolp delimited-flag) 2384 (or (and (symbolp delimited-flag)
2357 (get delimited-flag 'isearch-message-prefix)) 2385 (get delimited-flag
2386 'isearch-message-prefix))
2358 "word ") "") 2387 "word ") "")
2359 (if regexp-flag "regexp " "") 2388 (if regexp-flag "regexp " "")
2360 (if backward "backward " "") 2389 (if backward "backward " "")
@@ -2381,6 +2410,73 @@ It must return a string."
2381 (message "No previous match") 2410 (message "No previous match")
2382 (ding 'no-terminate) 2411 (ding 'no-terminate)
2383 (sit-for 1))) 2412 (sit-for 1)))
2413 ((or (eq def 'undo) (eq def 'undo-all))
2414 (if (null stack)
2415 (progn
2416 (message "Nothing to undo")
2417 (ding 'no-terminate)
2418 (sit-for 1))
2419 (let ((stack-idx 0)
2420 (stack-len (length stack))
2421 (num-replacements 0)
2422 search-string
2423 next-replacement)
2424 (while (and (< stack-idx stack-len)
2425 stack
2426 (null replaced))
2427 (let* ((elt (nth stack-idx stack)))
2428 (setq
2429 stack-idx (1+ stack-idx)
2430 replaced (nth 1 elt)
2431 ;; Bind swapped values
2432 ;; (search-string <--> replacement)
2433 search-string (nth (if replaced 4 3) elt)
2434 next-replacement (nth (if replaced 3 4) elt)
2435 search-string-replaced search-string
2436 next-replacement-replaced next-replacement)
2437
2438 (when (and (= stack-idx stack-len)
2439 (null replaced)
2440 (zerop num-replacements))
2441 (message "Nothing to undo")
2442 (ding 'no-terminate)
2443 (sit-for 1))
2444
2445 (when replaced
2446 (setq stack (nthcdr stack-idx stack))
2447 (goto-char (nth 0 elt))
2448 (set-match-data (nth 2 elt))
2449 (setq real-match-data
2450 (save-excursion
2451 (goto-char (match-beginning 0))
2452 (looking-at search-string)
2453 (match-data t (nth 2 elt)))
2454 noedit
2455 (replace-match-maybe-edit
2456 next-replacement nocasify literal
2457 noedit real-match-data backward)
2458 replace-count (1- replace-count)
2459 real-match-data
2460 (save-excursion
2461 (goto-char (match-beginning 0))
2462 (looking-at next-replacement)
2463 (match-data t (nth 2 elt))))
2464 ;; Set replaced nil to keep in loop
2465 (when (eq def 'undo-all)
2466 (setq replaced nil
2467 stack-len (- stack-len stack-idx)
2468 stack-idx 0
2469 num-replacements
2470 (1+ num-replacements))))))
2471 (when (and (eq def 'undo-all)
2472 (null (zerop num-replacements)))
2473 (message "Undid %d %s" num-replacements
2474 (if (= num-replacements 1)
2475 "replacement"
2476 "replacements"))
2477 (ding 'no-terminate)
2478 (sit-for 1)))
2479 (setq replaced nil last-was-undo t)))
2384 ((eq def 'act) 2480 ((eq def 'act)
2385 (or replaced 2481 (or replaced
2386 (setq noedit 2482 (setq noedit
@@ -2503,9 +2599,12 @@ It must return a string."
2503 (match-beginning 0) 2599 (match-beginning 0)
2504 (match-end 0) 2600 (match-end 0)
2505 (current-buffer)) 2601 (current-buffer))
2506 (match-data t))) 2602 (match-data t))
2507 stack)))))) 2603 search-string-replaced
2508 2604 next-replacement-replaced)
2605 stack)
2606 (setq next-replacement-replaced nil
2607 search-string-replaced nil))))))
2509 (replace-dehighlight)) 2608 (replace-dehighlight))
2510 (or unread-command-events 2609 (or unread-command-events
2511 (message "Replaced %d occurrence%s%s" 2610 (message "Replaced %d occurrence%s%s"