]> code.delx.au - gnu-emacs/blobdiff - lisp/replace.el
(Vchar_unify_table): Comment added.
[gnu-emacs] / lisp / replace.el
index 3680d574e8c55a1178b349b169446a80effacad6..0b57ea35fc19b9da7ea76ea0cc2a243dea8f629b 100644 (file)
@@ -7,10 +7,10 @@
 
 ;; 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:
 
@@ -225,20 +223,21 @@ only matches surrounded by word boundaries.
 Fourth and fifth arg START and END specify the region to operate on.
 
 To customize possible responses, change the \"bindings\" in `query-replace-map'."
-  (interactive (let ((common
-                     (query-replace-read-args
-                      (if (and transient-mark-mode mark-active)
-                        "Query replace in region"
-                        "Query replace")
-                        nil)))
-                (list (nth 0 common) (nth 1 common) (nth 2 common)
-                      ;; These are done separately here
-                      ;; so that command-history will record these expressions
-                      ;; rather than the values they had this time.
-                      (if (and transient-mark-mode mark-active)
-                          (region-beginning))
-                      (if (and transient-mark-mode mark-active)
-                          (region-end)))))
+  (interactive
+   (let ((common
+         (query-replace-read-args
+          (concat "Query replace"
+                  (if current-prefix-arg " word" "")
+                  (if (and transient-mark-mode mark-active) " in region" ""))
+          nil)))
+     (list (nth 0 common) (nth 1 common) (nth 2 common)
+          ;; These are done separately here
+          ;; so that command-history will record these expressions
+          ;; rather than the values they had this time.
+          (if (and transient-mark-mode mark-active)
+              (region-beginning))
+          (if (and transient-mark-mode mark-active)
+              (region-end)))))
   (perform-replace from-string to-string t nil delimited nil nil start end))
 
 (define-key esc-map "%" 'query-replace)
@@ -291,9 +290,10 @@ Use \\[repeat-complex-command] after this command for details."
   (interactive
    (let ((common
          (query-replace-read-args
-          (if (and transient-mark-mode mark-active)
-              "Query replace regexp in region"
-            "Query replace regexp")
+          (concat "Query replace"
+                  (if current-prefix-arg " word" "")
+                  " regexp"
+                  (if (and transient-mark-mode mark-active) " in region" ""))
           t)))
      (list (nth 0 common) (nth 1 common) (nth 2 common)
           ;; These are done separately here
@@ -449,9 +449,10 @@ and TO-STRING is also null.)"
   (interactive
    (let ((common
          (query-replace-read-args
-          (if (and transient-mark-mode mark-active)
-              "Replace string in region"
-            "Replace string")
+          (concat "Replace"
+                  (if current-prefix-arg " word" "")
+                  " string"
+                  (if (and transient-mark-mode mark-active) " in region" ""))
           nil)))
      (list (nth 0 common) (nth 1 common) (nth 2 common)
           (if (and transient-mark-mode mark-active)
@@ -506,9 +507,10 @@ which will run faster and will not set the mark or print anything."
   (interactive
    (let ((common
          (query-replace-read-args
-          (if (and transient-mark-mode mark-active)
-              "Replace regexp in region"
-            "Replace regexp")
+          (concat "Replace"
+                  (if current-prefix-arg " word" "")
+                  " regexp"
+                  (if (and transient-mark-mode mark-active) " in region" ""))
           t)))
      (list (nth 0 common) (nth 1 common) (nth 2 common)
           (if (and transient-mark-mode mark-active)
@@ -524,6 +526,39 @@ which will run faster and will not set the mark or print anything."
 Maximum length of the history list is determined by the value
 of `history-length', which see.")
 
+(defun read-regexp (prompt &optional default-value)
+  "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 argument DEFAULT-VALUE
+provides the value to display in the minibuffer prompt that is
+returned if the user just types RET.
+Values available via M-n 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-value
+              (format "%s (default %s): " prompt
+                      (query-replace-descr default-value))
+            (format "%s: " prompt))
+          nil nil nil 'regexp-history defaults t)))
+    (if (equal input "")
+       default-value
+      (prog1 input
+       (add-to-history 'regexp-history input)))))
+
 
 (defalias 'delete-non-matching-lines 'keep-lines)
 (defalias 'delete-matching-lines 'flush-lines)
@@ -534,20 +569,7 @@ of `history-length', which see.")
   "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.
@@ -576,7 +598,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))
@@ -651,7 +673,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))
@@ -681,7 +703,7 @@ starting on the same line at which another match ended is ignored."
   "Print and return number of matches for REGEXP following point.
 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.
+in all respects as if it had been called interactively.
 
 If REGEXP contains upper case characters (excluding those preceded by `\\')
 and `search-upper-case' is non-nil, the matching is case-sensitive.
@@ -697,7 +719,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
@@ -752,26 +774,36 @@ a previously found match."
                               "Display another occurrence when moving the cursor"))
     (define-key map [separator-1] '("--"))
     (define-key map [kill-this-buffer] 
-      '("Kill occur buffer" . kill-this-buffer))
+      '(menu-item "Kill occur buffer" kill-this-buffer
+                 :help "Kill the current *Occur* buffer"))
     (define-key map [quit-window] 
-      '("Quit occur window" . 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] 
-      '("Revert occur buffer" . 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] 
-      '("Clone occur buffer" . 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] 
-      '("Rename occur buffer" . 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]
-      '("Go To Occurrence Other Window" . 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]
-      '("Go To Occurrence" . 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]
-      '("Display Occurrence" . 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] 
-      '("Move to next match" . 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] 
-      '("Move to previous match" . 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'.")
 
@@ -995,29 +1027,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*.
@@ -1113,6 +1126,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
@@ -1363,6 +1378,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
@@ -1467,6 +1496,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)
@@ -1492,7 +1533,10 @@ make, or the user didn't cancel the call."
            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)
@@ -1503,6 +1547,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)
@@ -1524,6 +1569,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:
@@ -1621,8 +1671,7 @@ make, or the user didn't cancel the call."
                    (funcall (car replacements) (cdr replacements)
                             replace-count)))
            (if (not query-flag)
-               (let ((inhibit-read-only
-                      query-replace-skip-read-only))
+               (progn
                  (unless (or literal noedit)
                    (replace-highlight
                     (nth 0 real-match-data) (nth 1 real-match-data)
@@ -1671,6 +1720,7 @@ make, or the user didn't cancel the call."
                         (with-output-to-temp-buffer "*Help*"
                           (princ
                            (concat "Query replacing "
+                                   (if delimited-flag "word " "")
                                    (if regexp-flag "regexp " "")
                                    from-string " with "
                                    next-replacement ".\n\n"
@@ -1681,6 +1731,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)))
@@ -1720,14 +1772,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)
@@ -1814,7 +1867,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)