Move comment for last change to right place.
[bpt/emacs.git] / lisp / replace.el
index 8b2c3b9..086380f 100644 (file)
@@ -1,16 +1,16 @@
 ;;; replace.el --- replace commands for Emacs
 
 ;; Copyright (C) 1985, 1986, 1987, 1992, 1994, 1996, 1997, 2000, 2001,
-;;   2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+;;   2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -18,9 +18,7 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -519,7 +517,41 @@ which will run faster and will not set the mark or print anything."
 
 \f
 (defvar regexp-history nil
-  "History list for some commands that read regular expressions.")
+  "History list for some commands that read regular expressions.
+
+Maximum length of the history list is determined by the value
+of `history-length', which see.")
+
+(defun read-regexp (prompt &optional default)
+  "Read regexp as a string using the regexp history and some useful defaults.
+Prompt for a regular expression with PROMPT (without a colon and
+space) in the minibuffer.  The optional string argument DEFAULT
+provides the basic default value, that is returned on typing RET.
+Additional defaults are the string at point, the last isearch regexp,
+the last isearch string, and the last replacement regexp."
+  (let* ((defaults
+          (list (regexp-quote
+                 (or (funcall (or find-tag-default-function
+                                  (get major-mode 'find-tag-default-function)
+                                  'find-tag-default))
+                     ""))
+                (car regexp-search-ring)
+                (regexp-quote (or (car search-ring) ""))
+                (car (symbol-value
+                      query-replace-from-history-variable))))
+        (defaults (delete-dups (delq nil (delete "" defaults))))
+        ;; Don't add automatically the car of defaults for empty input
+        (history-add-new-input nil)
+        (input
+         (read-from-minibuffer
+          (if default
+              (format "%s (default %s): " prompt (query-replace-descr default))
+            (format "%s: " prompt))
+          nil nil nil 'regexp-history defaults t)))
+    (if (equal input "")
+       default
+      (prog1 input
+       (add-to-history 'regexp-history input)))))
 
 
 (defalias 'delete-non-matching-lines 'keep-lines)
@@ -531,20 +563,7 @@ which will run faster and will not set the mark or print anything."
   "Read arguments for `keep-lines' and friends.
 Prompt for a regexp with PROMPT.
 Value is a list, (REGEXP)."
