]> code.delx.au - gnu-emacs/blobdiff - lisp/isearch.el
(help-menu-bar-map): Put the Help item in this map.
[gnu-emacs] / lisp / isearch.el
index 8542cd9beb813641a92a25363c81536f4bc0d2c8..ec7005ce9d88ec2856f86f9cf134d0ca86a70270 100644 (file)
@@ -1,10 +1,10 @@
-;; Incremental search minor mode.
-;; Copyright (C) 1992 Free Software Foundation, Inc.
+;;; isearch.el --- incremental search minor mode.
 
-;; LCD Archive Entry:
-;; isearch-mode|Daniel LaLiberte|liberte@cs.uiuc.edu
-;; |A minor mode replacement for isearch.el.
-;; |$Date: 92/09/14 16:26:02 $|$Revision: 1.4 $|~/modes/isearch-mode.el
+;; Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+
+;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
+
+;; |$Date: 1993/07/08 22:33:57 $|$Revision: 1.45 $
 
 ;; This file is not yet part of GNU Emacs, but it is based almost
 ;; entirely on isearch.el which is part of GNU Emacs.
@@ -24,6 +24,8 @@
 ;; file named COPYING.  Among other things, the copyright notice
 ;; and this notice must be preserved on all copies.
 
+;;; Commentary:
+
 ;;;====================================================================
 ;; Instructions
 
@@ -36,7 +38,7 @@
 ;; isearch-forward, etc, will then use isearch-mode instead of
 ;; isearch.
 
