Bump version to 24.0.94
[bpt/emacs.git] / lisp / isearch.el
index 6eab3db..9d69443 100644 (file)
@@ -1,6 +1,6 @@
 ;;; isearch.el --- incremental search minor mode
 
-;; Copyright (C) 1992-1997, 1999-2011  Free Software Foundation, Inc.
+;; Copyright (C) 1992-1997, 1999-2012  Free Software Foundation, Inc.
 
 ;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
 ;; Maintainer: FSF
@@ -102,7 +102,7 @@ in Isearch mode is always downcased."
   :group 'isearch)
 
 (defcustom search-nonincremental-instead t
-  "If non-nil, do a nonincremental search instead if exiting immediately.
+  "If non-nil, do a nonincremental search instead of exiting immediately.
 Actually, `isearch-edit-string' is called to let you enter the search
 string, and RET terminates editing and does a nonincremental search."
   :type 'boolean
@@ -542,8 +542,8 @@ Each set is a vector of the form:
 (defvar isearch-string "")  ; The current search string.
 (defvar isearch-message "") ; text-char-description version of isearch-string
 
-(defvar isearch-message-prefix-add nil) ; Additonal text for the message prefix
-(defvar isearch-message-suffix-add nil) ; Additonal text for the message suffix
+(defvar isearch-message-prefix-add nil) ; Additional text for the message prefix
+(defvar isearch-message-suffix-add nil) ; Additional text for the message suffix
 
 (defvar isearch-success t)     ; Searching is currently successful.
 (defvar isearch-error nil)     ; Error message for failed search.
@@ -835,7 +835,8 @@ It is called by the function `isearch-forward' and other related functions."
 ;; Some high level utilities.  Others below.
 
 (defun isearch-update ()
-  ;; Called after each command to update the display.
+  "This is called after every isearch command to update the display.
+The last thing it does is to run `isearch-update-post-hook'."
   (if (and (null unread-command-events)
           (null executing-kbd-macro))
       (progn
@@ -1063,21 +1064,24 @@ nonincremental search instead via `isearch-edit-string'."
 
 (defvar minibuffer-history-symbol) ;; from external package gmhist.el
 
-(defun isearch-fail-pos ()
-  "Position of first mismatch in search string, or its length if none."
-  (let ((cmds isearch-cmds))
-    (if (and isearch-success (not isearch-error))
-        (length isearch-message)
+(defun isearch-fail-pos (&optional msg)
+  "Return position of first mismatch in search string, or nil if none.
+If MSG is non-nil, use `isearch-message', otherwise `isearch-string'."
+  (let ((cmds isearch-cmds)
+       (curr-msg (if msg isearch-message isearch-string))
+       succ-msg)
+    (when (or (not isearch-success) isearch-error)
       (while (or (not (isearch-success-state (car cmds)))
                  (isearch-error-state (car cmds)))
         (pop cmds))
-      (let ((succ-msg (and cmds (isearch-message-state (car cmds)))))
-        (if (and (stringp succ-msg)
-                 (< (length succ-msg) (length isearch-message))
-                 (equal succ-msg
-                        (substring isearch-message 0 (length succ-msg))))
-            (length succ-msg)
-          0)))))
+      (setq succ-msg (and cmds (if msg (isearch-message-state (car cmds))
+                                (isearch-string-state (car cmds)))))
+      (if (and (stringp succ-msg)
+              (< (length succ-msg) (length curr-msg))
+              (equal succ-msg
+                     (substring curr-msg 0 (length succ-msg))))
+         (length succ-msg)
+       0))))
 
 (defun isearch-edit-string ()
   "Edit the search string in the minibuffer.
@@ -1087,9 +1091,7 @@ The following additional command keys are active while editing.
 \\[isearch-nonincremental-exit-minibuffer] to do one nonincremental search.
 \\[isearch-forward-exit-minibuffer] to resume isearching forward.
 \\[isearch-reverse-exit-minibuffer] to resume isearching backward.
-\\[isearch-complete-edit] to complete the search string using the search ring.
-\\<isearch-mode-map>
-If first char entered is \\[isearch-yank-word-or-char], then do word search instead."
+\\[isearch-complete-edit] to complete the search string using the search ring."
 
   ;; This code is very hairy for several reasons, explained in the code.
   ;; Mainly, isearch-mode must be terminated while editing and then restarted.
@@ -1109,6 +1111,7 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst
              (isearch-new-message isearch-message)
              (isearch-new-forward isearch-forward)
              (isearch-new-word isearch-word)
+             (isearch-new-case-fold isearch-case-fold-search)
 
              (isearch-regexp isearch-regexp)
              (isearch-op-fun isearch-op-fun)
@@ -1160,18 +1163,18 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst
 
          (unwind-protect
              (let* ((message-log-max nil)
-                    ;; Protect global value of search rings from updating
-                    ;; by `read-from-minibuffer'.  It should be updated only
-                    ;; by `isearch-update-ring' in `isearch-done', not here.
-                    (search-ring search-ring)
-                    (regexp-search-ring regexp-search-ring)
+                    ;; Don't add a new search string to the search ring here
+                    ;; in `read-from-minibuffer'. It should be added only
+                    ;; by `isearch-update-ring' called from `isearch-done'.
+                    (history-add-new-input nil)
                     ;; Binding minibuffer-history-symbol to nil is a work-around
                     ;; for some incompatibility with gmhist.
                     (minibuffer-history-symbol))
                (setq isearch-new-string
                       (read-from-minibuffer
                        (isearch-message-prefix nil nil isearch-nonincremental)
-                      (cons isearch-string (1+ (isearch-fail-pos)))
+                      (cons isearch-string (1+ (or (isearch-fail-pos)
+                                                   (length isearch-string))))
                        minibuffer-local-isearch-map nil
                        (if isearch-regexp
                           (cons 'regexp-search-ring
@@ -1201,7 +1204,8 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst
            (setq isearch-string isearch-new-string
                  isearch-message isearch-new-message
                  isearch-forward isearch-new-forward
-                 isearch-word isearch-new-word))
+                 isearch-word isearch-new-word
+                 isearch-case-fold-search isearch-new-case-fold))
 
          ;; Empty isearch-string means use default.
          (when (= 0 (length isearch-string))
@@ -1381,8 +1385,8 @@ Use `isearch-exit' to quit without signaling."
   "Start `query-replace' with string to replace from last search string.
 The arg DELIMITED (prefix arg if interactive), if non-nil, means replace
 only matches surrounded by word boundaries.  Note that using the prefix arg
-is possible only when `isearch-allow-scroll' is non-nil, and it don't
-always provides the correct matches for `query-replace', so the preferred
+is possible only when `isearch-allow-scroll' is non-nil, and it doesn't
+always provide the correct matches for `query-replace', so the preferred
 way to run word replacements from Isearch is `M-s w ... M-%'."
   (interactive
    (list current-prefix-arg))
@@ -1429,26 +1433,43 @@ See `isearch-query-replace' for more information."
   (isearch-query-replace delimited t))
 
 (defun isearch-occur (regexp &optional nlines)
-  "Run `occur' with regexp to search from the current search string.
-Interactively, REGEXP is the current search regexp or a quoted search
-string.  NLINES has the same meaning as in `occur'."
+  "Run `occur' using the last search string as the regexp.
+Interactively, REGEXP is constructed using the search string from the
+last search command.  NLINES has the same meaning as in `occur'.
+
+If the last search command was a word search, REGEXP is computed from
+the search words, ignoring punctuation.  If the last search
+command was a regular expression search, REGEXP is the regular
+expression used in that search.  If the last search command searched
+for a literal string, REGEXP is constructed by quoting all the special
+characters in that string."
   (interactive
-   (list
-    (cond
-     (isearch-word (concat "\\b" (replace-regexp-in-string
-                                 "\\W+" "\\W+"
-                                 (replace-regexp-in-string
-                                  "^\\W+\\|\\W+$" "" isearch-string)
-                                 nil t)
-                          "\\b"))
-     (isearch-regexp isearch-string)
-     (t (regexp-quote isearch-string)))
-    (if current-prefix-arg (prefix-numeric-value current-prefix-arg))))
+   (let* ((perform-collect (consp current-prefix-arg))
+         (regexp (cond
+                  (isearch-word (word-search-regexp isearch-string))
+                  (isearch-regexp isearch-string)
+                  (t (regexp-quote isearch-string)))))
+     (list regexp
+          (if perform-collect
+              ;; Perform collect operation
+              (if (zerop (regexp-opt-depth regexp))
+                  ;; No subexpression so collect the entire match.
+                  "\\&"
+                ;; Get the regexp for collection pattern.
+                (isearch-done nil t)
+                (isearch-clean-overlays)
+                (let ((default (car occur-collect-regexp-history)))
+                  (read-string
+                   (format "Regexp to collect (default %s): " default)
+                   nil 'occur-collect-regexp-history default)))
+            ;; Otherwise normal occur takes numerical prefix argument.
+            (when current-prefix-arg
+              (prefix-numeric-value current-prefix-arg))))))
   (let ((case-fold-search isearch-case-fold-search)
        ;; Set `search-upper-case' to nil to not call
        ;; `isearch-no-upper-case-p' in `occur-1'.
        (search-upper-case nil)
-       (search-spaces-regexp search-whitespace-regexp))
+       (search-spaces-regexp (if isearch-regexp search-whitespace-regexp)))
     (occur regexp nlines)))
 
 (declare-function hi-lock-read-face-name "hi-lock" ())
@@ -1545,7 +1566,10 @@ If search string is empty, just beep."
 (defun isearch-yank-x-selection ()
   "Pull current X selection into search string."
   (interactive)
-  (isearch-yank-string (x-get-selection)))
+  (isearch-yank-string (x-get-selection))
+  ;; If `x-get-selection' returned the text from the active region,
+  ;; then it "used" the mark which we should hence deactivate.
+  (when select-active-regions (deactivate-mark)))
 
 
 (defun isearch-mouse-2 (click)
@@ -1636,8 +1660,10 @@ Subword is used when `subword-mode' is activated. "
                   (if (and (eq case-fold-search t) search-upper-case)
                       (setq case-fold-search
                             (isearch-no-upper-case-p isearch-string isearch-regexp)))
-                  (looking-at (if isearch-regexp isearch-string
-                                (regexp-quote isearch-string))))
+                  (looking-at (cond
+                               (isearch-word (word-search-regexp isearch-string t))
+                               (isearch-regexp isearch-string)
+                               (t (regexp-quote isearch-string)))))
               (error nil))
             (or isearch-yank-flag
                 (<= (match-end 0)
@@ -1800,9 +1826,13 @@ Scroll-bar or mode-line events are processed appropriately."
 ;; Commands which change the window layout
 (put 'delete-other-windows 'isearch-scroll t)
 (put 'balance-windows 'isearch-scroll t)
+(put 'split-window-right 'isearch-scroll t)
+(put 'split-window-below 'isearch-scroll t)
+(put 'enlarge-window 'isearch-scroll t)
+
+;; Aliases for split-window-*
 (put 'split-window-vertically 'isearch-scroll t)
 (put 'split-window-horizontally 'isearch-scroll t)
-(put 'enlarge-window 'isearch-scroll t)
 
 ;; Universal argument commands
 (put 'universal-argument 'isearch-scroll t)
@@ -1865,7 +1895,7 @@ the bottom."
   (goto-char isearch-point))
 
 (defun isearch-reread-key-sequence-naturally (keylist)
-  "Reread key sequence KEYLIST with Isearch mode's keymap deactivated.
+  "Reread key sequence KEYLIST with an inactive Isearch-mode keymap.
 Return the key sequence as a string/vector."
   (isearch-unread-key-sequence keylist)
   (let (overriding-terminal-local-map)
@@ -1920,6 +1950,7 @@ Isearch mode."
           (if (lookup-key global-map key)
               (progn
                 (isearch-done)
+                (setq prefix-arg arg)
                 (apply 'isearch-unread keylist))
             (setq keylist
                   (listify-key-sequence (lookup-key local-function-key-map key)))
@@ -1935,6 +1966,7 @@ Isearch mode."
                     (setq keylist (cdr keylist)))
                 ;; As the remaining keys in KEYLIST can't be handled
                 ;; here, we must reread them.
+                (setq prefix-arg arg)
                 (apply 'isearch-unread keylist)
                 (setq keylist nil)))))
          (
@@ -1957,8 +1989,10 @@ Isearch mode."
                               isearch-other-control-char)))))
           (setcar keylist (- main-event (- ?\C-\S-a ?\C-a)))
           (cancel-kbd-macro-events)
