]> code.delx.au - gnu-emacs/blobdiff - lisp/isearch.el
Merge from emacs--devo--0
[gnu-emacs] / lisp / isearch.el
index 78b523f3845a7f687c5a46d84d9378fec88990c3..93d43fcf18b03c404aed19ed952eb263cc869564 100644 (file)
@@ -1,7 +1,7 @@
 ;;; isearch.el --- incremental search minor mode
 
 ;; Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000,
-;;   2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+;;   2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
 ;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
 ;; Maintainer: FSF
@@ -11,7 +11,7 @@
 
 ;; 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 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
@@ -164,6 +164,10 @@ is non-nil if the user quit the search.")
 (defvar isearch-mode-end-hook-quit nil
   "Non-nil while running `isearch-mode-end-hook' if user quit the search.")
 
+(defvar isearch-message-function nil
+  "Function to call to display the search prompt.
+If nil, use `isearch-message'.")
+
 (defvar isearch-wrap-function nil
   "Function to call to wrap the search when search is failed.
 If nil, move point to the beginning of the buffer for a forward search,
@@ -531,8 +535,7 @@ 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\
- and search for it.
+Type \\[isearch-yank-kill] to yank the last string of killed text.
 Type \\[isearch-quote-char] to quote control character to search for it.
 \\[isearch-abort] while searching or when search has failed cancels input\
  back to what has
@@ -716,7 +719,9 @@ is treated as a regexp.  See \\[isearch-forward] for more info."
           (null executing-kbd-macro))
       (progn
         (if (not (input-pending-p))
-            (isearch-message))
+           (if isearch-message-function
+               (funcall isearch-message-function)
+             (isearch-message)))
         (if (and isearch-slow-terminal-mode
                  (not (or isearch-small-window
                           (pos-visible-in-window-p))))
@@ -784,13 +789,15 @@ NOPUSH is t and EDIT is t."
   (lazy-highlight-cleanup lazy-highlight-cleanup)
   (let ((found-start (window-start (selected-window)))
        (found-point (point)))
-    (if isearch-window-configuration
-       (set-window-configuration isearch-window-configuration))
-
-    (if isearch-small-window
-       (goto-char found-point)
-      ;; Exiting the save-window-excursion clobbers window-start; restore it.
-      (set-window-start (selected-window) found-start t)))
+    (when isearch-window-configuration
+      (set-window-configuration isearch-window-configuration)
+      (if isearch-small-window
+         (goto-char found-point)
+       ;; set-window-configuration clobbers window-start; restore it.
+       ;; This has an annoying side effect of clearing the last_modiff
+       ;; field of the window, which can cause unwanted scrolling,
+       ;; so don't do it unless truly necessary.
+       (set-window-start (selected-window) found-start t))))
 
   (setq isearch-mode nil)
   (if isearch-input-method-local-p
@@ -831,21 +838,10 @@ NOPUSH is t and EDIT is t."
 (defun isearch-update-ring (string &optional regexp)
   "Add STRING to the beginning of the search ring.
 REGEXP if non-nil says use the regexp search ring."
-  (if regexp
-      (when (or (null regexp-search-ring)
-               (not (string= string (car regexp-search-ring))))
-       (when history-delete-duplicates
-         (setq regexp-search-ring (delete string regexp-search-ring)))
-       (push string regexp-search-ring)
-       (when (> (length regexp-search-ring) regexp-search-ring-max)
-         (setcdr (nthcdr (1- search-ring-max) regexp-search-ring) nil)))
-    (when (or (null search-ring)
-             (not (string= string (car search-ring))))
-      (when history-delete-duplicates
-       (setq search-ring (delete string search-ring)))
-      (push string search-ring)
-      (when (> (length search-ring) search-ring-max)
-       (setcdr (nthcdr (1- search-ring-max) search-ring) nil)))))
+  (add-to-history
+   (if regexp 'regexp-search-ring 'search-ring)
+   string
+   (if regexp regexp-search-ring-max search-ring-max)))
 
 ;; Switching buffers should first terminate isearch-mode.
 ;; ;; For Emacs 19, the frame switch event is handled.
@@ -1002,7 +998,7 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst
               isearch-original-minibuffer-message-timeout)
              (isearch-original-minibuffer-message-timeout
               isearch-original-minibuffer-message-timeout)
-             )
+             old-point old-other-end)
 
          ;; Actually terminate isearching until editing is done.
          ;; This is so that the user can do anything without failure,
@@ -1011,6 +1007,10 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst
              (isearch-done t t)
            (exit nil))                 ; was recursive editing
 
+         ;; Save old point and isearch-other-end before reading from minibuffer
+         ;; that can change their values.
+         (setq old-point (point) old-other-end isearch-other-end)
+
          (isearch-message) ;; for read-char
          (unwind-protect
              (let* (;; Why does following read-char echo?
@@ -1046,6 +1046,14 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst
                      isearch-new-message
                      (mapconcat 'isearch-text-char-description
                                 isearch-new-string "")))
+
+           ;; Set point at the start (end) of old match if forward (backward),
+           ;; so after exiting minibuffer isearch resumes at the start (end)
+           ;; of this match and can find it again.
+           (if (and old-other-end (eq old-point (point))
+                    (eq isearch-forward isearch-new-forward))
+               (goto-char old-other-end))
+
            ;; Always resume isearching by restarting it.
            (isearch-mode isearch-forward
                          isearch-regexp
@@ -1079,6 +1087,7 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst
 
        ;; Reinvoke the pending search.
        (isearch-search)
+       (isearch-push-state)
        (isearch-update)
        (if isearch-nonincremental
            (progn
@@ -1269,10 +1278,13 @@ If search string is empty, just beep."
       (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))
+                                     isearch-string "")))
+  ;; Use the isearch-other-end as new starting point to be able
+  ;; to find the remaining part of the search string again.
+  (if isearch-other-end (goto-char isearch-other-end))
+  (isearch-search)
+  (isearch-push-state)
+  (isearch-update))
 
 (defun isearch-yank-string (string)
   "Pull STRING into search string."
@@ -1304,23 +1316,18 @@ If search string is empty, just beep."
 (defun isearch-mouse-2 (click)
   "Handle mouse-2 in Isearch mode.
 For a click in the echo area, invoke `isearch-yank-x-selection'.
-Otherwise invoke whatever mouse-2 is bound to outside of Isearch."
+Otherwise invoke whatever the calling mouse-2 command sequence
+is bound to outside of Isearch."
   (interactive "e")
   (let* ((w (posn-window (event-start click)))
         (overriding-terminal-local-map nil)
-        (key (vector (event-basic-type click)))
-        ;; FIXME: `key-binding' should accept an event as argument
-        ;; and do all the overlay/text-properties lookup etc...
-        (binding (with-current-buffer
-                     (if (window-live-p w) (window-buffer w) (current-buffer))
-                   (key-binding key))))
+        (binding (key-binding (this-command-keys-vector) t)))
     (if (and (window-minibuffer-p w)
             (not (minibuffer-window-active-p w))) ; in echo area
        (isearch-yank-x-selection)
       (when (functionp binding)
        (call-interactively binding)))))
 
-
 (defun isearch-yank-internal (jumpform)
   "Pull the text from point to the point reached by JUMPFORM.
 JUMPFORM is a lambda expression that takes no arguments and returns a
@@ -1368,7 +1375,8 @@ might return the position of the end of the line."
   "Pull rest of line from buffer into search string."
   (interactive)
   (isearch-yank-internal
-   (lambda () (line-end-position (if (eolp) 2 1)))))
+   (lambda () (let ((inhibit-field-text-motion t))
+               (line-end-position (if (eolp) 2 1))))))
 
 (defun isearch-search-and-update ()
   ;; Do the search and update the display.
@@ -1817,8 +1825,6 @@ Isearch mode."
    ((eq   char ?|)       (isearch-fallback t nil t)))
 
   ;; Append the char to the search string, update the message and re-search.
-  (if (char-table-p translation-table-for-input)
-      (setq char (or (aref translation-table-for-input char) char)))
   (isearch-process-search-string
    (char-to-string char)
    (if (>= char ?\200)
@@ -2003,9 +2009,41 @@ Can be changed via `isearch-search-fun-function' for special needs."
      (t
       (if isearch-forward 'search-forward 'search-backward)))))
 