-;; (fset 'isearch 'isearch-mode)
+;; (defalias 'isearch 'isearch-mode)
 ;; (autoload 'isearch-mode "isearch-mode")
 
 ;; For programmed use of isearch-mode, e.g. calling (isearch-forward),
@@ -49,7 +51,7 @@
 ;; of isearch-forward, etc. found in this file instead of those in
 ;; loaddefs.el.  The simplest way to ensure this is to just load
 ;; isearch-mode explicitly in your .emacs instead of using the above
-;; fset and autoload.
+;; defalias and autoload.
 
 ;; (load "isearch-mode")
 
 ;; the last possible moment.
 
 ;; TODO
-;; - Integrate the emacs 19 generalized commmand history.
+;; - Integrate the emacs 19 generalized command history.
 ;; - Think about incorporating query-replace.
 ;; - Hooks and options for failed search.
 
-;;;====================================================================
-;;; Change History
+;;; Change Log:
+
+;;; Changes before those recorded in ChangeLog:
 
-;;; $Header: /import/kaplan/kaplan/liberte/Isearch/RCS/isearch-mode.el,v 1.4 92/09/14 16:26:02 liberte Exp Locker: liberte $
-;;; $Log:      isearch-mode.el,v $
 ;;; Revision 1.4  92/09/14  16:26:02  liberte
 ;;; Added prefix args to isearch-forward, etc. to switch between
 ;;;    string and regular expression searching.
 ;;; 3/18/92 Fixed invalid-regexp.
 ;;; 3/18/92 Fixed yanking in regexps.
 
+;;; Code:
 
 \f
 ;;;=========================================================================
 ;; Each of the tests below must work on any version of emacs.
 ;; (Perhaps provide and featurep could be used for this purpose.)
 
-(defconst isearch-frames-exist nil) ;; emacs 19
+(defconst isearch-gnu-emacs-events (fboundp 'set-frame-height)) ;; emacs 19
 (defconst isearch-pre-command-hook-exists (boundp 'pre-command-hook)) ;; lemacs
-(defconst isearch-events-exist nil)  ;; lemacs
-
+(defconst isearch-event-data-type nil)  ;; lemacs
 
-;;;=========================================================================
-;;; The following, defined in loaddefs.el, are still used with isearch-mode.
+(defconst search-exit-option t
+  "*Non-nil means random control characters terminate incremental search.")
 
-;(defvar search-last-string ""
-;  "Last string search for by a search command.
-;This does not include direct calls to the primitive search functions,
-;and does not include searches that are aborted.")
+(defvar search-slow-window-lines 1
+  "*Number of lines in slow search display windows.
+These are the short windows used during incremental search on slow terminals.
+Negative means put the slow search window at the top (normally it's at bottom)
+and the value is minus the number of lines.")
 
-;(defvar search-last-regexp ""
-;  "Last string searched for by a regexp search command.
-;This does not include direct calls to the primitive search functions,
-;and does not include searches that are aborted.")
-
-;(defconst search-exit-option t
-;  "Non-nil means random control characters terminate incremental search.")
-
-;(defvar search-slow-window-lines 1
-;  "*Number of lines in slow search display windows.")
-
-;(defconst search-slow-speed 1200
-;  "*Highest terminal speed at which to use \"slow\" style incremental search.
-;This is the style where a one-line window is created to show the line
-;that the search has reached.")
+(defvar search-slow-speed 1200
+  "*Highest terminal speed at which to use \"slow\" style incremental search.
+This is the style where a one-line window is created to show the line
+that the search has reached.")
 
 ;;;========================================================================
 ;;; Some additional options and constants.
 
-(defvar search-caps-disable-folding t
+(defvar search-upper-case 'not-yanks
   "*If non-nil, upper case chars disable case fold searching.
 That is, upper and lower case chars must match exactly.
 This applies no matter where the chars come from, but does not
-apply to chars prefixed with \\, for regexps.
-If this value is 'not-yanks, yanked text is always downcased.")
+apply to chars in regexps that are prefixed with `\\'.
+If this value is `not-yanks', yanked text is always downcased.")
 
 (defvar search-nonincremental-instead t
   "*If non-nil, do a nonincremental search instead if exiting immediately.
@@ -182,10 +173,11 @@ string, and RET terminates editing and does a nonincremental search.")
   "*If non-nil, regular expression to match a sequence of whitespace chars.
 You might want to use something like \"[ \\t\\r\\n]+\" instead.")
 
+;; I removed the * from the doc string because highlighting is not 
+;; currently a clean thing to do.  Once highlighting is made clean, 
+;; this feature can be re-enabled and advertised.
 (defvar search-highlight nil
-  "*Whether isearch and query-replace should highlight the text which 
-currently matches the search-string.")
-
+  "*Non-nil means incremental search highlights the current match.")
 
 (defvar isearch-mode-hook nil
   "Function(s) to call after starting up an incremental search.")
@@ -207,10 +199,11 @@ currently matches the search-string.")
   "*Maximum length of regexp search ring before oldest elements are thrown away.")
 
 (defvar search-ring-yank-pointer nil
-  "The tail of the search ring whose car is the last thing searched for.")
+  "Index in `search-ring' of last string reused.
+nil if none yet.")
 (defvar regexp-search-ring-yank-pointer nil
-  "The tail of the regular expression search ring whose car is the last
-thing searched for.")
+  "Index in `regexp-search-ring' of last string reused.
+nil if none yet.")
 
 (defvar search-ring-update nil
   "*Non-nil if advancing or retreating in the search ring should cause search.
@@ -224,18 +217,27 @@ Default value, nil, means edit the string instead.")
 
 (or isearch-mode-map
     (let* ((i 0)
-          (map (make-keymap))
-          (len (length map)))
-
+          (map (make-keymap)))
+      (or (vectorp (nth 1 map))
+         (error "The initialization of isearch-mode-map must be updated"))
+      ;; Give this map a vector 256 long, for dense binding
+      ;; of a larger range of ordinary characters.
+      (setcar (cdr map) (make-vector 256 nil))
+
+      ;; Make function keys, etc, exit the search.
+      (define-key map [t] 'isearch-other-control-char)
       ;; Control chars, by default, end isearch mode transparently.
+      ;; We need these explicit definitions because, in a dense keymap, 
+      ;; the binding for t does not affect characters.
+      ;; We use a dense keymap to save space.
       (while (< i ?\ )
        (define-key map (make-string 1 i) 'isearch-other-control-char)
        (setq i (1+ i)))
 
-      ;; Printing chars extend the selection by default.
-      ;; This assumes that all remaining chars are printable.
-      (while (< i len)
-       (define-key map (make-string 1 i) 'isearch-printing-char)
+      ;; Printing chars extend the search string by default.
+      (setq i ?\ )
+      (while (< i (length (nth 1 map)))
+       (define-key map (vector i) 'isearch-printing-char)
        (setq i (1+ i)))
 
       ;; Several non-printing chars change the searching behavior.
@@ -246,9 +248,6 @@ Default value, nil, means edit the string instead.")
     
       (define-key map "\C-q" 'isearch-quote-char)
 
-      ;;  (define-key map "\r" 'isearch-return-char)
-      ;; For version 19, RET (C-m) terminates search and LFD (C-j) matches eol.
-      ;; We could make this conditional.
       (define-key map "\r" 'isearch-exit)
       (define-key map "\C-j" 'isearch-printing-char)
       (define-key map "\t" 'isearch-printing-char)
@@ -257,41 +256,43 @@ Default value, nil, means edit the string instead.")
       (define-key map "\C-w" 'isearch-yank-word)
       (define-key map "\C-y" 'isearch-yank-line)
 
+      ;; Bind the ASCII-equivalent "function keys" explicitly
+      ;; if we bind their equivalents, 
+      ;; since otherwise the default binding would override.
+      ;; We bind [escape] below.
+      (define-key map [tab] 'isearch-printing-char)
+      (define-key map [delete] 'isearch-delete-char)
+      (define-key map [backspace] 'isearch-delete-char)
+      (define-key map [return] 'isearch-exit)
+      (define-key map [newline] 'isearch-printing-char)
+
       ;; 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)
 
-      ;; You can reenable global keys by binding them locally to nil.
-      ;; For the help char this doesnt work quite as expected because
-      ;; isearch-mode is not a major mode.  Also the echo area is not
-      ;; restored after the help command while isearch-mode is
-      ;; still active.  Furthermore, we should not assume that the
-      ;; help-command is on C-h.  But here is how it would be done:
-      ;; (define-key map "\C-h" nil)
-
-      ;; Instead bind C-h to special help command for isearch-mode.
-      (define-key map "\C-h" 'isearch-mode-help)
+;;; Turned off because I find I expect to get the global definition--rms.
+;;;      ;; Instead bind C-h to special help command for isearch-mode.
+;;;      (define-key map "\C-h" 'isearch-mode-help)
 
       ;; To handle local bindings with meta char prefix keys, define
       ;; another full keymap.  This must be done for any other prefix
       ;; keys as well, one full keymap per char of the prefix key.  It
       ;; would be simpler to disable the global keymap, and/or have a
       ;; default local key binding for any key not otherwise bound.
-      (define-key map (char-to-string meta-prefix-char) (make-keymap))
-      (setq i 0)
-      (while (< i len)
-       (define-key map (char-to-string (+ 128 i)) ;; Needs to be generalized.
-         'isearch-other-meta-char)
-       (setq i (1+ i)))
+      (let ((meta-map (make-sparse-keymap)))
+       (define-key map (char-to-string meta-prefix-char) meta-map)
+       (define-key map [escape] meta-map))
+      (define-key map (vector meta-prefix-char t) 'isearch-other-meta-char)
 
       (define-key map "\M-n" 'isearch-ring-advance)
       (define-key map "\M-p" 'isearch-ring-retreat)
+
       (define-key map "\M-\t" 'isearch-complete)
 
       ;; For emacs 19, switching frames should terminate isearch-mode
-      (if isearch-frames-exist
+      (if isearch-gnu-emacs-events
          (define-key map [switch-frame] 'isearch-switch-frame-handler))
       
       (setq isearch-mode-map map)
@@ -376,13 +377,18 @@ Default value, nil, means edit the string instead.")
 (defvar isearch-mode nil) ;; Name of the minor mode, if non-nil.
 (make-variable-buffer-local 'isearch-mode)
 
+(define-key global-map "\C-s" 'isearch-forward)
+(define-key esc-map "\C-s" 'isearch-forward-regexp)
+(define-key global-map "\C-r" 'isearch-backward)
+(define-key esc-map "\C-r" 'isearch-backward-regexp)
+
 ;;;===============================================================
 ;;; Entry points to isearch-mode.
 ;;; These four functions should replace those in loaddefs.el
-;;; An alternative is to fset isearch-forward etc to isearch-mode,
+;;; An alternative is to defalias isearch-forward etc to isearch-mode,
 ;;; and look at this-command to set the options accordingly.
 
-(defun isearch-forward (&optional regexp-p)
+(defun isearch-forward (&optional regexp-p no-recursive-edit)
   "\
 Do incremental search forward.
 With a prefix argument, do an incremental regular expression search instead.
@@ -400,7 +406,6 @@ Type \\[isearch-yank-word] to yank word from buffer onto end of search\
 Type \\[isearch-yank-line] to yank rest of line onto end of search string\
  and search for it.
 Type \\[isearch-quote-char] to quote control character to search for it.
-Type \\[isearch-whitespace-chars] to match all whitespace chars in regexp.
 \\[isearch-abort] while searching or when search has failed cancels input\
  back to what has
  been found successfully.
@@ -421,34 +426,34 @@ Other control and meta characters terminate the search
 If this function is called non-interactively, it does not return to
 the calling function until the search is done."
 
-  (interactive "P")
-  (isearch-mode t (not (null regexp-p)) nil (not (interactive-p))))
+  (interactive "P\np")
+  (isearch-mode t (not (null regexp-p)) nil (not no-recursive-edit)))
 
-(defun isearch-forward-regexp (&optional regexp-p)
+(defun isearch-forward-regexp (&optional not-regexp no-recursive-edit)
   "\
 Do incremental search forward for regular expression.
 With a prefix argument, do a regular string search instead.
 Like ordinary incremental search except that your input
 is treated as a regexp.  See \\[isearch-forward] for more info."
-  (interactive)
-  (isearch-mode t (null regexp-p) nil (not (interactive-p))))
+  (interactive "P\np")
+  (isearch-mode t (null not-regexp) nil (not no-recursive-edit)))
 
-(defun isearch-backward (&optional regexp-p)
+(defun isearch-backward (&optional regexp-p no-recursive-edit)
   "\
 Do incremental search backward.
 With a prefix argument, do a regular expression search instead.
 See \\[isearch-forward] for more information."
-  (interactive)
-  (isearch-mode nil (not (null regexp-p)) nil (not (interactive-p))))
+  (interactive "P\np")
+  (isearch-mode nil (not (null regexp-p)) nil (not no-recursive-edit)))
 
-(defun isearch-backward-regexp (&optional regexp-p)
+(defun isearch-backward-regexp (&optional not-regexp no-recursive-edit)
   "\
 Do incremental search backward for regular expression.
 With a prefix argument, do a regular string search instead.
 Like ordinary incremental search except that your input
 is treated as a regexp.  See \\[isearch-forward] for more info."
-  (interactive)
-  (isearch-mode nil (null regexp-p) nil (not (interactive-p))))
+  (interactive "P\np")
+  (isearch-mode nil (null not-regexp) nil (not no-recursive-edit)))
 
 
 (defun isearch-mode-help ()
@@ -485,20 +490,31 @@ is treated as a regexp.  See \\[isearch-forward] for more info."
        isearch-adjusted nil
        isearch-yank-flag nil
        isearch-invalid-regexp nil
-       isearch-slow-terminal-mode (and (<= baud-rate search-slow-speed)
+       ;; Use (baud-rate) for now, for sake of other versions.
+       isearch-slow-terminal-mode (and (<= (baud-rate) search-slow-speed)
                                        (> (window-height)
                                           (* 4 search-slow-window-lines)))
        isearch-other-end nil
        isearch-small-window nil
 
        isearch-opoint (point)
-       isearch-window-configuration (current-window-configuration)
-       isearch-old-local-map (current-local-map))
-  (if isearch-pre-command-hook-exists
-      (add-hook 'pre-command-hook 'isearch-pre-command-hook))
+       isearch-old-local-map (current-local-map)
+       search-ring-yank-pointer nil
+       regexp-search-ring-yank-pointer nil)
+  (if isearch-slow-terminal-mode
+      (setq isearch-window-configuration (current-window-configuration)))
+
+;; This was for Lucid Emacs.  But now that we have pre-command-hook,
+;; it causes trouble.
+;;  (if isearch-pre-command-hook-exists
+;;      (add-hook 'pre-command-hook 'isearch-pre-command-hook))
   (setq        isearch-mode " Isearch")  ;; forward? regexp?
   (set-buffer-modified-p (buffer-modified-p)) ; update modeline
 
+  ;; It is ugly to show region highlighting while the search
+  ;; is going on.  And we don't want the mark active at the end either.
+  (setq deactivate-mark t)      
+
   (isearch-push-state)
 
   (use-local-map isearch-mode-map)
@@ -508,7 +524,9 @@ is treated as a regexp.  See \\[isearch-forward] for more info."
   ;; isearch-mode can be made modal (in the sense of not returning to 
   ;; the calling function until searching is completed) by entering 
   ;; a recursive-edit and exiting it when done isearching.
-  (if recursive-edit (recursive-edit))
+  (if recursive-edit
+      (let ((isearch-recursive-edit t))
+       (recursive-edit)))
   )
 
 
@@ -517,10 +535,10 @@ is treated as a regexp.  See \\[isearch-forward] for more info."
 
 (defun isearch-update ()
   ;; Called after each command to update the display.  
-  (if (if isearch-events-exist
+  (if (if isearch-event-data-type
          (null unread-command-event)
-       (if isearch-frames-exist
-           (null unread-command-char)
+       (if isearch-gnu-emacs-events
+           (null unread-command-events)
          (< unread-command-char 0)))
       (progn
        (if (not (input-pending-p))
@@ -555,19 +573,25 @@ is treated as a regexp.  See \\[isearch-forward] for more info."
   )
 
 
-(defun isearch-done ()
+(defun isearch-done (&optional nopush)
   ;; Called by all commands that terminate isearch-mode.
+  ;; If NOPUSH is non-nil, we don't push the string on the search ring.
   (use-local-map isearch-old-local-map)
   ;; (setq pre-command-hook isearch-old-pre-command-hook) ; for lemacs
   (isearch-dehighlight t)
   (let ((found-start (window-start (selected-window)))
        (found-point (point)))
-    (set-window-configuration isearch-window-configuration)
+    (if isearch-window-configuration
+       (set-window-configuration isearch-window-configuration))
 
     ;; If there was movement, mark the starting position.
     ;; Maybe should test difference between and set mark iff > threshold.
     (if (/= (point) isearch-opoint)
-       (push-mark isearch-opoint)
+       (progn
+         (push-mark isearch-opoint t)
+         (deactivate-mark)
+         (or executing-macro (> (minibuffer-depth) 0)
+             (message "Mark saved where search started")))
       ;; (message "") why is this needed?
       )
     (if isearch-small-window
@@ -578,26 +602,21 @@ is treated as a regexp.  See \\[isearch-forward] for more info."
   (setq isearch-mode nil)
   (set-buffer-modified-p (buffer-modified-p))  ;; update modeline
 
-  (if (> (length isearch-string) 0)
+  (if (and (> (length isearch-string) 0) (not nopush))
       ;; Update the ring data.
       (if isearch-regexp 
-         (if (not (setq regexp-search-ring-yank-pointer
-                        ;; really need equal test instead of eq.
-                        (isearch-member-equal 
-                         isearch-string regexp-search-ring)))
+         (if (or (null regexp-search-ring)
+                 (not (string= isearch-string (car regexp-search-ring))))
              (progn
                (setq regexp-search-ring
-                     (cons isearch-string regexp-search-ring)
-                     regexp-search-ring-yank-pointer regexp-search-ring)
+                     (cons isearch-string regexp-search-ring))
                (if (> (length regexp-search-ring) regexp-search-ring-max)
                    (setcdr (nthcdr (1- search-ring-max) regexp-search-ring)
                            nil))))
-       (if (not (setq search-ring-yank-pointer
-                      ;; really need equal test instead of eq.
-                      (isearch-member-equal isearch-string search-ring)))
+       (if (or (null search-ring)
+               (not (string= isearch-string (car search-ring))))
            (progn
-             (setq search-ring (cons isearch-string search-ring)
-                   search-ring-yank-pointer search-ring)
+             (setq search-ring (cons isearch-string search-ring))
              (if (> (length search-ring) search-ring-max)
                  (setcdr (nthcdr (1- search-ring-max) search-ring) nil))))))
 
@@ -606,7 +625,7 @@ is treated as a regexp.  See \\[isearch-forward] for more info."
 
 ;;;=======================================================
 ;;; Switching buffers should first terminate isearch-mode.
-;;; This is done quite differently for each varient of emacs.
+;;; This is done quite differently for each variant of emacs.
 ;;; For lemacs, see Exiting in lemacs below
 
 ;; For Emacs 19, the frame switch event is handled.
@@ -614,7 +633,7 @@ is treated as a regexp.  See \\[isearch-forward] for more info."
   (interactive) ;; Is this necessary?
   ;; First terminate isearch-mode.
   (isearch-done)
-  (select-frame (car (cdr (isearch-last-command-char)))))
+  (handle-switch-frame (car (cdr (isearch-last-command-char)))))
 
 ;;;========================================================
 
@@ -644,7 +663,7 @@ The following additional command keys are active while editing.
 \\[isearch-forward-exit-minibuffer] to resume isearching forward.
 \\[isearch-backward-exit-minibuffer] to resume isearching backward.
 \\[isearch-ring-advance-edit] to replace the search string with the next item in the search ring.
-\\[isearch-ring-retreat-edit] to replace the search string with the previou item in the search ring.
+\\[isearch-ring-retreat-edit] to replace the search string with the previous item in the search ring.
 \\[isearch-complete-edit] to complete the search string using the search ring.
 
 If first char entered is \\[isearch-yank-word], then do word search instead."
@@ -653,11 +672,10 @@ If first char entered is \\[isearch-yank-word], then do word search instead."
   ;; Mainly, isearch-mode must be terminated while editing and then restarted.
   ;; If there were a way to catch any change of buffer from the minibuffer,
   ;; this could be simplified greatly.
-  ;; Editing doesnt back up the search point.  Should it?
+  ;; Editing doesn't back up the search point.  Should it?
   (interactive)
   (condition-case err
-      (let ((minibuffer-local-map minibuffer-local-isearch-map)
-           isearch-nonincremental      ; should search nonincrementally?
+      (let ((isearch-nonincremental isearch-nonincremental)
 
            ;; Locally bind all isearch global variables to protect them
            ;; from recursive isearching.
@@ -690,15 +708,16 @@ If first char entered is \\[isearch-yank-word], then do word search instead."
        ;; This is so that the user can do anything without failure, 
        ;; like switch buffers and start another isearch, and return.
        (condition-case err
-           (isearch-done)
+           (isearch-done t)
          (exit nil))                   ; was recursive editing
 
        (isearch-message) ;; for read-char
        (unwind-protect
            (let* (;; Why does following read-char echo?  
                   ;;(echo-keystrokes 0) ;; not needed with above message
-                  (cursor-in-echo-area t)
-                  (e (if isearch-events-exist (allocate-event) (read-char)))
+                  (e (let ((cursor-in-echo-area t))
+                       (if isearch-event-data-type
+                           (allocate-event) (read-char))))
                   ;; Binding minibuffer-history-symbol to nil is a work-around
                   ;; for some incompatibility with gmhist.
                   (minibuffer-history-symbol))
@@ -713,14 +732,19 @@ If first char entered is \\[isearch-yank-word], then do word search instead."
                      (lookup-key
                       isearch-mode-map
                       (char-to-string
-                       (if isearch-events-exist
+                       (if isearch-event-data-type
                            (or (event-to-character (next-command-event e)) 0)
                          e))))
                  (setq isearch-word t  ;; so message-prefix is right
                        isearch-new-word t)
                (isearch-unread e))
-             (setq isearch-new-string (read-string (isearch-message-prefix)
-                                                   isearch-string)
+             (setq cursor-in-echo-area nil)
+             (setq isearch-new-string
+                   (let (junk-ring)
+                     (read-from-minibuffer (isearch-message-prefix)
+                                           isearch-string
+                                           minibuffer-local-isearch-map nil
+                                           'junk-ring))
                    isearch-new-message (mapconcat 'text-char-description
                                                   isearch-new-string "")))
          ;; Always resume isearching by restarting it.
@@ -738,12 +762,12 @@ If first char entered is \\[isearch-yank-word], then do word search instead."
 
        ;; Empty isearch-string means use default.
        (if (= 0 (length isearch-string))
-           (setq isearch-string (if isearch-regexp search-last-regexp
-                                  search-last-string))
-         ;; Set last search string now so it is set even if we fail.
-         (if search-last-regexp
-             (setq search-last-regexp isearch-string)
-           (setq search-last-string isearch-string)))
+           (setq isearch-string (car (if isearch-regexp regexp-search-ring
+                                       search-ring)))
+         ;; This used to set the last search string,
+         ;; but I think it is not right to do that here.
+         ;; Only the string actually used should be saved.
+         )
 
        ;; Reinvoke the pending search.
        (isearch-push-state)
@@ -779,14 +803,14 @@ If first char entered is \\[isearch-yank-word], then do word search instead."
 Otherwise, revert to previous successful search and continue searching.
 Use `isearch-exit' to quit without signalling."
   (interactive)
-;;  (ding)  signal instead below, if quiting
+;;  (ding)  signal instead below, if quitting
   (discard-input)
   (if isearch-success
       ;; If search is successful, move back to starting point
       ;; and really do quit.
       (progn (goto-char isearch-opoint)
-            (isearch-done)   ; exit isearch
-            (signal 'quit '(isearch)))  ; and pass on quit signal
+            (isearch-done t)   ; exit isearch
+            (signal 'quit nil))  ; and pass on quit signal
     ;; If search is failing, rub out until it is once more successful.
     (while (not isearch-success) (isearch-pop-state))
     (isearch-update)))
@@ -800,12 +824,8 @@ Use `isearch-exit' to quit without signalling."
          ;; If search string is empty, use last one.
          (setq isearch-string
                (or (if isearch-regexp
-                       (if regexp-search-ring-yank-pointer
-                           (car regexp-search-ring-yank-pointer)
-                         (car regexp-search-ring))
-                     (if search-ring-yank-pointer
-                         (car search-ring-yank-pointer)
-                       (car search-ring)))
+                       (car regexp-search-ring)
+                     (car search-ring))
                    "")
                isearch-message
                (mapconcat 'isearch-text-char-description
@@ -875,7 +895,7 @@ If no previous match was done, just beep."
                     (point))))))
     ;; Downcase the string if not supposed to case-fold yanked strings.
     (if (and isearch-case-fold-search
-            (eq 'not-yanks search-caps-disable-folding))
+            (eq 'not-yanks search-upper-case))
        (setq string (downcase string)))
     (if isearch-regexp (setq string (regexp-quote string)))
     (setq isearch-string (concat isearch-string string)
@@ -973,50 +993,43 @@ If no previous match was done, just beep."
   (isearch-process-search-char (isearch-last-command-char)))
 
 
-(defun isearch-other-control-char ()
-  "Any other control char => unread it and exit the search normally.
-But only if `search-exit-option' is non-nil, the default.
-If it is the symbol `edit', the search string is edited in the minibuffer
-and the control char is unread so that it is applied to the editing."
-  (interactive)
-  (cond
-   ((eq search-exit-option 'edit)
-    (isearch-unread (isearch-last-command-char))
-    (isearch-edit-string))
-   (search-exit-option  ;; any other non-nil value
-    (isearch-unread (isearch-last-command-char))
-    (isearch-done))
-   (t ;; search-exit-option is nil
-    (isearch-process-search-char (isearch-last-command-char)))
-   ))
-
+(defalias 'isearch-other-control-char 'isearch-other-meta-char)
 
 (defun isearch-other-meta-char ()
-  "Any other meta char => exit the search normally and reexecute the whole key.
-But only if `search-exit-option' is non-nil."
-  ;; This will probably work in place of isearch-other-control-char too,
-  ;; but here we use unwind-protect and command-execute since it is
-  ;; a multi-char key we would want to unread.
+  "Exit the search normally and reread this key sequence.
+But only if `search-exit-option' is non-nil, the default.
+If it is the symbol `edit', the search string is edited in the minibuffer
+and the meta character is unread so that it applies to editing the string."
   (interactive)
-  (cond
-   (search-exit-option
-    (unwind-protect
-       ;; Exit recursive edit and restore the outside keymap.
-       (isearch-done)
-      ;; Reexecute the key with the outside keymap.
-      ;; Note: this doesnt work unless the entered key is the same 
-      ;; as some outside key since command-execute only takes whole keys.
-      ;; So three character keys typically will not work!
-      ;; Also, executing the command here may not work if isearch was
-      ;; invoked non-interactively, since other input may be expected.
-      ;; We also can't do isearch-edit-string as in -other-control-char.
-      ;; because we need to set unread-command-key, if that existed.
-      ;; So a new unread-command-key would solve all these problems.
-      (command-execute (this-command-keys))))
-   (t  ;; otherwise nil
-    (isearch-process-search-string (this-command-keys) (this-command-keys))
-    )))
-
+  (cond ((eq search-exit-option 'edit)
+        (let ((key (this-command-keys)))
+          (apply 'isearch-unread (listify-key-sequence key)))
+        (isearch-edit-string))
+       (search-exit-option
+        (let ((key (this-command-keys))
+              (index 0)
+              window)
+          (apply 'isearch-unread (listify-key-sequence key))
+          ;; Properly handle scroll-bar and mode-line clicks
+          ;; for which a dummy prefix event was generated as (aref key 0).
+          (and (> (length key) 1)
+               (symbolp (aref key 0))
+               (listp (aref key 1))
+               (consp (posn-point (event-start (aref key 1))))
+               (setq index 1))
+          ;; If we got a mouse click, maybe it was read with the buffer
+          ;; it was clicked on.  If so, that buffer, not the current one,
+          ;; is in isearch mode.  So end the search in that buffer.
+          (if (and (listp (aref key index))
+                   (setq window (posn-window (event-start (aref key index))))
+                   (windowp window))
+              (save-excursion
+                (set-buffer (window-buffer window))
+                (isearch-done))
+            (isearch-done))))
+       (t;; otherwise nil
+        (isearch-process-search-string (this-command-keys)
+                                       (this-command-keys)))))
 
 (defun isearch-quote-char ()
   "Quote special characters for incremental search."
@@ -1030,20 +1043,20 @@ Obsolete."
   (isearch-process-search-char ?\n))
 
 (defun isearch-printing-char ()
-  "Any other printing character => add it to the search string and search."
+  "Add this ordinary printing character to the search string and search."
   (interactive)
   (isearch-process-search-char (isearch-last-command-char)))
 
 (defun isearch-whitespace-chars ()
   "Match all whitespace chars, if in regexp mode.
-If not in regexp mode, activate word search."
+If you want to search for just a space, type C-q SPC."
   (interactive)
   (if isearch-regexp 
       (if search-whitespace-regexp
          (isearch-process-search-string search-whitespace-regexp " ")
        (isearch-printing-char))
     (progn
-      ;; This way of doing word search doesnt correctly extend current search.
+      ;; This way of doing word search doesn't correctly extend current search.
       ;;      (setq isearch-word t)
       ;;      (setq isearch-adjusted t)
       ;;      (goto-char isearch-barrier)
@@ -1076,10 +1089,10 @@ If not in regexp mode, activate word search."
        ()
       (set yank-pointer-name
           (setq yank-pointer
-                (nthcdr (% (+ (- length (length yank-pointer))
-                              (if advance (1- length) 1))
-                           length) ring)))
-      (setq isearch-string (car yank-pointer)
+                (% (+ (or yank-pointer 0)
+                      (if advance (1- length) 1))
+                   length)))
+      (setq isearch-string (nth yank-pointer ring)
            isearch-message (mapconcat 'isearch-text-char-description
                                       isearch-string "")))))
 
@@ -1107,20 +1120,48 @@ If not in regexp mode, activate word search."
   (interactive)
   (isearch-ring-adjust nil))
 
-(defun isearch-ring-adjust-edit (advance)
-  "Use the next or previous search string in the ring while in minibuffer."
-  (isearch-ring-adjust1 advance)
-  (erase-buffer)
-  (insert isearch-string))
+(defun isearch-ring-advance-edit (n)
+  "Insert the next element of the search history into the minibuffer."
+  (interactive "p")
+  (let* ((yank-pointer-name (if isearch-regexp
+                               'regexp-search-ring-yank-pointer
+                             'search-ring-yank-pointer))
+        (yank-pointer (eval yank-pointer-name))
+        (ring (if isearch-regexp regexp-search-ring search-ring))
+        (length (length ring)))
+    (if (zerop length)
+       ()
+      (set yank-pointer-name
+          (setq yank-pointer
+                (% (+ (or yank-pointer 0)
+                      ;; Add LENGTH here to ensure a positive result.
+                      length
+                      (% (- n) length))
+                   length)))
 
-(defun isearch-ring-advance-edit ()
-  (interactive)
-  (isearch-ring-adjust-edit 'advance))
+      (erase-buffer)
+      (insert (nth yank-pointer ring))
+      (goto-char (point-max)))))
 
-(defun isearch-ring-retreat-edit ()
-  "Retreat to the previous search string in the ring while in the minibuffer."
-  (interactive)
-  (isearch-ring-adjust-edit nil))
+(defun isearch-ring-retreat-edit (n)
+  "Inserts the previous element of the search history into the minibuffer."
+  (interactive "p")
+  (isearch-ring-advance-edit (- n)))
+
+;;(defun isearch-ring-adjust-edit (advance)
+;;  "Use the next or previous search string in the ring while in minibuffer."
+;;  (isearch-ring-adjust1 advance)
+;;  (erase-buffer)
+;;  (insert isearch-string))
+
+;;(defun isearch-ring-advance-edit ()
+;;  (interactive)
+;;  (isearch-ring-adjust-edit 'advance))
+
+;;(defun isearch-ring-retreat-edit ()
+;;  "Retreat to the previous search string in the ring while in the minibuffer."
+;;  (interactive)
+;;  (isearch-ring-adjust-edit nil))
 
 
 (defun isearch-complete1 ()
@@ -1247,8 +1288,9 @@ If there is no completion possible, say so and continue searching."
 (defun isearch-search ()
   ;; Do the search with the current search string.
   (isearch-message nil t)
-  (if search-caps-disable-folding
-      (setq isearch-case-fold-search (isearch-no-upper-case-p isearch-string)))
+  (if (and isearch-case-fold-search search-upper-case)
+      (setq isearch-case-fold-search
+           (isearch-no-upper-case-p isearch-string isearch-regexp)))
   (condition-case lossage
       (let ((inhibit-quit nil)
            (case-fold-search isearch-case-fold-search))
@@ -1276,7 +1318,10 @@ If there is no completion possible, say so and continue searching."
      (if (string-match
          "\\`Premature \\|\\`Unmatched \\|\\`Invalid "
          isearch-invalid-regexp)
-        (setq isearch-invalid-regexp "incomplete input"))))
+        (setq isearch-invalid-regexp "incomplete input")))
+    (error
+     ;; stack overflow in regexp search.
+     (setq isearch-invalid-regexp (car (cdr lossage)))))
 
   (if isearch-success
       nil
@@ -1290,196 +1335,72 @@ If there is no completion possible, say so and continue searching."
 ;;;========================================================
 ;;; Highlighting
 
-(defun isearch-highlight (begin end))
-(defun isearch-dehighlight (totally))
+(defvar isearch-overlay nil)
 
-;; lemacs uses faces
-'(progn
-(defvar isearch-extent nil)
-
-(or (find-face 'isearch)       ;; this face is initialized by x-faces.el
-    (make-face 'isearch))      ;; since isearch is preloaded
-
-(defun isearch-lemacs-highlight (begin end)
-  (if (null isearch-highlight)
+(defun isearch-highlight (beg end)
+  (if (null search-highlight)
       nil
-    (if (and (extentp isearch-extent)
-            (eq (extent-buffer isearch-extent) (current-buffer)))
-       (set-extent-endpoints isearch-extent begin end)
-      (if (and (extentp isearch-extent)
-              (bufferp (extent-buffer isearch-extent))
-              (buffer-name (extent-buffer isearch-extent)))
-         (delete-extent isearch-extent))
-      (setq isearch-extent (make-extent begin end (current-buffer))))
-    (set-extent-face isearch-extent 'isearch)))
-
-(defun isearch-lemacs-dehighlight (totally)
-  (if (and isearch-highlight isearch-extent)
-      (if totally
-         (let ((inhibit-quit t))
-           (if (and (extentp isearch-extent)
-                    (bufferp (extent-buffer isearch-extent))
-                    (buffer-name (extent-buffer isearch-extent)))
-               (delete-extent isearch-extent))
-           (setq isearch-extent nil))
-       (if (and (extentp isearch-extent)
-                (bufferp (extent-buffer isearch-extent))
-                (buffer-name (extent-buffer isearch-extent)))
-           (set-extent-face isearch-extent 'default)
-         (isearch-dehighlight t)))))
-
-(fset 'isearch-highlight (symbol-function 'isearch-lemacs-highlight))
-(fset 'isearch-dehighlight (symbol-function 'isearch-lemacs-dehighlight))
-)
+    (or isearch-overlay (setq isearch-overlay (make-overlay beg end)))
+    (move-overlay isearch-overlay beg end (current-buffer))
+    (overlay-put isearch-overlay 'face
+                (if (internal-find-face 'isearch nil)
+                    'isearch 'region))))
+
+(defun isearch-dehighlight (totally)
+  (if isearch-overlay
+      (delete-overlay isearch-overlay)))
 
 ;;;===========================================================
 ;;; General utilities
 
-;; (fset 'isearch-member-equal (symbol-function 'member)) ; for emacs 19
 
-(defun isearch-member-equal (item list)
-  "Return non-nil if ITEM is `equal' to some item in LIST.
-Actually return the list whose car is that item."
-  (while (and list (not (equal item (car list))))
-    (setq list (cdr list)))
-  list)
-
-
-(defun isearch-no-upper-case-p (string)
-  "Return t if there are no upper case chars in string.
-But upper case chars preceeded by \\ (but not \\\\) do not count since they
-have special meaning in a regexp."
+(defun isearch-no-upper-case-p (string regexp-flag)
+  "Return t if there are no upper case chars in STRING.
+If REGEXP-FLAG is non-nil, disregard letters preceeded by `\\' (but not `\\\\')
+since they have special meaning in a regexp."
   (let ((case-fold-search nil))
-    (not (string-match "\\(^\\|\\\\\\\\\\|[^\\]\\)[A-Z]" string))))
+    (not (string-match (if regexp-flag "\\(^\\|\\\\\\\\\\|[^\\]\\)[A-Z]"
+                        "[A-Z]")
+                      string))))
 
 
 ;;;=================================================
-;;; Special functions for lemacs events.
+;; Portability functions to support various Emacs versions.
 
 ;; To quiet the byte-compiler.
 (defvar unread-command-event)
+(defvar unread-command-events)
 (defvar last-command-event)
 
 (defun isearch-char-to-string (c)
   (if (integerp c)
       (make-string 1 c)
-   (make-string 1 (event-to-character c))))
+    (if (and (symbolp c) (get c 'ascii-character))
+       (make-string 1 (get c 'ascii-character))
+      (make-string 1 (event-to-character c)))))
 
 (defun isearch-text-char-description (c)
   (isearch-char-to-string c))
 
-(defun isearch-unread (char-or-event)
-  ;; General function to unread a character or event.
-  (if isearch-events-exist
-      (setq unread-command-event char-or-event)
-    (setq unread-command-char char-or-event)))
+(defun isearch-unread (&rest char-or-events)
+  ;; General function to unread characters or events.
+  (if isearch-gnu-emacs-events
+      (setq unread-command-events
+           (append char-or-events unread-command-events))
+    (let ((char (if (cdr char-or-events)
+                   (progn
+                     (while (cdr char-or-events)
+                       (setq char-or-events (cdr char-or-events)))
+                     (+ 128 (car char-or-events)))
+                 (car char-or-events))))
+      (if isearch-event-data-type
+         (setq unread-command-event char)
+       (setq unread-command-char char)))))
 
 (defun isearch-last-command-char ()
   ;; General function to return the last command character.
-  (if isearch-events-exist
+  (if isearch-event-data-type
       last-command-event
     last-command-char))
 
-
-
-\f
-;;;========================================================
-;;; Exiting in lemacs
-
-;; This is a large amount of code to support automatic termination of
-;; isearch-mode when a command (however it is invoked) is not an
-;; isearch command, or the buffer is switched out from under
-;; isearch-mode.   Only later versions of lemacs have the pre-command-hook.
-
-;;(if isearch-pre-command-hook-exists
-;;(progn
-
-;;;; This list must be modified whenever the available commands are modified.
-;;(mapcar (function (lambda (command)
-;;                 (put command 'isearch-command t)))
-;;     '(isearch-printing-char
-;;       isearch-return-char
-;;       isearch-repeat-forward
-;;       isearch-repeat-backward
-;;       isearch-delete-char
-;;       isearch-abort 
-;;       isearch-quote-char
-;;       isearch-exit  
-;;       isearch-printing-char
-;;       isearch-printing-char
-;;       isearch-yank-word     
-;;       isearch-yank-line     
-;;       isearch-*-char        
-;;       isearch-*-char        
-;;       isearch-|-char        
-;;       isearch-toggle-regexp
-;;       isearch-edit-string
-;;       isearch-mode-help     
-;;       isearch-ring-advance
-;;       isearch-ring-retreat
-;;       isearch-ring-advance-edit
-;;       isearch-ring-retreat-edit
-;;       isearch-whitespace-chars
-;;       isearch-complete      
-;;       isearch-complete-edit
-;;       isearch-edit-string
-;;       isearch-toggle-regexp
-;;       ;; The following may not be needed since isearch-mode is off already.
-;;       isearch-forward-exit-minibuffer
-;;       isearch-reverse-exit-minibuffer
-;;       isearch-nonincremental-exit-minibuffer))
-
-;;(defun isearch-pre-command-hook ()
-;;  ;;
-;;  ;; For use as the value of `pre-command-hook' when isearch-mode is active.
-;;  ;; If the command about to be executed is not one of the isearch commands,
-;;  ;; then isearch-mode is turned off before that command is executed.
-;;  ;;
-;;  ;; If the command about to be executed is self-insert-command, or is a
-;;  ;; keyboard macro of a single key sequence which is bound to self-insert-
-;;  ;; command, then we add those chars to the search ring instead of inserting
-;;  ;; them in the buffer.  In this way, the set of self-searching characters
-;;  ;; need not be exhaustively enumerated, but is derived from other maps.
-;;  ;;
-;;  (isearch-maybe-frob-keyboard-macros)
-;;  (if (and (symbolp this-command)
-;;        (get this-command 'isearch-command))
-;;      nil
-;;    (isearch-done)))
-
-;;(defun isearch-maybe-frob-keyboard-macros ()
-;;  ;;
-;;  ;; If the command about to be executed is `self-insert-command' then change
-;;  ;; the command to `isearch-printing-char' instead, meaning add the last-
-;;  ;; typed character to the search string.
-;;  ;;
-;;  ;; If `this-command' is a string or a vector (that is, a keyboard macro)
-;;  ;; and it contains only one command, which is bound to self-insert-command,
-;;  ;; then do the same thing as for self-inserting commands: arrange for that
-;;  ;; character to be added to the search string.  If we didn't do this, then
-;;  ;; typing a compose sequence (a la x-compose.el) would terminate the search
-;;  ;; and insert the character, instead of searching for that character.
-;;  ;;
-;;  (cond ((eq this-command 'self-insert-command)
-;;      (setq this-command 'isearch-printing-char))
-;;     ((and (stringp this-command)
-;;           (eq (key-binding this-command) 'self-insert-command))
-;;      (setq last-command-char (aref this-command 0)
-;;            last-command-event (character-to-event last-command-char)
-;;            this-command 'isearch-printing-char))
-;;     ((and (vectorp this-command)
-;;           (eq (key-binding this-command) 'self-insert-command))
-;;      (let* ((desc (aref this-command 0))
-;;             (code (cond ((integerp desc) desc)
-;;                         ((symbolp desc) (get desc character-set-property))
-;;                         ((consp desc)
-;;                          (and (null (cdr desc))
-;;                               (get (car desc) character-set-property)))
-;;                         (t nil))))
-;;        (if code
-;;            (setq last-command-char code
-;;                  last-command-event (character-to-event last-command-char)
-;;                  this-command 'isearch-printing-char))))
-;;     ))
-
-;;))
+;;; isearch.el ends here