+          (setq prefix-arg arg)
           (apply 'isearch-unread keylist))
          ((eq search-exit-option 'edit)
+          (setq prefix-arg arg)
           (apply 'isearch-unread keylist)
           (isearch-edit-string))
           ;; Handle a scrolling function.
@@ -1987,6 +2021,7 @@ Isearch mode."
           (isearch-edit-string))
          (search-exit-option
           (let (window)
+            (setq prefix-arg arg)
              (isearch-unread-key-sequence keylist)
              (setq main-event (car unread-command-events))
 
@@ -2171,22 +2206,11 @@ If there is no completion possible, say so and continue searching."
   ;; Generate and print the message string.
   (let ((cursor-in-echo-area ellipsis)
        (m isearch-message)
-       (cmds isearch-cmds)
-       succ-msg)
-    (when (or (not isearch-success) isearch-error)
-      ;; Highlight failed part
-      (while (or (not (isearch-success-state (car cmds)))
-                (isearch-error-state (car cmds)))
-       (pop cmds))
-      (setq succ-msg (and cmds (isearch-message-state (car cmds)))
-           m (copy-sequence m))
-      (add-text-properties
-       (if (and (stringp succ-msg)
-               (< (length succ-msg) (length m))
-               (equal succ-msg (substring m 0 (length succ-msg))))
-          (length succ-msg)
-        0)
-       (length m) '(face isearch-fail) m)
+       (fail-pos (isearch-fail-pos t)))
+    ;; Highlight failed part
+    (when fail-pos
+      (setq m (copy-sequence m))
+      (add-text-properties fail-pos (length m) '(face isearch-fail) m)
       ;; Highlight failed trailing whitespace
       (when (string-match " +$" m)
        (add-text-properties (match-beginning 0) (match-end 0)
@@ -2224,7 +2248,11 @@ If there is no completion possible, say so and continue searching."
                   (if nonincremental "search" "I-search")
                   (if isearch-forward "" " backward")
                   (if current-input-method
-                      (concat " [" current-input-method-title "]: ")
+                      ;; Input methods for RTL languages use RTL
+                      ;; characters for their title, and that messes
+                      ;; up the display of search text after the prompt.
+                      (bidi-string-mark-left-to-right
+                       (concat " [" current-input-method-title "]: "))
                     ": ")
                   )))
     (propertize (concat (upcase (substring m 0 1)) (substring m 1))
@@ -2241,7 +2269,7 @@ If there is no completion possible, say so and continue searching."
 ;; Searching
 
 (defvar isearch-search-fun-function nil
-  "Overrides the default `isearch-search-fun' behaviour.
+  "Overrides the default `isearch-search-fun' behavior.
 This variable's value should be a function, which will be called
 with no arguments, and should return a function that takes three
 arguments: STRING, BOUND, and NOERROR.
@@ -2619,6 +2647,7 @@ since they have special meaning in a regexp."
 (defvar isearch-lazy-highlight-case-fold-search nil)
 (defvar isearch-lazy-highlight-regexp nil)
 (defvar isearch-lazy-highlight-space-regexp nil)
+(defvar isearch-lazy-highlight-word nil)
 (defvar isearch-lazy-highlight-forward nil)
 (defvar isearch-lazy-highlight-error nil)
 
@@ -2657,6 +2686,8 @@ by other Emacs features."
                          isearch-case-fold-search))
                 (not (eq isearch-lazy-highlight-regexp
                          isearch-regexp))
+                (not (eq isearch-lazy-highlight-word
+                         isearch-word))
                  (not (= (window-start)
                          isearch-lazy-highlight-window-start))
                  (not (= (window-end)   ; Window may have been split/joined.
@@ -2669,24 +2700,27 @@ by other Emacs features."
     ;; something important did indeed change
     (lazy-highlight-cleanup t) ;kill old loop & remove overlays
     (setq isearch-lazy-highlight-error isearch-error)
-    (when (not isearch-error)
-      (setq isearch-lazy-highlight-start-limit beg
-           isearch-lazy-highlight-end-limit end)
-      (setq isearch-lazy-highlight-window       (selected-window)
-            isearch-lazy-highlight-window-start (window-start)
-            isearch-lazy-highlight-window-end   (window-end)
-            isearch-lazy-highlight-start        (point)
-            isearch-lazy-highlight-end          (point)
-            isearch-lazy-highlight-last-string  isearch-string
-           isearch-lazy-highlight-case-fold-search isearch-case-fold-search
-           isearch-lazy-highlight-regexp       isearch-regexp
-            isearch-lazy-highlight-wrapped      nil
-           isearch-lazy-highlight-space-regexp search-whitespace-regexp
-           isearch-lazy-highlight-forward      isearch-forward)
+    ;; It used to check for `(not isearch-error)' here, but actually
+    ;; lazy-highlighting might find matches to highlight even when
+    ;; `isearch-error' is non-nil.  (Bug#9918)
+    (setq isearch-lazy-highlight-start-limit beg
+         isearch-lazy-highlight-end-limit end)
+    (setq isearch-lazy-highlight-window       (selected-window)
+         isearch-lazy-highlight-window-start (window-start)
+         isearch-lazy-highlight-window-end   (window-end)
+         isearch-lazy-highlight-start        (point)
+         isearch-lazy-highlight-end          (point)
+         isearch-lazy-highlight-wrapped      nil
+         isearch-lazy-highlight-last-string  isearch-string
+         isearch-lazy-highlight-case-fold-search isearch-case-fold-search
+         isearch-lazy-highlight-regexp       isearch-regexp
+         isearch-lazy-highlight-space-regexp search-whitespace-regexp
+         isearch-lazy-highlight-word         isearch-word
+         isearch-lazy-highlight-forward      isearch-forward)
       (unless (equal isearch-string "")
        (setq isearch-lazy-highlight-timer
              (run-with-idle-timer lazy-highlight-initial-delay nil
-                                  'isearch-lazy-highlight-update))))))
+                                  'isearch-lazy-highlight-update)))))
 
 (defun isearch-lazy-highlight-search ()
   "Search ahead for the next or previous match, for lazy highlighting.
@@ -2695,6 +2729,7 @@ Attempt to do the search exactly the way the pending Isearch would."
       (let ((case-fold-search isearch-lazy-highlight-case-fold-search)
            (isearch-regexp isearch-lazy-highlight-regexp)
            (search-spaces-regexp isearch-lazy-highlight-space-regexp)
+           (isearch-word isearch-lazy-highlight-word)
            (search-invisible nil)      ; don't match invisible text
            (retry t)
            (success nil)