(occur-read-primary-args): Pass default to read-from-minibuffer.
[bpt/emacs.git] / lisp / isearch.el
index d84510e..a5261d2 100644 (file)
@@ -1,7 +1,7 @@
 ;;; isearch.el --- incremental search minor mode
 
-;; Copyright (C) 1992, 93, 94, 95, 96, 97, 1999, 2000, 01, 2003
-;;   Free Software Foundation, Inc.
+;; Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1999,
+;;   2000, 2001, 2003, 2004  Free Software Foundation, Inc.
 
 ;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
 ;; Maintainer: FSF
@@ -59,7 +59,6 @@
 
 ;; TODO
 ;; - Integrate the emacs 19 generalized command history.
-;; - Think about incorporating query-replace.
 ;; - Hooks and options for failed search.
 
 ;;; Change Log:
@@ -294,13 +293,16 @@ Default value, nil, means edit the string instead."
     (define-key map " " 'isearch-whitespace-chars)
     (define-key map [?\S-\ ] 'isearch-whitespace-chars)
 
-    (define-key map "\C-w" 'isearch-yank-word-or-char)
-    (define-key map "\C-y" 'isearch-yank-line)
+    (define-key map    "\C-w" 'isearch-yank-word-or-char)
+    (define-key map "\M-\C-w" 'isearch-del-char)
+    (define-key map "\M-\C-y" 'isearch-yank-char)
+    (define-key map    "\C-y" 'isearch-yank-line)
 
     ;; Define keys for regexp chars * ? |.
     ;; Nothing special for + because it matches at least once.
     (define-key map "*" 'isearch-*-char)
     (define-key map "?" 'isearch-*-char)
+    (define-key map "{" 'isearch-{-char)
     (define-key map "|" 'isearch-|-char)
 
     ;; Turned off because I find I expect to get the global definition--rms.
@@ -335,18 +337,27 @@ Default value, nil, means edit the string instead."
     (define-key map "\M-r" 'isearch-toggle-regexp)
     (define-key map "\M-e" 'isearch-edit-string)
 
+    (define-key map [?\M-%] 'isearch-query-replace)
+    (define-key map [?\C-\M-%] 'isearch-query-replace-regexp)
+
     map)
   "Keymap for `isearch-mode'.")
 
 (defvar minibuffer-local-isearch-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map minibuffer-local-map)
-    (define-key map "\r" 'isearch-nonincremental-exit-minibuffer)
-    (define-key map "\M-n" 'isearch-ring-advance-edit)
-    (define-key map "\M-p" 'isearch-ring-retreat-edit)
+    (define-key map "\r"    'isearch-nonincremental-exit-minibuffer)
+    (define-key map "\M-n"  'isearch-ring-advance-edit)
+    (define-key map [next]  'isearch-ring-advance-edit)
+    (define-key map [down]  'isearch-ring-advance-edit)
+    (define-key map "\M-p"  'isearch-ring-retreat-edit)
+    (define-key map [prior] 'isearch-ring-retreat-edit)
+    (define-key map [up]    'isearch-ring-retreat-edit)
     (define-key map "\M-\t" 'isearch-complete-edit)
-    (define-key map "\C-s" 'isearch-forward-exit-minibuffer)
-    (define-key map "\C-r" 'isearch-reverse-exit-minibuffer)
+    (define-key map "\C-s"  'isearch-forward-exit-minibuffer)
+    (define-key map "\C-r"  'isearch-reverse-exit-minibuffer)
+    (define-key map "\C-f"  'isearch-yank-char-in-minibuffer)
+    (define-key map [right] 'isearch-yank-char-in-minibuffer)
     map)
   "Keymap for editing isearch strings in the minibuffer.")
 
@@ -447,13 +458,16 @@ With a prefix argument, do an incremental regular expression search instead.
 As you type characters, they add to the search string and are found.
 The following non-printing keys are bound in `isearch-mode-map'.
 
-Type \\[isearch-delete-char] to cancel characters from end of search string.
+Type \\[isearch-delete-char] to cancel last input item from end of search string.
 Type \\[isearch-exit] to exit, leaving point at location found.
 Type LFD (C-j) to match end of line.
 Type \\[isearch-repeat-forward] to search again forward,\
  \\[isearch-repeat-backward] to search again backward.
 Type \\[isearch-yank-word-or-char] to yank word from buffer onto end of search\
  string and search for it.
+Type \\[isearch-del-char] to delete character from end of search string.
+Type \\[isearch-yank-char] to yank char from buffer onto end of search\
+ string and search for it.
 Type \\[isearch-yank-line] to yank rest of line onto end of search string\
  and search for it.
 Type \\[isearch-yank-kill] to yank last killed text onto end of search string\
@@ -485,7 +499,7 @@ To use a different input method for searching, type
 you want to use.
 
 The above keys, bound in `isearch-mode-map', are often controlled by
- options; do M-x apropos on search-.* to find them.
+ options; do \\[apropos] on search-.* to find them.
 Other control and meta characters terminate the search
  and are then executed normally (depending on `search-exit-option').
 Likewise for function keys and mouse button events.
@@ -995,7 +1009,8 @@ Use `isearch-exit' to quit without signaling."
 
   (if (equal isearch-string "")
       (setq isearch-success t)
-    (if (and isearch-success (equal (match-end 0) (match-beginning 0))
+    (if (and isearch-success
+            (equal (point) isearch-other-end)
             (not isearch-just-started))
        ;; If repeating a search that found
        ;; an empty string, ensure we advance.
@@ -1043,6 +1058,32 @@ Use `isearch-exit' to quit without signaling."
   (sit-for 1)
   (isearch-update))
 
+(defun isearch-query-replace ()
+  "Start query-replace with string to replace from last search string."
+  (interactive)
+  (barf-if-buffer-read-only)
+  (let ((case-fold-search isearch-case-fold-search))
+    (isearch-done)
+    (isearch-clean-overlays)
+    (and isearch-forward isearch-other-end (goto-char isearch-other-end))
+    (perform-replace
+     isearch-string
+     (query-replace-read-to isearch-string "Query replace" isearch-regexp)
+     t isearch-regexp isearch-word)))
+
+(defun isearch-query-replace-regexp ()
+  "Start query-replace-regexp with string to replace from last search string."
+  (interactive)
+  (let ((query-replace-interactive t)
+        (case-fold-search isearch-case-fold-search))
+    ;; Put search string into the right ring
+    (setq isearch-regexp t)
+    (isearch-done)
+    (isearch-clean-overlays)
+    (and isearch-forward isearch-other-end (goto-char isearch-other-end))
+    (call-interactively 'query-replace-regexp)))
+
+\f
 (defun isearch-delete-char ()
   "Discard last input item and move point back.
 If no previous match was done, just beep."
@@ -1052,6 +1093,18 @@ If no previous match was done, just beep."
     (isearch-pop-state))
   (isearch-update))
 
+(defun isearch-del-char (&optional arg)
+  "Delete character from end of search string and search again.
+If search string is empty, just beep."
+  (interactive "p")
+  (if (= 0 (length isearch-string))
+      (ding)
+    (setq isearch-string (substring isearch-string 0 (- (or arg 1)))
+          isearch-message (mapconcat 'isearch-text-char-description
+                                     isearch-string "")
+          ;; Don't move cursor in reverse search.
+          isearch-yank-flag t))
+  (isearch-search-and-update))
 
 (defun isearch-yank-string (string)
   "Pull STRING into search string."
@@ -1112,10 +1165,21 @@ might return the position of the end of the line."
          (goto-char isearch-other-end))
      (buffer-substring-no-properties (point) (funcall jumpform)))))
 
-(defun isearch-yank-char ()
-  "Pull next letter from buffer into search string."
-  (interactive)
-  (isearch-yank-internal (lambda () (forward-char 1) (point))))
+(defun isearch-yank-char-in-minibuffer (&optional arg)
+  "Pull next character from buffer into end of search string in minibuffer."
+  (interactive "p")
+  (if (eobp)
+      (insert
+       (save-excursion
+         (set-buffer (cadr (buffer-list)))
+         (buffer-substring-no-properties
+          (point) (progn (forward-char arg) (point)))))
+    (forward-char arg)))
+
+(defun isearch-yank-char (&optional arg)
+  "Pull next character from buffer into search string."
+  (interactive "p")
+  (isearch-yank-internal (lambda () (forward-char arg) (point))))
 
 (defun isearch-yank-word-or-char ()
   "Pull next character or word from buffer into search string."
@@ -1141,9 +1205,8 @@ might return the position of the end of the line."
 (defun isearch-search-and-update ()
   ;; Do the search and update the display.
   (when (or isearch-success
-           ;; unsuccessful regexp search may become
-           ;;  successful by addition of characters which
-           ;;  make isearch-string valid
+           ;; Unsuccessful regexp search may become successful by
+           ;; addition of characters which make isearch-string valid
            isearch-regexp
            ;; If the string was found but was completely invisible,
            ;; it might now be partly visible, so try again.
@@ -1186,21 +1249,30 @@ might return the position of the end of the line."
   (isearch-update))
 
 
+(defun isearch-{-char ()
+  "Handle \{ specially in regexps."
+  (interactive)
+  (isearch-*-char t))
+
 ;; *, ?, and | chars can make a regexp more liberal.
 ;; They can make a regexp match sooner or make it succeed instead of failing.
 ;; So go back to place last successful search started
 ;; or to the last ^S/^R (barrier), whichever is nearer.
 ;; + needs no special handling because the string must match at least once.
 
-(defun isearch-*-char ()
-  "Handle * and ? specially in regexps."
+(defun isearch-*-char (&optional want-backslash)
+  "Handle * and ? specially in regexps.
+When WANT-BACKSLASH is non-nil, do special handling for \{."
   (interactive)
   (if isearch-regexp
       (let ((idx (length isearch-string)))
        (while (and (> idx 0)
                    (eq (aref isearch-string (1- idx)) ?\\))
          (setq idx (1- idx)))
-       (when (= (mod (- (length isearch-string) idx) 2) 0)
+       ;; * and ? are special when not preceded by \.
+       ;; { is special when it is preceded by \.
+       (when (= (mod (- (length isearch-string) idx) 2)
+                (if want-backslash 1 0))
          (setq isearch-adjusted t)
          ;; Get the isearch-other-end from before the last search.
          ;; We want to start from there,
@@ -1461,7 +1533,9 @@ Isearch mode."
            (command-execute scroll-command)
            (let ((ab-bel (isearch-string-out-of-window isearch-point)))
              (if ab-bel
-                 (isearch-back-into-window (eq ab-bel 'above) isearch-point)))
+                 (isearch-back-into-window (eq ab-bel 'above) isearch-point)
+               (or (eq (point) isearch-point)
+                   (goto-char isearch-point))))
            (isearch-update))
          (search-exit-option
           (let (window)
@@ -1740,7 +1814,13 @@ If there is no completion possible, say so and continue searching."
   (let ((cursor-in-echo-area ellipsis)
        (m (concat
            (isearch-message-prefix c-q-hack ellipsis isearch-nonincremental)
-           isearch-message
+           (if (and (not isearch-success)
+                     (string-match " +$" isearch-message))
+                (concat
+                 (substring isearch-message 0 (match-beginning 0))
+                 (propertize (substring isearch-message (match-beginning 0))
+                             'face 'trailing-whitespace))
+              isearch-message)
            (isearch-message-suffix c-q-hack ellipsis)
            )))
     (if c-q-hack
@@ -1787,7 +1867,11 @@ If there is no completion possible, say so and continue searching."
 \f
 ;; Searching
 
-(defvar isearch-search-fun-function nil "Override `isearch-function-fun'.")
+(defvar isearch-search-fun-function nil
+  "Override `isearch-search-fun'.
+This function should return the search function for isearch to use.
+It will call this function with three arguments
+as if it were `search-forward'.")
 
 (defun isearch-search-fun ()
   "Return the function to use for the search.
@@ -2128,26 +2212,30 @@ A value of nil means highlight all matches."
   :group 'isearch)
 
 (defface isearch
-  '((((type tty pc) (class color))
-     (:background "magenta4" :foreground "cyan1"))
-    (((class color) (background light))
+  '((((class color) (min-colors 88) (background light))
      ;; The background must not be too dark, for that means
      ;; the character is hard to see when the cursor is there.
      (:background "magenta2" :foreground "lightskyblue1"))
-    (((class color) (background dark))
+    (((class color) (min-colors 88) (background dark))
      (:background "palevioletred2" :foreground "brown4"))
+    (((class color) (min-colors 16))
+     (:background "magenta4" :foreground "cyan1"))
+    (((class color) (min-colors 8))
+     (:background "magenta4" :foreground "cyan1"))
     (t (:inverse-video t)))
   "Face for highlighting Isearch matches."
   :group 'isearch-faces)
 (defvar isearch 'isearch)
 
 (defface isearch-lazy-highlight-face
-  '((((type tty pc) (class color))
-     (:background "turquoise3"))
-    (((class color) (background light))
+  '((((class color) (min-colors 88) (background light))
      (:background "paleturquoise"))
-    (((class color) (background dark))
+    (((class color) (min-colors 88) (background dark))
      (:background "paleturquoise4"))
+    (((class color) (min-colors 16))
+     (:background "turquoise3"))
+    (((class color) (min-colors 8))
+     (:background "turquoise3"))
     (t (:underline t)))
   "Face for lazy highlighting of Isearch matches other than the current one."
   :group 'isearch-faces)
@@ -2292,5 +2380,5 @@ CASE-FOLD non-nil means the search was case-insensitive."
        isearch-case-fold-search case-fold)
   (isearch-search))
 
-;;; arch-tag: 74850515-f7d8-43a6-8a2c-ca90a4c1e675
+;; arch-tag: 74850515-f7d8-43a6-8a2c-ca90a4c1e675
 ;;; isearch.el ends here