+(defun isearch-search-string (string bound noerror)
+  ;; Search for the first occurance of STRING or its translation.  If
+  ;; found, move point to the end of the occurance, update
+  ;; isearch-match-beg and isearch-match-end, and return point.
+  (let ((func (isearch-search-fun))
+       (len (length string))
+       pos1 pos2)
+    (setq pos1 (save-excursion (funcall func string bound noerror)))
+    (if (and (char-table-p translation-table-for-input)
+            (> (string-bytes string) len))
+       (let (translated match-data)
+         (dotimes (i len)
+           (let ((x (aref translation-table-for-input (aref string i))))
+             (when x
+               (or translated (setq translated (copy-sequence string)))
+               (aset translated i x))))
+         (when translated
+           (save-match-data
+             (save-excursion
+               (if (setq pos2 (funcall func translated bound noerror))
+                   (setq match-data (match-data t)))))
+           (when (and pos2
+                      (or (not pos1)
+                          (if isearch-forward (< pos2 pos1) (> pos2 pos1))))
+             (setq pos1 pos2)
+             (set-match-data match-data)))))
+    (if pos1
+       (goto-char pos1))
+    pos1))
+
 (defun isearch-search ()
   ;; Do the search with the current search string.
-  (isearch-message nil t)
+  (if isearch-message-function
+      (funcall isearch-message-function nil t)
+    (isearch-message nil t))
   (if (and (eq isearch-case-fold-search t) search-upper-case)
       (setq isearch-case-fold-search
            (isearch-no-upper-case-p isearch-string isearch-regexp)))
@@ -2018,9 +2056,7 @@ Can be changed via `isearch-search-fun-function' for special needs."
        (setq isearch-error nil)
        (while retry
          (setq isearch-success
-               (funcall
-                (isearch-search-fun)
-                isearch-string nil t))
+               (isearch-search-string isearch-string nil t))
          ;; Clear RETRY unless we matched some invisible text
          ;; and we aren't supposed to do that.
          (if (or (eq search-invisible t)
@@ -2222,7 +2258,18 @@ since they have special meaning in a regexp."
              (setq found t))
          (setq quote-flag nil)))
       (setq i (1+ i)))
-    (not found)))
+    (not (or found
+             ;; Even if there's no uppercase char, we want to detect the use
+             ;; of [:upper:] or [:lower:] char-class, which indicates
+             ;; clearly that the user cares about case distinction.
+             (and regexp-flag (string-match "\\[:\\(upp\\|low\\)er:]" string)
+                  (condition-case err
+                      (progn
+                        (string-match (substring string 0 (match-beginning 0))
+                                      "")
+                        nil)
+                    (invalid-regexp
+                     (equal "Unmatched [ or [^" (cadr err)))))))))
 
 ;; Portability functions to support various Emacs versions.
 
@@ -2297,6 +2344,7 @@ since they have special meaning in a regexp."
 (defvar isearch-lazy-highlight-window-end nil)
 (defvar isearch-lazy-highlight-case-fold-search nil)
 (defvar isearch-lazy-highlight-regexp nil)
+(defvar isearch-lazy-highlight-space-regexp nil)
 
 (defun lazy-highlight-cleanup (&optional force)
   "Stop lazy highlighting and remove extra highlighting from current buffer.
@@ -2350,7 +2398,8 @@ by other Emacs features."
             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-wrapped      nil
+           isearch-lazy-highlight-space-regexp search-whitespace-regexp)
       (unless (equal isearch-string "")
        (setq isearch-lazy-highlight-timer
              (run-with-idle-timer lazy-highlight-initial-delay nil
@@ -2361,9 +2410,9 @@ by other Emacs features."
 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 search-whitespace-regexp))
+       (search-spaces-regexp isearch-lazy-highlight-space-regexp))
     (condition-case nil
-       (funcall (isearch-search-fun)
+       (isearch-search-string
                 isearch-lazy-highlight-last-string
                 (if isearch-forward
                     (min (or isearch-lazy-highlight-end-limit (point-max))