comparison lisp/prim/replace.el @ 70:131b0175ea99 r20-0b30

Import from CVS: tag r20-0b30
author cvs
date Mon, 13 Aug 2007 09:02:59 +0200
parents 441bb1e64a06
children b9518feda344
comparison
equal deleted inserted replaced
69:804d1389bcd6 70:131b0175ea99
13 ;; WITHOUT ANY WARRANTY; without even the implied warranty of 13 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ;; General Public License for more details. 15 ;; General Public License for more details.
16 16
17 ;; You should have received a copy of the GNU General Public License 17 ;; You should have received a copy of the GNU General Public License
18 ;; along with XEmacs; see the file COPYING. If not, write to the Free 18 ;; along with XEmacs; see the file COPYING. If not, write to the
19 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 19 ;; Free Software Foundation, 59 Temple Place - Suite 330,
20 ;; 02111-1307, USA. 20 ;; Boston, MA 02111-1307, USA.
21 21
22 ;;; Synched up with: FSF 19.34 [Partially]. 22 ;;; Synched up with: FSF 19.30.
23 23
24 ;;; Commentary: 24 ;;; Commentary:
25 25
26 ;; This package supplies the string and regular-expression replace functions 26 ;; This package supplies the string and regular-expression replace functions
27 ;; documented in the XEmacs Reference Manual. 27 ;; documented in the XEmacs Reference Manual.
28 28
29 ;; All the gettext calls are for XEmacs I18N3 message catalog support.
30
31 ;;; Code: 29 ;;; Code:
32 30
33 (defconst case-replace t "\ 31 (defvar case-replace t "\
34 *Non-nil means `query-replace' should preserve case in replacements. 32 *Non-nil means `query-replace' should preserve case in replacements.
35 What this means is that `query-replace' will change the case of the 33 What this means is that `query-replace' will change the case of the
36 replacement text so that it matches the text that was replaced. 34 replacement text so that it matches the text that was replaced.
37 If this variable is nil, the replacement text will be inserted 35 If this variable is nil, the replacement text will be inserted
38 exactly as it was specified by the user, irrespective of the case 36 exactly as it was specified by the user, irrespective of the case
145 143
146 (defun replace-string (from-string to-string &optional delimited) 144 (defun replace-string (from-string to-string &optional delimited)
147 "Replace occurrences of FROM-STRING with TO-STRING. 145 "Replace occurrences of FROM-STRING with TO-STRING.
148 Preserve case in each match if `case-replace' and `case-fold-search' 146 Preserve case in each match if `case-replace' and `case-fold-search'
149 are non-nil and FROM-STRING has no uppercase letters. 147 are non-nil and FROM-STRING has no uppercase letters.
150 \(Preserving case means that if the string matched is all caps, or capitalized,
151 then its replacement is upcased or capitalized.)
152
153 Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace 148 Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
154 only matches surrounded by word boundaries. 149 only matches surrounded by word boundaries.
155 150
156 If `query-replace-interactive' is non-nil, the last incremental search 151 If `query-replace-interactive' is non-nil, the last incremental search
157 string is used as FROM-STRING--you don't have to specify it with the 152 string is used as FROM-STRING--you don't have to specify it with the
255 250
256 (defvar occur-mode-map ()) 251 (defvar occur-mode-map ())
257 (if occur-mode-map 252 (if occur-mode-map
258 () 253 ()
259 (setq occur-mode-map (make-sparse-keymap)) 254 (setq occur-mode-map (make-sparse-keymap))
260 (set-keymap-name occur-mode-map 'occur-mode-map) ; XEmacs 255 (set-keymap-name occur-mode-map 'occur-mode-map)
261 (define-key occur-mode-map 'button2 'occur-mode-mouse-goto) ; XEmacs 256 (define-key occur-mode-map 'button2 'occur-mode-mouse-goto)
262 (define-key occur-mode-map "\C-c\C-c" 'occur-mode-goto-occurrence) 257 (define-key occur-mode-map "\C-c\C-c" 'occur-mode-goto-occurrence)
263 (define-key occur-mode-map "\C-m" 'occur-mode-goto-occurrence)) 258 (define-key occur-mode-map "\C-m" 'occur-mode-goto-occurrence))
264 259
265 (defvar occur-buffer nil) 260 (defvar occur-buffer nil)
266 (defvar occur-nlines nil) 261 (defvar occur-nlines nil)
274 269
275 \\{occur-mode-map}" 270 \\{occur-mode-map}"
276 (kill-all-local-variables) 271 (kill-all-local-variables)
277 (use-local-map occur-mode-map) 272 (use-local-map occur-mode-map)
278 (setq major-mode 'occur-mode) 273 (setq major-mode 'occur-mode)
279 (setq mode-name (gettext "Occur")) ; XEmacs 274 (setq mode-name (gettext "Occur"))
280 (make-local-variable 'occur-buffer) 275 (make-local-variable 'occur-buffer)
281 (make-local-variable 'occur-nlines) 276 (make-local-variable 'occur-nlines)
282 (make-local-variable 'occur-pos-list) 277 (make-local-variable 'occur-pos-list)
283 (require 'mode-motion) ; XEmacs 278 (require 'mode-motion)
284 (setq mode-motion-hook 'mode-motion-highlight-line) ; XEmacs 279 (setq mode-motion-hook 'mode-motion-highlight-line)
285 (run-hooks 'occur-mode-hook)) 280 (run-hooks 'occur-mode-hook))
286 281
287 ;; FSF Version of next function: 282 (defun occur-mode-mouse-goto (e)
288 ; (let (buffer pos)
289 ; (save-excursion
290 ; (set-buffer (window-buffer (posn-window (event-end event))))
291 ; (save-excursion
292 ; (goto-char (posn-point (event-end event)))
293 ; (setq pos (occur-mode-find-occurrence))
294 ; (setq buffer occur-buffer)))
295 ; (pop-to-buffer buffer)
296 ; (goto-char (marker-position pos))))
297
298 (defun occur-mode-mouse-goto (event)
299 "Go to the occurrence highlighted by mouse. 283 "Go to the occurrence highlighted by mouse.
300 This function is only reasonable when bound to a mouse key in the occur buffer" 284 This function is only reasonable when bound to a mouse key in the occur buffer"
301 (interactive "e") 285 (interactive "e")
302 (let ((window-save (selected-window)) 286 (let ((window-save (selected-window))
303 (frame-save (selected-frame))) 287 (frame-save (selected-frame)))
304 ;; preserve the window/frame setup 288 ;; preserve the window/frame setup
305 (unwind-protect 289 (unwind-protect
306 (progn 290 (progn
307 (mouse-set-point event) 291 (mouse-set-point e)
308 (occur-mode-goto-occurrence)) 292 (occur-mode-goto-occurrence))
309 (select-frame frame-save) 293 (select-frame frame-save)
310 (select-window window-save)))) 294 (select-window window-save))))
311 295
312 ;; Called occur-mode-find-occurrence in FSF
313 (defun occur-mode-goto-occurrence () 296 (defun occur-mode-goto-occurrence ()
314 "Go to the occurrence the current line describes." 297 "Go to the occurrence the current line describes."
315 (interactive) 298 (interactive)
316 (if (or (null occur-buffer) 299 (if (or (null occur-buffer)
317 (null (buffer-name occur-buffer))) 300 (null (buffer-name occur-buffer)))
338 (occur-source-buffer occur-buffer)) 321 (occur-source-buffer occur-buffer))
339 (if (< line-count 1) 322 (if (< line-count 1)
340 (error "No occurrence on this line")) 323 (error "No occurrence on this line"))
341 (or pos 324 (or pos
342 (error "No occurrence on this line")) 325 (error "No occurrence on this line"))
343 ;; XEmacs: don't raise window unless it isn't visible 326 ;; don't raise window unless it isn't visible
344 ;; allow for the possibility that the occur buffer is on another frame 327 ;; allow for the possibility that the occur buffer is on another frame
345 (or (and window 328 (or (and window
346 (window-live-p window) 329 (window-live-p window)
347 (frame-visible-p (window-frame window)) 330 (frame-visible-p (window-frame window))
348 (set-buffer occur-source-buffer)) 331 (set-buffer occur-source-buffer))
359 342
360 ;; XEmacs addition 343 ;; XEmacs addition
361 ;;; Damn you Jamie, this is utter trash. 344 ;;; Damn you Jamie, this is utter trash.
362 (defvar list-matching-lines-whole-buffer t 345 (defvar list-matching-lines-whole-buffer t
363 "If t, occur operates on whole buffer, otherwise occur starts from point. 346 "If t, occur operates on whole buffer, otherwise occur starts from point.
364 default is t.") 347 default is nil.")
365 348
366 (define-function 'occur 'list-matching-lines) 349 (define-function 'occur 'list-matching-lines)
367 (defun list-matching-lines (regexp &optional nlines) 350 (defun list-matching-lines (regexp &optional nlines)
368 "Show all lines in the current buffer containing a match for REGEXP. 351 "Show all lines in the current buffer containing a match for REGEXP.
369 352
370 If a match spreads across multiple lines, all those lines are shown. 353 If a match spreads across multiple lines, all those lines are shown.
371 354
372 If variable `list-matching-lines-whole-buffer' is non-nil, the entire buffer is 355 If variable `list-matching-lines-whole-buffer' is non-nil, the entire buffer is
373 searched, otherwise search begins at point. 356 searched, otherwise search begins at point.
374 357
375 Each line is displayed with NLINES lines before and after, or -NLINES 358 Each line is displayed with NLINES lines before and after,
376 before if NLINES is negative. 359 or -NLINES before if NLINES is negative.
377 NLINES defaults to `list-matching-lines-default-context-lines'. 360 NLINES defaults to `list-matching-lines-default-context-lines'.
378 Interactively it is the prefix arg. 361 Interactively it is the prefix arg.
379 362
380 The lines are shown in a buffer named `*Occur*'. 363 The lines are shown in a buffer named `*Occur*'.
381 It serves as a menu to find any of the occurrences in this buffer. 364 It serves as a menu to find any of the occurrences in this buffer.
382 \\[describe-mode] in that buffer will explain how." 365 \\[describe-mode] in that buffer will explain how."
383 (interactive 366 (interactive
384 ;; XEmacs change
385 (list (let* ((default (or (symbol-near-point) 367 (list (let* ((default (or (symbol-near-point)
386 (and regexp-history 368 (and regexp-history
387 (car regexp-history)))) 369 (car regexp-history))))
388 (minibuffer-history-minimum-string-length 0) 370 (minibuffer-history-minimum-string-length 0)
389 (input 371 (input
412 (let ((first t) 394 (let ((first t)
413 (dir default-directory) 395 (dir default-directory)
414 (buffer (current-buffer)) 396 (buffer (current-buffer))
415 (linenum 1) 397 (linenum 1)
416 (prevpos (point-min)) 398 (prevpos (point-min))
417 ;; The rest of this function is very different from FSF.
418 ;; Presumably that's due to Jamie's misfeature
419 (final-context-start (make-marker))) 399 (final-context-start (make-marker)))
420 (if (not list-matching-lines-whole-buffer) 400 (if (not list-matching-lines-whole-buffer)
421 (save-excursion 401 (save-excursion
422 (beginning-of-line) 402 (beginning-of-line)
423 (setq linenum (1+ (count-lines (point-min) (point)))) 403 (setq linenum (1+ (count-lines (point-min) (point))))
438 (if (eq buffer standard-output) 418 (if (eq buffer standard-output)
439 (goto-char (point-max))) 419 (goto-char (point-max)))
440 (save-excursion 420 (save-excursion
441 (if list-matching-lines-whole-buffer 421 (if list-matching-lines-whole-buffer
442 (beginning-of-buffer)) 422 (beginning-of-buffer))
443 (message (format "Searching for %s ..." regexp)) 423 (message "Searching for %s ..." regexp)
444 ;; Find next match, but give up if prev match was at end of buffer. 424 ;; Find next match, but give up if prev match was at end of buffer.
445 (while (and (not (= prevpos (point-max))) 425 (while (and (not (= prevpos (point-max)))
446 (re-search-forward regexp nil t)) 426 (re-search-forward regexp nil t))
447 (goto-char (match-beginning 0)) 427 (goto-char (match-beginning 0))
448 (beginning-of-line) 428 (beginning-of-line)
516 (if (interactive-p) 496 (if (interactive-p)
517 (message "%d matching lines." (length occur-pos-list))))))) 497 (message "%d matching lines." (length occur-pos-list)))))))
518 498
519 ;; It would be nice to use \\[...], but there is no reasonable way 499 ;; It would be nice to use \\[...], but there is no reasonable way
520 ;; to make that display both SPC and Y. 500 ;; to make that display both SPC and Y.
521 (defconst query-replace-help 501 (defvar query-replace-help (purecopy
522 (purecopy 502 "Type Space or `y' to replace one match, Delete or `n' to skip to next,
523 "Type Space or `y' to replace one match, Delete or `n' to skip to next,
524 RET or `q' to exit, Period to replace one match and exit, 503 RET or `q' to exit, Period to replace one match and exit,
525 Comma to replace but not move point immediately, 504 Comma to replace but not move point immediately,
526 C-r to enter recursive edit (\\[exit-recursive-edit] to get out again), 505 C-r to enter recursive edit (\\[exit-recursive-edit] to get out again),
527 C-w to delete match and recursive edit, 506 C-w to delete match and recursive edit,
528 C-l to clear the frame, redisplay, and offer same replacement again, 507 C-l to clear the frame, redisplay, and offer same replacement again,
529 ! to replace all remaining matches with no more questions, 508 ! to replace all remaining matches with no more questions,
530 ^ to move point back to previous match." 509 ^ to move point back to previous match.")
531 )
532 "Help message while in query-replace") 510 "Help message while in query-replace")
533 511
534 (defvar query-replace-map nil 512 (defvar query-replace-map nil
535 "Keymap that defines the responses to questions in `query-replace'. 513 "Keymap that defines the responses to questions in `query-replace'.
536 The \"bindings\" in this map are not commands; they are answers. 514 The \"bindings\" in this map are not commands; they are answers.
537 The valid answers include `act', `skip', `act-and-show', 515 The valid answers include `act', `skip', `act-and-show',
538 `exit', `act-and-exit', `edit', `delete-and-edit', `recenter', 516 `exit', `act-and-exit', `edit', `delete-and-edit', `recenter',
539 `automatic', `backup', `exit-prefix', and `help'.") 517 `automatic', `backup', `exit-prefix', and `help'.")
540 518
541 ;; Why does it seem that ever file has a different method of doing this?
542 (if query-replace-map 519 (if query-replace-map
543 nil 520 nil
544 (let ((map (make-sparse-keymap))) 521 (let ((map (make-sparse-keymap)))
545 (set-keymap-name map 'query-replace-map) 522 (set-keymap-name map 'query-replace-map)
546 (define-key map " " 'act) 523 (define-key map " " 'act)
573 (setq query-replace-map map))) 550 (setq query-replace-map map)))
574 551
575 552
576 (autoload 'isearch-highlight "isearch") 553 (autoload 'isearch-highlight "isearch")
577 554
578 ;; XEmacs
579 (defun perform-replace-next-event (event) 555 (defun perform-replace-next-event (event)
580 (if isearch-highlight 556 (if isearch-highlight
581 (let ((aborted t)) 557 (let ((aborted t))
582 (unwind-protect 558 (unwind-protect
583 (progn 559 (progn
584 (if (match-beginning 0) 560 (isearch-highlight (match-beginning 0) (match-end 0))
585 (isearch-highlight (match-beginning 0) (match-end 0)))
586 (next-command-event event) 561 (next-command-event event)
587 (setq aborted nil)) 562 (setq aborted nil))
588 (isearch-dehighlight aborted))) 563 (isearch-dehighlight aborted)))
589 (next-command-event event))) 564 (next-command-event event)))
590 565
598 (replace-match \"foobar\" nil nil)) 573 (replace-match \"foobar\" nil nil))
599 which will run faster and probably do exactly what you want." 574 which will run faster and probably do exactly what you want."
600 (or map (setq map query-replace-map)) 575 (or map (setq map query-replace-map))
601 (let* ((event (make-event)) 576 (let* ((event (make-event))
602 (nocasify (not (and case-fold-search case-replace 577 (nocasify (not (and case-fold-search case-replace
603 (string-equal from-string 578 (string-equal from-string
604 (downcase from-string))))) 579 (downcase from-string)))))
605 (literal (not regexp-flag)) 580 (literal (not regexp-flag))
606 (search-function (if regexp-flag 're-search-forward 'search-forward)) 581 (search-function (if regexp-flag 're-search-forward 'search-forward))
607 (search-string from-string) 582 (search-string from-string)
608 (real-match-data nil) ; the match data for the current match 583 (real-match-data nil) ; the match data for the current match
609 (next-replacement nil) 584 (next-replacement nil)
632 (if regexp-flag from-string 607 (if regexp-flag from-string
633 (regexp-quote from-string)) 608 (regexp-quote from-string))
634 "\\b"))) 609 "\\b")))
635 (push-mark) 610 (push-mark)
636 (undo-boundary) 611 (undo-boundary)
637 (unwind-protect 612 ;; Loop finding occurrences that perhaps should be replaced.
638 ;; Loop finding occurrences that perhaps should be replaced. 613 (while (and keep-going
639 (while (and keep-going 614 (not (eobp))
640 (not (eobp)) 615 (let ((case-fold-search qr-case-fold-search))
641 (let ((case-fold-search qr-case-fold-search)) 616 (funcall search-function search-string nil t))
642 (funcall search-function search-string nil t)) 617 ;; If the search string matches immediately after
643 ;; If the search string matches immediately after 618 ;; the previous match, but it did not match there
644 ;; the previous match, but it did not match there 619 ;; before the replacement was done, ignore the match.
645 ;; before the replacement was done, ignore the match. 620 (if (or (eq lastrepl (point))
646 (if (or (eq lastrepl (point)) 621 (and regexp-flag
647 (and regexp-flag 622 (eq lastrepl (match-beginning 0))
648 (eq lastrepl (match-beginning 0)) 623 (not match-again)))
649 (not match-again))) 624
650 (if (eobp) 625 (if (eobp)
651 nil 626 nil
652 ;; Don't replace the null string 627 ;; Don't replace the null string
653 ;; right after end of previous replacement. 628 ;; right after end of previous replacement.
654 (forward-char 1) 629 (forward-char 1)
655 (let ((case-fold-search qr-case-fold-search)) 630 (let ((case-fold-search qr-case-fold-search))
656 (funcall search-function search-string nil t))) 631 (funcall search-function search-string nil t)))
657 t)) 632 t))
658 633 ;; Save the data associated with the real match.
659 ;; Save the data associated with the real match. 634 (setq real-match-data (match-data))
660 (setq real-match-data (match-data)) 635
661 636 ;; Before we make the replacement, decide whether the search string
662 ;; Before we make the replacement, decide whether the search string 637 ;; can match again just after this match.
663 ;; can match again just after this match. 638 (if regexp-flag
664 (if regexp-flag 639 (progn
665 (progn 640 (setq match-again (looking-at search-string))
666 (setq match-again (looking-at search-string)) 641 (store-match-data real-match-data)))
667 ;; XEmacs addition 642
668 (store-match-data real-match-data))) 643 ;; If time for a change, advance to next replacement string.
669 ;; If time for a change, advance to next replacement string. 644 (if (and (listp replacements)
670 (if (and (listp replacements) 645 (= next-rotate-count replace-count))
671 (= next-rotate-count replace-count)) 646 (progn
672 (progn 647 (setq next-rotate-count
673 (setq next-rotate-count 648 (+ next-rotate-count repeat-count))
674 (+ next-rotate-count repeat-count)) 649 (setq next-replacement (nth replacement-index replacements))
675 (setq next-replacement (nth replacement-index replacements)) 650 (setq replacement-index (% (1+ replacement-index) (length replacements)))))
676 (setq replacement-index (% (1+ replacement-index) (length replacements))))) 651 (if (not query-flag)
677 (if (not query-flag) 652 (progn
678 (progn 653 (store-match-data real-match-data)
679 (store-match-data real-match-data) 654 (replace-match next-replacement nocasify literal)
680 (replace-match next-replacement nocasify literal) 655 (setq replace-count (1+ replace-count)))
681 (setq replace-count (1+ replace-count))) 656 (undo-boundary)
682 (undo-boundary) 657 (let ((help-form
683 (let ((help-form 658 '(concat (format "Query replacing %s%s with %s.\n\n"
684 '(concat (format "Query replacing %s%s with %s.\n\n" 659 (if regexp-flag (gettext "regexp ") "")
685 (if regexp-flag (gettext "regexp ") "") 660 from-string next-replacement)
686 from-string next-replacement) 661 (substitute-command-keys query-replace-help)))
687 (substitute-command-keys query-replace-help))) 662 (done nil)
688 done replaced def) 663 (replaced nil)
689 ;; Loop reading commands until one of them sets done, 664 def)
690 ;; which means it has finished handling this occurrence. 665 ;; Loop reading commands until one of them sets done,
691 (while (not done) 666 ;; which means it has finished handling this occurrence.
692 ;; Don't fill up the message log 667 (while (not done)
693 ;; with a bunch of identical messages. 668 ;; Don't fill up the message log
694 ;; XEmacs change 669 ;; with a bunch of identical messages.
695 (display-message 'prompt 670 (display-message 'prompt
696 (format message from-string next-replacement)) 671 (format message from-string next-replacement))
697 (perform-replace-next-event event) 672 (perform-replace-next-event event)
698 (setq def (lookup-key map (vector event))) 673 (setq def (lookup-key map (vector event)))
699 ;; Restore the match data while we process the command. 674 ;; Restore the match data while we process the command.
700 (store-match-data real-match-data) 675 (store-match-data real-match-data)
701 (cond ((eq def 'help) 676 (cond ((eq def 'help)
702 (with-output-to-temp-buffer (gettext "*Help*") 677 (with-output-to-temp-buffer (gettext "*Help*")
703 (princ (concat 678 (princ (concat
704 (format "Query replacing %s%s with %s.\n\n" 679 (format "Query replacing %s%s with %s.\n\n"
705 (if regexp-flag "regexp " "") 680 (if regexp-flag "regexp " "")
706 from-string next-replacement) 681 from-string next-replacement)
707 (substitute-command-keys 682 (substitute-command-keys
708 query-replace-help))) 683 query-replace-help)))
709 (save-excursion 684 (save-excursion
710 (set-buffer standard-output) 685 (set-buffer standard-output)
711 (help-mode)))) 686 (help-mode))))
712 ((eq def 'exit) 687 ((eq def 'exit)
713 (setq keep-going nil) 688 (setq keep-going nil)
714 (setq done t)) 689 (setq done t))
715 ((eq def 'backup) 690 ((eq def 'backup)
716 (if stack 691 (if stack
717 (let ((elt (car stack))) 692 (let ((elt (car stack)))
718 (goto-char (car elt)) 693 (goto-char (car elt))
719 (setq replaced (eq t (cdr elt))) 694 (setq replaced (eq t (cdr elt)))
720 (or replaced 695 (or replaced
721 (store-match-data (cdr elt))) 696 (store-match-data (cdr elt)))
722 (setq stack (cdr stack))) 697 (setq stack (cdr stack)))
698 (progn
723 (message "No previous match") 699 (message "No previous match")
724 (ding 'no-terminate) 700 (ding 'no-terminate)
725 (sit-for 1))) 701 (sit-for 1))))
726 ((eq def 'act) 702 ((eq def 'act)
727 (or replaced 703 (or replaced
728 (replace-match next-replacement nocasify literal)) 704 (replace-match next-replacement nocasify literal))
729 (setq done t replaced t)) 705 (setq done t replaced t))
730 ((eq def 'act-and-exit) 706 ((eq def 'act-and-exit)
731 (or replaced 707 (or replaced
732 (replace-match next-replacement nocasify literal)) 708 (replace-match next-replacement nocasify literal))
733 (setq keep-going nil) 709 (setq keep-going nil)
734 (setq done t replaced t)) 710 (setq done t replaced t))
735 ((eq def 'act-and-show) 711 ((eq def 'act-and-show)
736 (if (not replaced) 712 (if (not replaced)
737 (progn 713 (progn
738 (replace-match next-replacement nocasify literal) 714 (replace-match next-replacement nocasify literal)
739 (store-match-data nil) 715 (setq replaced t))))
740 (setq replaced t)))) 716 ((eq def 'automatic)
741 ((eq def 'automatic) 717 (or replaced
742 (or replaced 718 (replace-match next-replacement nocasify literal))
743 (replace-match next-replacement nocasify literal)) 719 (setq done t query-flag nil replaced t))
744 (setq done t query-flag nil replaced t)) 720 ((eq def 'skip)
745 ((eq def 'skip) 721 (setq done t))
746 (setq done t)) 722 ((eq def 'recenter)
747 ((eq def 'recenter) 723 (recenter nil))
748 (recenter nil)) 724 ((eq def 'edit)
749 ((eq def 'edit) 725 (store-match-data
750 (store-match-data 726 (prog1 (match-data)
751 (prog1 (match-data) 727 (save-excursion (recursive-edit))))
752 (save-excursion (recursive-edit)))) 728 ;; Before we make the replacement,
753 ;; Before we make the replacement, 729 ;; decide whether the search string
754 ;; decide whether the search string 730 ;; can match again just after this match.
755 ;; can match again just after this match. 731 (if regexp-flag
756 (if regexp-flag 732 (setq match-again (looking-at search-string))))
757 (setq match-again (looking-at search-string)))) 733 ((eq def 'delete-and-edit)
758 ((eq def 'delete-and-edit) 734 (delete-region (match-beginning 0) (match-end 0))
759 (delete-region (match-beginning 0) (match-end 0)) 735 (store-match-data (prog1 (match-data)
760 (store-match-data (prog1 (match-data) 736 (save-excursion (recursive-edit))))
761 (save-excursion (recursive-edit)))) 737 (setq replaced t))
762 (setq replaced t)) 738 ;; Note: we do not need to treat `exit-prefix'
763 ;; Note: we do not need to treat `exit-prefix' 739 ;; specially here, since we reread
764 ;; specially here, since we reread 740 ;; any unrecognized character.
765 ;; any unrecognized character. 741 (t
766 (t 742 (setq this-command 'mode-exited)
767 (setq this-command 'mode-exited) 743 (setq keep-going nil)
768 (setq keep-going nil) 744 (setq unread-command-events
769 (setq unread-command-events 745 (cons event unread-command-events))
770 (cons event unread-command-events)) 746 (setq done t))))
771 (setq done t)))) 747 ;; Record previous position for ^ when we move on.
772 ;; Record previous position for ^ when we move on. 748 ;; Change markers to numbers in the match data
773 ;; Change markers to numbers in the match data 749 ;; since lots of markers slow down editing.
774 ;; since lots of markers slow down editing. 750 (setq stack
775 (setq stack 751 (cons (cons (point)
776 (cons (cons (point) 752 (or replaced
777 (or replaced 753 (mapcar
778 (mapcar 754 #'(lambda (elt)
779 #'(lambda (elt) 755 (if (markerp elt)
780 (if (markerp elt) 756 (prog1 (marker-position elt)
781 (prog1 (marker-position elt) 757 (set-marker elt nil))
782 (set-marker elt nil)) 758 elt))
783 elt)) 759 (match-data))))
784 (match-data)))) 760 stack))
785 stack)) 761 (if replaced (setq replace-count (1+ replace-count)))))
786 (if replaced (setq replace-count (1+ replace-count))))) 762 (setq lastrepl (point)))
787 (setq lastrepl (point)))
788 (replace-dehighlight))
789 (or unread-command-events 763 (or unread-command-events
790 (message "Replaced %d occurrence%s" 764 (message "Replaced %d occurrence%s"
791 replace-count 765 replace-count
792 (if (= replace-count 1) "" "s"))) 766 (if (= replace-count 1) "" "s")))
793 (and keep-going stack))) 767 (and keep-going stack)))
794 768
795 (defvar query-replace-highlight nil 769 ; FSF 19.30 original:
796 "*Non-nil means to highlight words during query replacement.") 770 ; (defun match-string (num &optional string)
797 771 ; "Return string of text matched by last search.
798 (defvar replace-overlay nil) 772 ; NUM specifies which parenthesized expression in the last regexp.
799 773 ; Value is nil if NUMth pair didn't match, or there were less than NUM pairs.
800 (defun replace-dehighlight () 774 ; Zero means the entire text matched by the whole regexp or whole string.
801 (and replace-overlay 775 ; STRING should be given if the last search was by `string-match' on STRING."
802 (progn 776 ; (if (match-beginning num)
803 (delete-overlay replace-overlay) 777 ; (if string
804 (setq replace-overlay nil)))) 778 ; (substring string (match-beginning num) (match-end num))
805 779 ; (buffer-substring (match-beginning num) (match-end num)))))
806 (defun replace-highlight (start end) 780
807 (and query-replace-highlight 781 ;; #### - this could stand to be in C...
808 (progn 782 (defmacro match-string (n &optional string)
809 (or replace-overlay 783 "Returns the Nth subexpression matched by the last regular expression
810 (progn 784 search. The second argument, STRING, must be specified if the last
811 (setq replace-overlay (make-overlay start end)) 785 regular expression search was done with `string-match'."
812 (overlay-put replace-overlay 'face 786 ;; #### - note that match-beginning is byte coded, so it's more efficient
813 (if (internal-find-face 'query-replace) 787 ;; to just call it twice than it is to let-bind its return value... --Stig
814 'query-replace 'region)))) 788 `(and (match-beginning ,n)
815 (move-overlay replace-overlay start end (current-buffer))))) 789 ,(if string
816 790 `(substring ,string (match-beginning ,n) (match-end ,n))
817 (defun match-string (num &optional string) 791 `(buffer-substring (match-beginning ,n) (match-end ,n)))))
818 "Return string of text matched by last search.
819 NUM specifies which parenthesized expression in the last regexp.
820 Value is nil if NUMth pair didn't match, or there were less than NUM pairs.
821 Zero means the entire text matched by the whole regexp or whole string.
822 STRING should be given if the last search was by `string-match' on STRING."
823 (if (match-beginning num)
824 (if string
825 (substring string (match-beginning num) (match-end num))
826 (buffer-substring (match-beginning num) (match-end num)))))
827 792
828 (defmacro save-match-data (&rest body) 793 (defmacro save-match-data (&rest body)
829 "Execute BODY forms, restoring the global value of the match data." 794 "Execute BODY forms, restoring the global value of the match data."
830 (let ((original (make-symbol "match-data"))) 795 (let ((original (make-symbol "match-data")))
831 (list 'let (list (list original '(match-data))) 796 (list 'let (list (list original '(match-data)))