-  (let* ((default (list
-                  (regexp-quote
-                   (or (funcall (or find-tag-default-function
-                                    (get major-mode 'find-tag-default-function)
-                                    'find-tag-default))
-                       ""))
-                  (car regexp-search-ring)
-                  (regexp-quote (or (car search-ring) ""))
-                  (car (symbol-value
-                        query-replace-from-history-variable))))
-        (default (delete-dups (delq nil (delete "" default)))))
-    (list (read-from-minibuffer prompt nil nil nil
-                               'regexp-history default t)
-         nil nil t)))
+  (list (read-regexp prompt) nil nil t))
 
 (defun keep-lines (regexp &optional rstart rend interactive)
   "Delete all lines except those containing matches for REGEXP.
@@ -552,8 +571,8 @@ A match split across lines preserves all the lines it lies in.
 When called from Lisp (and usually interactively as well, see below)
 applies to all lines starting after point.
 
-If REGEXP contains upper case characters (excluding those preceded by `\\'),
-the matching is case-sensitive.
+If REGEXP contains upper case characters (excluding those preceded by `\\')
+and `search-upper-case' is non-nil, the matching is case-sensitive.
 
 Second and third arg RSTART and REND specify the region to operate on.
 This command operates on (the accessible part of) all lines whose
@@ -573,7 +592,7 @@ a previously found match."
   (interactive
    (progn
      (barf-if-buffer-read-only)
-     (keep-lines-read-args "Keep lines (containing match for regexp): ")))
+     (keep-lines-read-args "Keep lines containing match for regexp")))
   (if rstart
       (progn
        (goto-char (min rstart rend))
@@ -597,8 +616,10 @@ a previously found match."
   (save-excursion
     (or (bolp) (forward-line 1))
     (let ((start (point))
-         (case-fold-search  (and case-fold-search
-                                 (isearch-no-upper-case-p regexp t))))
+         (case-fold-search
+          (if (and case-fold-search search-upper-case)
+              (isearch-no-upper-case-p regexp t)
+            case-fold-search)))
       (while (< (point) rend)
        ;; Start is first char not preserved by previous match.
        (if (not (re-search-forward regexp rend 'move))
@@ -626,8 +647,8 @@ well, see below), applies to the part of the buffer after point.
 The line point is in is deleted if and only if it contains a
 match for regexp starting after point.
 
-If REGEXP contains upper case characters (excluding those preceded by `\\'),
-the matching is case-sensitive.
+If REGEXP contains upper case characters (excluding those preceded by `\\')
+and `search-upper-case' is non-nil, the matching is case-sensitive.
 
 Second and third arg RSTART and REND specify the region to operate on.
 Lines partially contained in this region are deleted if and only if
@@ -646,7 +667,7 @@ starting on the same line at which another match ended is ignored."
   (interactive
    (progn
      (barf-if-buffer-read-only)
-     (keep-lines-read-args "Flush lines (containing match for regexp): ")))
+     (keep-lines-read-args "Flush lines containing match for regexp")))
   (if rstart
       (progn
        (goto-char (min rstart rend))
@@ -657,8 +678,10 @@ starting on the same line at which another match ended is ignored."
       (setq rstart (point)
            rend (point-max-marker)))
     (goto-char rstart))
-  (let ((case-fold-search (and case-fold-search
-                              (isearch-no-upper-case-p regexp t))))
+  (let ((case-fold-search
+        (if (and case-fold-search search-upper-case)
+            (isearch-no-upper-case-p regexp t)
+          case-fold-search)))
     (save-excursion
       (while (and (< (point) rend)
                  (re-search-forward regexp rend t))
@@ -676,8 +699,8 @@ When called from Lisp and INTERACTIVE is omitted or nil, just return
 the number, do not print it; if INTERACTIVE is t, the function behaves
 in all respects has if it had been called interactively.
 
-If REGEXP contains upper case characters (excluding those preceded by `\\'),
-the matching is case-sensitive.
+If REGEXP contains upper case characters (excluding those preceded by `\\')
+and `search-upper-case' is non-nil, the matching is case-sensitive.
 
 Second and third arg RSTART and REND specify the region to operate on.
 
@@ -690,7 +713,7 @@ the previous match.  Hence, it ignores matches that overlap
 a previously found match."
 
   (interactive
-   (keep-lines-read-args "How many matches for (regexp): "))
+   (keep-lines-read-args "How many matches for regexp"))
   (save-excursion
     (if rstart
        (progn
@@ -704,8 +727,10 @@ a previously found match."
       (goto-char rstart))
     (let ((count 0)
          opoint
-         (case-fold-search (and case-fold-search
-                                (isearch-no-upper-case-p regexp t))))
+         (case-fold-search
+          (if (and case-fold-search search-upper-case)
+              (isearch-no-upper-case-p regexp t)
+            case-fold-search)))
       (while (and (< (point) rend)
                  (progn (setq opoint (point))
                         (re-search-forward regexp rend t)))
@@ -734,6 +759,45 @@ a previously found match."
     (define-key map "q" 'quit-window)
     (define-key map "z" 'kill-this-buffer)
     (define-key map "\C-c\C-f" 'next-error-follow-minor-mode)
+    (define-key map [menu-bar] (make-sparse-keymap))
+    (define-key map [menu-bar occur]
+      (cons "Occur" map))
+    (define-key map [next-error-follow-minor-mode]
+      (menu-bar-make-mm-toggle next-error-follow-minor-mode
+                              "Auto Occurrence Display"
+                              "Display another occurrence when moving the cursor"))
+    (define-key map [separator-1] '("--"))
+    (define-key map [kill-this-buffer] 
+      '(menu-item "Kill occur buffer" kill-this-buffer
+                 :help "Kill the current *Occur* buffer"))
+    (define-key map [quit-window] 
+      '(menu-item "Quit occur window" quit-window
+                 :help "Quit the current *Occur* buffer.  Bury it, and maybe delete the selected frame"))
+    (define-key map [revert-buffer] 
+      '(menu-item "Revert occur buffer" revert-buffer
+                 :help "Replace the text in the *Occur* buffer with the results of rerunning occur"))
+    (define-key map [clone-buffer] 
+      '(menu-item "Clone occur buffer" clone-buffer
+                 :help "Create and return a twin copy of the current *Occur* buffer"))
+    (define-key map [occur-rename-buffer] 
+      '(menu-item "Rename occur buffer" occur-rename-buffer
+                 :help "Rename the current *Occur* buffer to *Occur: original-buffer-name*."))
+    (define-key map [separator-2] '("--"))
+    (define-key map [occur-mode-goto-occurrence-other-window]
+      '(menu-item "Go To Occurrence Other Window" occur-mode-goto-occurrence-other-window
+                 :help "Go to the occurrence the current line describes, in another window"))
+    (define-key map [occur-mode-goto-occurrence]
+      '(menu-item "Go To Occurrence" occur-mode-goto-occurrence
+                 :help "Go to the occurrence the current line describes"))
+    (define-key map [occur-mode-display-occurrence]
+      '(menu-item "Display Occurrence" occur-mode-display-occurrence
+                 :help "Display in another window the occurrence the current line describes"))
+    (define-key map [occur-next] 
+      '(menu-item "Move to next match" occur-next
+                 :help "Move to the Nth (default 1) next match in an Occur mode buffer"))
+    (define-key map [occur-prev] 
+      '(menu-item "Move to previous match" occur-prev
+                 :help "Move to the Nth (default 1) previous match in an Occur mode buffer"))
     map)
   "Keymap for `occur-mode'.")
 
@@ -751,6 +815,13 @@ See `occur-revert-function'.")
   :type 'hook
   :group 'matching)
 
+(defcustom occur-mode-find-occurrence-hook nil
+  "Hook run by Occur after locating an occurrence.
+This will be called with the cursor position at the occurrence.  An application
+for this is to reveal context in an outline-mode when the occurrence is hidden."
+  :type 'hook
+  :group 'matching)
+
 (put 'occur-mode 'mode-class 'special)
 (defun occur-mode ()
   "Major mode for output from \\[occur].
@@ -799,14 +870,16 @@ Alternatively, click \\[occur-mode-mouse-goto] on an item to go to it.
         same-window-buffer-names
         same-window-regexps)
     (pop-to-buffer (marker-buffer pos))
-    (goto-char pos)))
+    (goto-char pos)
+    (run-hooks 'occur-mode-find-occurrence-hook)))
 
 (defun occur-mode-goto-occurrence-other-window ()
   "Go to the occurrence the current line describes, in another window."
   (interactive)
   (let ((pos (occur-mode-find-occurrence)))
     (switch-to-buffer-other-window (marker-buffer pos))
-    (goto-char pos)))
+    (goto-char pos)
+    (run-hooks 'occur-mode-find-occurrence-hook)))
 
 (defun occur-mode-display-occurrence ()
   "Display in another window the occurrence the current line describes."
@@ -820,7 +893,8 @@ Alternatively, click \\[occur-mode-mouse-goto] on an item to go to it.
     ;; This is the way to set point in the proper window.
     (save-selected-window
       (select-window window)
-      (goto-char pos))))
+      (goto-char pos)
+      (run-hooks 'occur-mode-find-occurrence-hook))))
 
 (defun occur-find-match (n search message)
   (if (not n) (setq n 1))
@@ -947,29 +1021,10 @@ which means to discard all text properties."
       (nreverse result))))
 
 (defun occur-read-primary-args ()
-  (let* ((default
-          (list (and transient-mark-mode mark-active
-                     (regexp-quote
-                      (buffer-substring-no-properties
-                       (region-beginning) (region-end))))
-                (regexp-quote
-                 (or (funcall
-                      (or find-tag-default-function
-                          (get major-mode 'find-tag-default-function)
-                          'find-tag-default))
-                     ""))
-                (car regexp-search-ring)
-                (regexp-quote (or (car search-ring) ""))
-                (car (symbol-value
-                      query-replace-from-history-variable))))
-        (default (delete-dups (delq nil (delete "" default))))
-        (input
-         (read-from-minibuffer
-          "List lines matching regexp: "
-          nil nil nil 'regexp-history default)))
-    (list input
-         (when current-prefix-arg
-           (prefix-numeric-value current-prefix-arg)))))
+  (list (read-regexp "List lines matching regexp"
+                    (car regexp-history))
+       (when current-prefix-arg
+         (prefix-numeric-value current-prefix-arg))))
 
 (defun occur-rename-buffer (&optional unique-p interactive-p)
   "Rename the current *Occur* buffer to *Occur: original-buffer-name*.
@@ -1001,8 +1056,8 @@ The lines are shown in a buffer named `*Occur*'.
 It serves as a menu to find any of the occurrences in this buffer.
 \\<occur-mode-map>\\[describe-mode] in that buffer will explain how.
 
-If REGEXP contains upper case characters (excluding those preceded by `\\'),
-the matching is case-sensitive."
+If REGEXP contains upper case characters (excluding those preceded by `\\')
+and `search-upper-case' is non-nil, the matching is case-sensitive."
   (interactive (occur-read-primary-args))
   (occur-1 regexp nlines (list (current-buffer))))
 
@@ -1065,6 +1120,8 @@ See also `multi-occur'."
                           (buffer-list))))))
 
 (defun occur-1 (regexp nlines bufs &optional buf-name)
+  (unless (and regexp (not (equal regexp "")))
+    (error "Occur doesn't work with the empty regexp"))
   (unless buf-name
     (setq buf-name "*Occur*"))
   (let (occur-buf
@@ -1090,8 +1147,9 @@ See also `multi-occur'."
        (let ((count (occur-engine
                      regexp active-bufs occur-buf
                      (or nlines list-matching-lines-default-context-lines)
-                     (and case-fold-search
-                          (isearch-no-upper-case-p regexp t))
+                     (if (and case-fold-search search-upper-case)
+                         (isearch-no-upper-case-p regexp t)
+                       case-fold-search)
                      list-matching-lines-buffer-name-face
                      nil list-matching-lines-face
                      (not (eq occur-excluded-properties t)))))
@@ -1207,16 +1265,9 @@ See also `multi-occur'."
                            (if (= nlines 0)
                                ;; The simple display style
                                out-line
-                             ;; The complex multi-line display
-                             ;; style.  Generate a list of lines,
-                             ;; concatenate them all together.
-                             (apply #'concat
-                                    (nconc
-                                     (occur-engine-add-prefix (nreverse (cdr (occur-accumulate-lines (- (1+ (abs nlines))) keep-props))))
-                                     (list out-line)
-                                     (if (> nlines 0)
-                                         (occur-engine-add-prefix
-                                          (cdr (occur-accumulate-lines (1+ nlines) keep-props)))))))))
+                             ;; The complex multi-line display style.
+                             (occur-context-lines out-line nlines keep-props)
+                             )))
                      ;; Actually insert the match display data
                      (with-current-buffer out-buf
                        (let ((beg (point))
@@ -1254,6 +1305,21 @@ See also `multi-occur'."
       ;; Return the number of matches
       globalcount)))
 
+;; Generate context display for occur.
+;; OUT-LINE is the line where the match is.
+;; NLINES and KEEP-PROPS are args to occur-engine.
+;; Generate a list of lines, add prefixes to all but OUT-LINE,
+;; then concatenate them all together.
+(defun occur-context-lines (out-line nlines keep-props)
+  (apply #'concat
+        (nconc
+         (occur-engine-add-prefix
+          (nreverse (cdr (occur-accumulate-lines
+                          (- (1+ (abs nlines))) keep-props))))
+         (list out-line)
+         (if (> nlines 0)
+             (occur-engine-add-prefix
+              (cdr (occur-accumulate-lines (1+ nlines) keep-props)))))))
 \f
 ;; It would be nice to use \\[...], but there is no reasonable way
 ;; to make that display both SPC and Y.
@@ -1306,6 +1372,20 @@ The valid answers include `act', `skip', `act-and-show',
 `exit', `act-and-exit', `edit', `delete-and-edit', `recenter',
 `automatic', `backup', `exit-prefix', and `help'.")
 
+(defvar multi-query-replace-map
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-parent map query-replace-map)
+    (define-key map "Y" 'automatic-all)
+    (define-key map "N" 'exit-current)
+    map)
+  "Keymap that defines additional bindings for multi-buffer replacements.
+It extends its parent map `query-replace-map' with new bindings to
+operate on a set of buffers/files.  The difference with its parent map
+is the additional answers `automatic-all' to replace all remaining
+matches in all remaining buffers with no more questions, and
+`exit-current' to skip remaining matches in the current buffer
+and to continue with the next buffer in the sequence.")
+
 (defun replace-match-string-symbols (n)
   "Process a list (and any sub-lists), expanding certain symbols.
 Symbol  Expands To
@@ -1410,6 +1490,18 @@ passed in.  If LITERAL is set, no checking is done, anyway."
   (replace-match newtext fixedcase literal)
   noedit)
 
+(defvar replace-search-function 'search-forward
+  "Function to use when searching for strings to replace.
+It is used by `query-replace' and `replace-string', and is called
+with three arguments, as if it were `search-forward'.")
+
+(defvar replace-re-search-function 're-search-forward
+  "Function to use when searching for regexps to replace.
+It is used by `query-replace-regexp', `replace-regexp',
+`query-replace-regexp-eval', and `map-query-replace-regexp'.
+It is called with three arguments, as if it were
+`re-search-forward'.")
+
 (defun perform-replace (from-string replacements
                        query-flag regexp-flag delimited-flag
                        &optional repeat-count map start end)
@@ -1430,11 +1522,15 @@ make, or the user didn't cancel the call."
   (and query-flag minibuffer-auto-raise
        (raise-frame (window-frame (minibuffer-window))))
   (let* ((case-fold-search
-          (and case-fold-search
-               (isearch-no-upper-case-p from-string regexp-flag)))
+         (if (and case-fold-search search-upper-case)
+             (isearch-no-upper-case-p from-string regexp-flag)
+           case-fold-search))
          (nocasify (not (and case-replace case-fold-search)))
          (literal (or (not regexp-flag) (eq regexp-flag 'literal)))
-         (search-function (if regexp-flag 're-search-forward 'search-forward))
+         (search-function
+         (if regexp-flag
+             replace-re-search-function
+           replace-search-function))
          (search-string from-string)
          (real-match-data nil)       ; The match data for the current match.
          (next-replacement nil)
@@ -1445,6 +1541,7 @@ make, or the user didn't cancel the call."
          (stack nil)
          (replace-count 0)
          (nonempty-match nil)
+        (multi-buffer nil)
 
          ;; If non-nil, it is marker saying where in the buffer to stop.
          (limit nil)
@@ -1466,6 +1563,11 @@ make, or the user didn't cancel the call."
       (goto-char (min start end))
       (deactivate-mark))
 
+    ;; If last typed key in previous call of multi-buffer perform-replace
+    ;; was `automatic-all', don't ask more questions in next files
+    (when (eq (lookup-key map (vector last-input-char)) 'automatic-all)
+      (setq query-flag nil multi-buffer t))
+
     ;; REPLACEMENTS is either a string, a list of strings, or a cons cell
     ;; containing a function and its first argument.  The function is
     ;; called to generate each replacement like this:
@@ -1623,6 +1725,8 @@ make, or the user didn't cancel the call."
                        ((eq def 'exit)
                         (setq keep-going nil)
                         (setq done t))
+                       ((eq def 'exit-current)
+                        (setq multi-buffer t keep-going nil done t))
                        ((eq def 'backup)
                         (if stack
                             (let ((elt (pop stack)))
@@ -1662,14 +1766,15 @@ make, or the user didn't cancel the call."
                                   real-match-data (replace-match-data
                                                    t real-match-data)
                                   replaced t)))
-                       ((eq def 'automatic)
+                       ((or (eq def 'automatic) (eq def 'automatic-all))
                         (or replaced
                             (setq noedit
                                   (replace-match-maybe-edit
                                    next-replacement nocasify literal
                                    noedit real-match-data)
                                   replace-count (1+ replace-count)))
-                        (setq done t query-flag nil replaced t))
+                        (setq done t query-flag nil replaced t)
+                        (if (eq def 'automatic-all) (setq multi-buffer t)))
                        ((eq def 'skip)
                         (setq done t))
                        ((eq def 'recenter)
@@ -1756,7 +1861,7 @@ make, or the user didn't cancel the call."
        (message "Replaced %d occurrence%s"
                 replace-count
                 (if (= replace-count 1) "" "s")))
-    (and keep-going stack)))
+    (or (and keep-going stack) multi-buffer)))
 
 (defvar replace-overlay nil)