]> 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 0e93b054ef07d66df33ef9c4f65a22566efb26b6..ec7005ce9d88ec2856f86f9cf134d0ca86a70270 100644 (file)
@@ -1,11 +1,13 @@
-;; isearch-mode.el --- incremental search minor mode.
+;;; isearch.el --- incremental search minor mode.
 
-;; Copyright (C) 1992 Free Software Foundation, Inc.
+;; Copyright (C) 1992, 1993 Free Software Foundation, Inc.
 
 ;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
-;; Version: 1.2
 
-;; This file is part of GNU Emacs.
+;; |$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.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY.  No author or distributor
 ;; 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),
+;; isearch-mode behaves modally and does not return until the search
+;; is completed.  It uses a recursive-edit to behave this way.  Note:
+;; gnus does it wrong: (call-interactively 'isearch-forward).
+
+;; If any package you use invokes isearching non-interactively to get
+;; the modal behavior described above, you must use the redefinitions
+;; 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
+;; defalias and autoload.
+
+;; (load "isearch-mode")
+
 ;; The key bindings active within isearch-mode are defined below in
-;; `isearch-mode-map' and `isearch-mode-meta-map' which are given
-;; bindings close to the default characters of isearch.el for
-;; version 19.  With `isearch-mode', however, you can bind
-;; multi-character keys and it should be easier to add new commands.
-
-;; Note to epoch and emacs version 19 users: isearch-mode should
-;; work even if you switch windows with the mouse.  However, if
-;; you isearch in a buffer that is also displayed in another window,
-;; when you switch to that other window you will still be in
-;; isearch mode but not necessarily in the right state for it to work.
-;; So ... don't do it unless you are in an experimental mood.
-;; You can also experiment with the window-local-variable routines
-;; contained in this package but not yet used.
-;; Also, I am not sure what happens when you return to an isearching
-;; buffer; ideally, the echo area should redisplay the searching status.
-;; A select-window-hook might be useful.
+;; `isearch-mode-map' which is given bindings close to the default
+;; characters of the original isearch.el.  With `isearch-mode',
+;; however, you can bind multi-character keys and it should be easier
+;; to add new commands.  One bug though: keys with meta-prefix cannot
+;; be longer than two chars.  Also see minibuffer-local-isearch-map
+;; for bindings active during `isearch-edit-string'.
+
+;; Note to emacs version 19 users: isearch-mode should work even if
+;; you switch windows with the mouse, in which case isearch-mode is
+;; terminated automatically before the switch.  This is true of lemacs
+;; too, with a few more cleanups I've neglected in this release. 
+;; No one has supplied patches for epoch yet.
+
+;; The search ring and completion commands automatically put you in
+;; the minibuffer to edit the string.  This gives you a chance to
+;; modify the search string before executing the search.  There are
+;; three commands to terminate the editing: C-s and C-r exit the
+;; minibuffer and search forward and reverse respectively, while C-m
+;; exits and does a nonincremental search.
+
+;; Exiting immediately from isearch uses isearch-edit-string instead
+;; of nonincremental-search, if search-nonincremental-instead is non-nil.
+;; The name of this option should probably be changed if we decide to
+;; keep the behavior.  No point in forcing nonincremental search until
+;; the last possible moment.
+
+;; TODO
+;; - Integrate the emacs 19 generalized command history.
+;; - Think about incorporating query-replace.
+;; - Hooks and options for failed search.
 
 ;;; Change Log:
 
-;;;====================================================================
-
-;;; $Header: /import/kaplan/kaplan/liberte/Isearch/RCS/isearch-mode.el,v 1.2 92/05/27 11:33:57 liberte Exp Locker: liberte $
-;;; $Log:      isearch-mode.el,v $
-;;; Revision 1.2  92/05/27  11:33:57  liberte
-;;; Several new commands and features have been added.  Emacs version
-;;; 19 has a search ring, which is supported here.  Other fixes found
-;;; in the version 19 isearch are included here.  Also see variables
-;;; search-caps-disable-folding, search-nonincremental-instead,
-;;; search-whitespace-regexp, and commands isearch-toggle-regexp,
-;;; isearch-edit-string,
-;;; 
-;;; Semi-modal searching is supported, using a recursive edit. If
-;;; isearching is started non-interactively by calling one of the
-;;; isearch commands (e.g. isearch-forward), it does not return
-;;; until the search is completed.  You should still be able switch
-;;; buffers, so be careful not to get things confused.
+;;; Changes before those recorded in ChangeLog:
+
+;;; 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.
+;;; Added some support for lemacs.
+;;; Added general isearch-highlight option - but only for lemacs so far.
+;;; Added support for frame switching in emacs 19.
+;;; Added word search option to isearch-edit-string.
+;;; Renamed isearch-quit to isearch-abort.
+;;; Numerous changes to comments and doc strings.
 ;;; 
+;;; Revision 1.3  92/06/29  13:10:08  liberte
+;;; Moved modal isearch-mode handling into isearch-mode.
+;;; Got rid of buffer-local isearch variables.
+;;; isearch-edit-string used by ring adjustments, completion, and
+;;; nonincremental searching.  C-s and C-r are additional exit commands.
+;;; Renamed all regex to regexp.
+;;; Got rid of found-start and found-point globals.
+;;; Generalized handling of upper-case chars.
+;;; Revision 1.2  92/05/27  11:33:57  liberte
+;;; Emacs version 19 has a search ring, which is supported here.
+;;; Other fixes found in the version 19 isearch are included here.
+;;;
+;;; Also see variables search-caps-disable-folding,
+;;; search-nonincremental-instead, search-whitespace-regexp, and
+;;; commands isearch-toggle-regexp, isearch-edit-string.
+;;;
+;;; semi-modal isearching is supported.
 
 ;;; Changes for 1.1
 ;;; 3/18/92 Fixed invalid-regexp.
 
 ;;; Code:
 
+\f
 ;;;=========================================================================
-;;; The following, defined in loaddefs.el, are still used with isearch-mode.
+;;; Emacs features
 
-;(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.")
+;; isearch-mode takes advantage of the features provided by several
+;; different versions of emacs.  Rather than testing the version of
+;; emacs, several constants are defined, one for each of the features.
+;; Each of the tests below must work on any version of emacs.
+;; (Perhaps provide and featurep could be used for this purpose.)
 
-;(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 isearch-gnu-emacs-events (fboundp 'set-frame-height)) ;; emacs 19
+(defconst isearch-pre-command-hook-exists (boundp 'pre-command-hook)) ;; lemacs
+(defconst isearch-event-data-type nil)  ;; lemacs
 
-;(defconst search-exit-option t
-;  "Non-nil means random control characters terminate incremental search.")
+(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.")
+(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.")
 
-;(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.
-This does not yet apply to yanked strings, however.")
+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 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.
-The default value of t reflects the default behavior of old  
-isearch.")
+Actually, `isearch-edit-string' is called to let you enter the search
+string, and RET terminates editing and does a nonincremental search.")
 
 (defconst search-whitespace-regexp "\\s-+"
   "*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
+  "*Non-nil means incremental search highlights the current match.")
+
+(defvar isearch-mode-hook nil
+  "Function(s) to call after starting up an incremental search.")
+
+(defvar isearch-mode-end-hook nil
+  "Function(s) to call after terminating an incremental search.")
+
 ;;;==================================================================
 ;;; Search ring.
-;;; "regex" == "regexp".  One should become the standard term.
 
 (defvar search-ring nil
   "List of search string sequences.")
-(defvar regex-search-ring nil   ;; Is `regex' the new spelling?
+(defvar regexp-search-ring nil
   "List of regular expression search string sequences.")
 
 (defconst search-ring-max 16
   "*Maximum length of search ring before oldest elements are thrown away.")
-(defconst regex-search-ring-max 16
-  "*Maximum length of regex search ring before oldest elements are thrown away.")
+(defconst regexp-search-ring-max 16
+  "*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.")
-(defvar regex-search-ring-yank-pointer nil
-  "The tail of the regular expression 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
+  "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.
+Default value, nil, means edit the string instead.")
 
 ;;;====================================================
 ;;; Define isearch-mode keymap.
@@ -150,143 +215,156 @@ thing searched for.")
 (defvar isearch-mode-map nil
   "Keymap for isearch-mode.")
 
-(defvar isearch-mode-meta-map nil
-  "Keymap for isearch-mode for keys with meta char prefix.")
-
-
-;; To handle meta char prefix keys, define another full keymap.
-;; The same must be done for any other prefix keys.
-;; It would be simpler to disable to global keymap, and/or
-;; have a default local key binding for any key not otherwise bound.
-(if isearch-mode-meta-map
-    nil
-  (setq isearch-mode-meta-map  
-       (list 'keymap (make-vector 128 'isearch-other-meta-char)))
-  (define-key isearch-mode-meta-map "n" 'isearch-ring-advance)
-  (define-key isearch-mode-meta-map "p" 'isearch-ring-retreat)
-  (define-key isearch-mode-meta-map " " 'isearch-whitespace-chars)  
-;for regexps
-
-;;  (define-key isearch-mode-meta-map "?" nil) ; my help key is M-?
-  )
-
-(if isearch-mode-map
-    nil
-  (let ((i 0)
-
-       ;; Printing chars extend the selection by default.
-       (array (make-vector 128 'isearch-printing-char)))
-
-    ;; Non-printing chars by default suspend isearch mode transparently
-    (while (< i ?\ )
-      (aset array i 'isearch-other-control-char)
-      (setq i (1+ i)))
-
-    (setq i ?A)
-    (while (<= i ?Z)
-      (aset array i 'isearch-upper-case-char)
-      (setq i (1+ i)))
-
-    (setq isearch-mode-map (list 'keymap array))
-
-    ;; You can reenable global keys by unbinding them locally.  
-
-    ;; For the help char this doesnt work quite as expected because
-    ;; isearch-mode is not a major mode, and the echo area is not
-    ;; restored after the help command.
-    ;; Also, we should not assume that the help-command is on C-h.
-    ;; If it is not, and the prefix is not the meta-char, we would
-    ;; have to create another map for its prefix.
-;    (define-key isearch-mode-map "\C-h" nil)
-
-    ;; Several non-printing chars change the searching behavior.
-    (define-key isearch-mode-map "\C-s" 'isearch-repeat-forward)
-    (define-key isearch-mode-map "\C-r" 'isearch-repeat-backward)
-    (define-key isearch-mode-map "\177" 'isearch-delete-char)
-    (define-key isearch-mode-map "\C-g" 'isearch-quit)
+(or isearch-mode-map
+    (let* ((i 0)
+          (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 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.
+      (define-key map "\C-s" 'isearch-repeat-forward)
+      (define-key map "\C-r" 'isearch-repeat-backward)
+      (define-key map "\177" 'isearch-delete-char)
+      (define-key map "\C-g" 'isearch-abort)
     
+      (define-key map "\C-q" 'isearch-quote-char)
 
-    (define-key isearch-mode-map "\C-q" 'isearch-quote-char)
-
-    ;;  (define-key isearch-mode-map "\r" 'isearch-return-char)
-    ;; For version 19, CR (C-m) terminates search and LFD (C-j) matches eol.
-    (define-key isearch-mode-map "\r" 'isearch-exit)
-    (define-key isearch-mode-map "\C-j" 'isearch-printing-char)
+      (define-key map "\r" 'isearch-exit)
+      (define-key map "\C-j" 'isearch-printing-char)
+      (define-key map "\t" 'isearch-printing-char)
+      (define-key map " " 'isearch-whitespace-chars)
     
+      (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)
+
+;;; 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.
+      (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-gnu-emacs-events
+         (define-key map [switch-frame] 'isearch-switch-frame-handler))
+      
+      (setq isearch-mode-map map)
+      ))
 
-    (define-key isearch-mode-map "\C-w" 'isearch-yank-word)
-    (define-key isearch-mode-map "\C-y" 'isearch-yank-line)
+;; Some bindings you may want to put in your isearch-mode-hook.
+;; Suggest some alternates...
+;; (define-key isearch-mode-map "\C-t" 'isearch-toggle-regexp)
+;; (define-key isearch-mode-map "\C-^" 'isearch-edit-string)
 
-    (define-key isearch-mode-map "\C-t" 'isearch-toggle-regexp)
-    (define-key isearch-mode-map "\C-^" 'isearch-edit-string)
 
-    ;; define keys for regexp chars * ? |
-    (define-key isearch-mode-map "*" 'isearch-*-char)
-    (define-key isearch-mode-map "?" 'isearch-*-char)
-    (define-key isearch-mode-map "|" 'isearch-|-char)
+(defvar minibuffer-local-isearch-map nil
+  "Keymap for editing isearch strings in the minibuffer.")
 
-    ;; Assumes meta-prefix-char is \e.
-    ;; isearch-mode-meta-map must be a keymap before this.
-    (define-key isearch-mode-map "\e" isearch-mode-meta-map)
-    ))
+(or minibuffer-local-isearch-map
+    (let ((map (copy-keymap 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 "\M-\t" 'isearch-complete-edit)
+      (define-key map "\C-s" 'isearch-forward-exit-minibuffer)
+      (define-key map "\C-r" 'isearch-reverse-exit-minibuffer)
+      (setq minibuffer-local-isearch-map map)
+      ))
 
 ;;;========================================================
 ;; Internal variables declared globally for byte-compiler.
-;; These are all made buffer-local during searching.
-
-(defvar isearch-cmds nil
-  "Stack of search status sets.")
-(defvar isearch-string ""
-  "The current search string.")
-(defvar isearch-message ""
-  "The text-char-description version of isearch-string")
-(defvar isearch-success t)
-(defvar isearch-forward nil)
-(defvar isearch-other-end nil  
-  "Start of last match if forward, end if backward.")
-(defvar isearch-invalid-regexp nil)
-(defvar isearch-wrapped nil)
+;; These are all set with setq while isearching
+;; and bound locally while editing the search string.
+
+(defvar isearch-forward nil)   ; Searching in the forward direction.
+(defvar isearch-regexp nil)    ; Searching for a regexp.
+(defvar isearch-word nil)      ; Searching for words.
+
+(defvar isearch-cmds nil)   ; Stack of search status sets.
+(defvar isearch-string "")  ; The current search string.
+(defvar isearch-message "") ; text-char-description version of isearch-string
+
+(defvar isearch-success t)             ; Searching is currently successful.
+(defvar isearch-invalid-regexp nil)    ; Regexp not well formed.
+(defvar isearch-other-end nil) ; Start (end) of match if forward (backward).
+(defvar isearch-wrapped nil)   ; Searching restarted from the top (bottom).
 (defvar isearch-barrier 0)
 
-(defvar isearch-regexp nil)
-(defvar isearch-case-fold-search nil
-  "Value of case-fold-search while actually searching.")
+(defvar isearch-case-fold-search nil) ; case-fold-search while searching.
 
 (defvar isearch-adjusted nil)
 (defvar isearch-slow-terminal-mode nil)
-(defvar isearch-small-window nil
-  "If t, using a small window.")
-(defvar isearch-found-point nil
-  "to restore point from a small window.")
-
-(defvar isearch-found-start nil
-  "This is the window-start value found by the search.")
+;;; If t, using a small window.
+(defvar isearch-small-window nil)
 (defvar isearch-opoint 0)
-(defvar isearch-window-configuration nil
-  "The window configuration active at the beginning of the search.")
-(defvar isearch-old-local-map [])
+;;; The window configuration active at the beginning of the search.
+(defvar isearch-window-configuration nil)
+(defvar isearch-old-local-map nil)
 
-(defvar isearch-yank-flag nil
-  "Flag to indicate a yank occurred, so don't move the cursor.")
+;; Flag to indicate a yank occurred, so don't move the cursor.
+(defvar isearch-yank-flag nil)
 
-(defvar isearch-op-fun nil
-  "A function to be called after each input character is processed.
-(It is not called after characters that exit the search.)
-It is only set from an optional argument to `isearch-mode'.")
+;;; A function to be called after each input character is processed.
+;;; (It is not called after characters that exit the search.)
+;;; It is only set from an optional argument to `isearch-mode'.
+(defvar isearch-op-fun nil)
 
-;; This is a global variable to avoid byte-compile warnings.
-(defvar isearch-last-command-char -1
-  "Last command char.")
+;;;  Is isearch-mode in a recursive edit for modal searching.
+(defvar isearch-recursive-edit nil)
 
-(defvar isearch-mode-hook nil
-  "List of functions to call after starting up an incremental search.
-See `isearch-modal' for an example.
-Set with `(setq isearch-mode-hook (cons 'myhook isearch-mode-hook))
-where myhook can be a function name or lambda expression.")
+;;; Should isearch be terminated after doing one search?
+(defvar isearch-nonincremental nil)
+
+;; New value of isearch-forward after isearch-edit-string.
+(defvar isearch-new-forward nil)
 
-(defvar isearch-mode-end-hook nil
-  "List of functions to call after terminating an incremental search.
-See `isearch-mode-hook' for more details.")
 
 ;;;==============================================================
 ;; Minor-mode-alist changes - kind of redundant with the
@@ -296,117 +374,111 @@ See `isearch-mode-hook' for more details.")
     (nconc minor-mode-alist
           (list '(isearch-mode isearch-mode))))
 
-(defvar isearch-mode nil)
+(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 be moved to loaddefs.el
+;;; These four functions should replace those in loaddefs.el
+;;; An alternative is to defalias isearch-forward etc to isearch-mode,
+;;; and look at this-command to set the options accordingly.
 
-(defun isearch-forward ()
+(defun isearch-forward (&optional regexp-p no-recursive-edit)
   "\
 Do incremental search forward.
+With a prefix argument, do an incremental regular expression search instead.
+\\<isearch-mode-map>
 As you type characters, they add to the search string and are found.
+The following non-printing keys are bound in `isearch-mode-map'.  
 
-\\<isearch-mode-map>
-Type \\[isearch-delete-char] to cancel characters from end of search  
-string.
+Type \\[isearch-delete-char] to cancel characters from end of search string.
 Type \\[isearch-exit] to exit, leaving point at location found.
-Type \\[isearch-repeat-forward] to search again forward,  
-\\[isearch-repeat-backward] to search again backward.
-Type \\[isearch-toggle-regexp] to toggle regular expression with normal searching.
-Type \\[isearch-yank-word] to yank word 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, etc.
+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] to yank word 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-quote-char] to quote control character to search for it.
-Type C-j to match end of line.
+\\[isearch-abort] while searching or when search has failed cancels input\
+ back to what has
+ been found successfully.
+\\[isearch-abort] when search is successful aborts and moves point to\
+ starting point.
 
 Also supported is a search ring of the previous 16 search strings.
 Type \\[isearch-ring-advance] to search for the next item in the search ring.
-Type \\[isearch-ring-retreat] to search for the previous item in the search ring.
+Type \\[isearch-ring-retreat] to search for the previous item in the search\
+ ring.
+Type \\[isearch-complete] to complete the search string using the search ring.
 
+The above keys, bound in `isearch-mode-map', are often controlled by 
+ options; do M-x apropos on search-.* to find them.
 Other control and meta characters terminate the search
- and are then executed normally.
+ and are then executed normally (depending on `search-exit-option').
 
-\\[isearch-quit] while searching or when search has failed
- cancels input back to what has been found successfully.
-\\[isearch-quit] when search is successful aborts and moves point to starting point.
+If this function is called non-interactively, it does not return to
+the calling function until the search is done."
 
-All of these keys are bound in `isearch-mode-map' and
-`isearch-mode-meta-map'.  If `isearch-forward' is called
-non-interactively, it does not return to the calling function until
-the search is done."
-  (interactive)
-  (if (interactive-p)
-      (isearch-mode t)
-    (isearch-modal t)))
+  (interactive "P\np")
+  (isearch-mode t (not (null regexp-p)) nil (not no-recursive-edit)))
 
-(defun isearch-forward-regexp ()
+(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)
-  (if (interactive-p)
-      (isearch-mode t t)
-    (isearch-modal t t)))
+  (interactive "P\np")
+  (isearch-mode t (null not-regexp) nil (not no-recursive-edit)))
 
-(defun isearch-backward ()
+(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)
-  (if (interactive-p)
-      (isearch-mode nil)
-    (isearch-modal nil)))
+  (interactive "P\np")
+  (isearch-mode nil (not (null regexp-p)) nil (not no-recursive-edit)))
 
-(defun isearch-backward-regexp ()
+(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 "P\np")
+  (isearch-mode nil (null not-regexp) nil (not no-recursive-edit)))
+
+
+(defun isearch-mode-help ()
   (interactive)
-  (if (interactive-p)
-      (isearch-mode nil t)
-    (isearch-modal nil t)))
-
-
-(defun isearch-modal (forward &optional regexp op-fun)
-  ;; As an example of using the hooks, 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.
-  ;; This is used if the above functions are called non-interactively.
-  (let ((isearch-mode-hook 
-        (cons (function (lambda () (recursive-edit)))
-              isearch-mode-hook))
-       (isearch-mode-end-hook
-        (cons (function (lambda () (exit-recursive-edit)))
-              isearch-mode-end-hook)))
-    (isearch-mode forward regexp op-fun)))
+  (describe-function 'isearch-forward)
+  (isearch-update))
 
 \f
 ;;;==================================================================
 ;; isearch-mode only sets up incremental search for the minor mode.
 ;; All the work is done by the isearch-mode commands.
 
-(defun isearch-mode (forward &optional regexp op-fun)
+;; Not used yet:
+;;(defconst isearch-commands '(isearch-forward isearch-backward
+;;                          isearch-forward-regexp isearch-backward-regexp)
+;;  "List of commands for which isearch-mode does not recursive-edit.")
+                            
+
+(defun isearch-mode (forward &optional regexp op-fun recursive-edit word-p)
   "Start isearch minor mode.  Called by isearch-forward, etc."
-  ;; Make buffer-local variables for isearching.
-  ;; We really need window-local variables.
-  (mapcar 
-   'make-local-variable
-   '(isearch-forward 
-     isearch-regexp isearch-string isearch-message
-     isearch-case-fold-search
-     isearch-cmds isearch-success isearch-wrapped
-     isearch-barrier isearch-adjusted isearch-invalid-regexp
-     isearch-slow-terminal-mode isearch-other-end isearch-small-window
-     isearch-found-point isearch-found-start isearch-opoint 
-     isearch-window-configuration isearch-old-local-map))
 
   ;; Initialize global vars.
   (setq isearch-forward forward
        isearch-regexp regexp
+       isearch-word word-p
        isearch-op-fun op-fun
        isearch-case-fold-search case-fold-search
        isearch-string ""
@@ -418,28 +490,43 @@ is treated as a regexp.  See \\[isearch-forward] for more info."
        isearch-adjusted nil
        isearch-yank-flag nil
        isearch-invalid-regexp nil
+       ;; 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-found-point nil
 
-       isearch-found-start nil
        isearch-opoint (point)
-       isearch-window-configuration (current-window-configuration)
        isearch-old-local-map (current-local-map)
-
-;;     inhibit-quit t
-       )
+       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)
   (isearch-update)
   (run-hooks 'isearch-mode-hook)
+
+  ;; 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
+      (let ((isearch-recursive-edit t))
+       (recursive-edit)))
   )
 
 
@@ -448,16 +535,19 @@ is treated as a regexp.  See \\[isearch-forward] for more info."
 
 (defun isearch-update ()
   ;; Called after each command to update the display.  
-  (or unread-command-char
+  (if (if isearch-event-data-type
+         (null unread-command-event)
+       (if isearch-gnu-emacs-events
+           (null unread-command-events)
+         (< unread-command-char 0)))
       (progn
        (if (not (input-pending-p))
            (isearch-message))
        (if (and isearch-slow-terminal-mode
                 (not (or isearch-small-window 
                          (pos-visible-in-window-p))))
-           (progn
+           (let ((found-point (point)))
              (setq isearch-small-window t)
-             (setq isearch-found-point (point))
              (move-to-window-line 0)
              (let ((window-min-height 1))
                (split-window nil (if (< search-slow-window-lines 0)
@@ -471,65 +561,81 @@ is treated as a regexp.  See \\[isearch-forward] for more info."
                                             (window-hscroll))
                         (set-window-hscroll (selected-window) 0))
                (other-window 1))
-             (goto-char isearch-found-point)))))
+             (goto-char found-point)))
+       (if isearch-other-end
+           (if (< isearch-other-end (point)) ; isearch-forward?
+               (isearch-highlight isearch-other-end (point))
+             (isearch-highlight (point) isearch-other-end)))
+       ))
   (setq ;; quit-flag nil  not for isearch-mode
    isearch-adjusted nil
    isearch-yank-flag nil)
   )
 
 
-(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 isearch-found-start (window-start (selected-window)))
-  (setq isearch-found-point (point))
-  (set-window-configuration isearch-window-configuration)
+  ;; (setq pre-command-hook isearch-old-pre-command-hook) ; for lemacs
+  (isearch-dehighlight t)
+  (let ((found-start (window-start (selected-window)))
+       (found-point (point)))
+    (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)
+       (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
+       (goto-char found-point)
+      ;; Exiting the save-window-excursion clobbers window-start; restore it.
+      (set-window-start (selected-window) found-start t)))
+
+  (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 regex-search-ring-yank-pointer
-                        (memq isearch-string regex-search-ring)))
+         (if (or (null regexp-search-ring)
+                 (not (string= isearch-string (car regexp-search-ring))))
              (progn
-               (setq regex-search-ring (cons isearch-string regex-search-ring)
-                     regex-search-ring-yank-pointer regex-search-ring)
-               (if (> (length regex-search-ring) regex-search-ring-max)
-                   (setcdr (nthcdr (1- search-ring-max) regex-search-ring)
+               (setq 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
-                      (memq 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))))))
 
-  ;; 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)
-    (message ""))
-  (if isearch-small-window
-      (goto-char isearch-found-point)
-    ;; Exiting the save-window-excursion clobbers window-start; restore it.
-    (set-window-start (selected-window) isearch-found-start t))
-
-  ;; Kill buffer-local variables for isearching
-  (mapcar 
-   'kill-local-variable
-   '(isearch-forward 
-     isearch-regexp isearch-string isearch-message
-     isearch-case-fold-search
-     isearch-cmds isearch-success isearch-wrapped
-     isearch-barrier isearch-adjusted isearch-invalid-regexp
-     isearch-slow-terminal-mode isearch-other-end isearch-small-window
-     isearch-found-point isearch-found-start isearch-opoint 
-     isearch-window-configuration isearch-old-local-map))
-
-  (setq isearch-mode nil)
-  (set-buffer-modified-p (buffer-modified-p))
   (run-hooks 'isearch-mode-end-hook)
-  )
+  (if isearch-recursive-edit (exit-recursive-edit)))
+
+;;;=======================================================
+;;; Switching buffers should first terminate isearch-mode.
+;;; 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.
+(defun isearch-switch-frame-handler ()
+  (interactive) ;; Is this necessary?
+  ;; First terminate isearch-mode.
+  (isearch-done)
+  (handle-switch-frame (car (cdr (isearch-last-command-char)))))
+
+;;;========================================================
 
 \f
 ;;;====================================================
@@ -539,40 +645,173 @@ is treated as a regexp.  See \\[isearch-forward] for more info."
   "Exit search normally.
 However, if this is the first command after starting incremental
 search and `search-nonincremental-instead' is non-nil, do a
-nonincremental search instead."
-
+nonincremental search instead via `isearch-edit-string'."
   (interactive)
   (if (and search-nonincremental-instead 
           (= 0 (length isearch-string)))
-      (nonincremental-search isearch-forward isearch-regexp))
+      (let ((isearch-nonincremental t))
+       (isearch-edit-string)))
   (isearch-done))
 
 
 (defun isearch-edit-string ()
-  "Edit the search string in the minibuffer and return to incremental search."
-  ;; This doesnt back up the search point.
+  "Edit the search string in the minibuffer.
+The following additional command keys are active while editing.
+\\<minibuffer-local-isearch-map>
+\\[exit-minibuffer] to resume incremental searching with the edited string.
+\\[isearch-nonincremental-exit-minibuffer] to do one nonincremental search.
+\\[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 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."
+
+  ;; This code is very hairy for several reasons, explained in the code.
+  ;; 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 doesn't back up the search point.  Should it?
   (interactive)
-  (setq isearch-string (read-string (isearch-message-prefix) isearch-string)
-       isearch-message (mapconcat 'text-char-description
-                                  isearch-string ""))
-  (isearch-push-state)
-  (isearch-search)
-  (isearch-update))
+  (condition-case err
+      (let ((isearch-nonincremental isearch-nonincremental)
+
+           ;; Locally bind all isearch global variables to protect them
+           ;; from recursive isearching.
+           ;; isearch-string -message and -forward are not bound
+           ;; so they may be changed.  Instead, save the values.
+           (isearch-new-string isearch-string)
+           (isearch-new-message isearch-message)
+           (isearch-new-forward isearch-forward)
+           (isearch-new-word isearch-word)
+
+           (isearch-regexp isearch-regexp)
+           (isearch-op-fun isearch-op-fun)
+           (isearch-cmds isearch-cmds)
+           (isearch-success isearch-success)
+           (isearch-wrapped isearch-wrapped)
+           (isearch-barrier isearch-barrier)
+           (isearch-adjusted isearch-adjusted)
+           (isearch-yank-flag isearch-yank-flag)
+           (isearch-invalid-regexp isearch-invalid-regexp)
+           (isearch-other-end isearch-other-end)
+           (isearch-opoint isearch-opoint)
+           (isearch-slow-terminal-mode isearch-slow-terminal-mode)
+           (isearch-small-window isearch-small-window)
+           (isearch-recursive-edit isearch-recursive-edit)
+           ;; Save current configuration so we can restore it here.
+           (isearch-window-configuration (current-window-configuration))
+           )
+
+       ;; Actually terminate isearching until editing is done.
+       ;; 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 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
+                  (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))
+             ;; If the first character the user types when we prompt them
+             ;; for a string is the yank-word character, then go into
+             ;; word-search mode.  Otherwise unread that character and
+             ;; read a key the normal way.
+             ;; Word search does not apply (yet) to regexp searches,
+             ;; no check is made here.
+             (message (isearch-message-prefix nil nil t))
+             (if (eq 'isearch-yank-word
+                     (lookup-key
+                      isearch-mode-map
+                      (char-to-string
+                       (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 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.
+         (isearch-mode isearch-forward 
+                       isearch-regexp 
+                       isearch-op-fun 
+                       isearch-recursive-edit
+                       isearch-word)
+
+         ;; Copy new local values to isearch globals
+         (setq isearch-string isearch-new-string
+               isearch-message isearch-new-message
+               isearch-forward isearch-new-forward
+               isearch-word isearch-new-word))
+
+       ;; Empty isearch-string means use default.
+       (if (= 0 (length 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)
+       (isearch-search)
+       (isearch-update)
+       (if isearch-nonincremental 
+           (progn
+             ;; (sit-for 1) ;; needed if isearch-done does: (message "")
+             (isearch-done))))
+
+    (quit  ; handle abort-recursive-edit
+     (isearch-abort)  ;; outside of let to restore outside global values
+     )))
+
+(defun isearch-nonincremental-exit-minibuffer ()
+  (interactive)
+  (setq isearch-nonincremental t)
+  (exit-minibuffer))
+
+(defun isearch-forward-exit-minibuffer ()
+  (interactive)
+  (setq isearch-new-forward t)
+  (exit-minibuffer))
+
+(defun isearch-reverse-exit-minibuffer ()
+  (interactive)
+  (setq isearch-new-forward nil)
+  (exit-minibuffer))
 
 
-(defun isearch-quit ()
-  "Quit incremental search mode if searching is successful.
-Otherwise, revert to previous successful search and continue searching."
+(defun isearch-abort ()
+  "Abort incremental search mode if searching is successful, signalling quit.
+Otherwise, revert to previous successful search and continue searching.
+Use `isearch-exit' to quit without signalling."
   (interactive)
-  (ding)
+;;  (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 and quit
-    ;; If search is failing, rub out until it is once more
-    ;;  successful.
+            (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)))
 
@@ -584,18 +823,12 @@ Otherwise, revert to previous successful search and continue searching."
       (if (equal isearch-string "")
          ;; If search string is empty, use last one.
          (setq isearch-string
-;;             (if isearch-regexp
-;;                 search-last-regexp search-last-string)
                (or (if isearch-regexp
-                       (if regex-search-ring-yank-pointer
-                           (car regex-search-ring-yank-pointer)
-                         (car regex-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 'text-char-description
+               (mapconcat 'isearch-text-char-description
                           isearch-string ""))
        ;; If already have what to search for, repeat it.
        (or isearch-success
@@ -633,6 +866,7 @@ Otherwise, revert to previous successful search and continue searching."
   ;; The status stack is left unchanged.
   (interactive)
   (setq isearch-regexp (not isearch-regexp))
+  (if isearch-regexp (setq isearch-word nil))
   (isearch-update))
 
 (defun isearch-delete-char ()
@@ -647,24 +881,28 @@ If no previous match was done, just beep."
 
 (defun isearch-yank (chunk)
   ;; Helper for isearch-yank-word and isearch-yank-line
-  (let ((word (save-excursion
-               (and (not isearch-forward) isearch-other-end
-                    (goto-char isearch-other-end))
-               (buffer-substring
-                (point)
-                (save-excursion
-                  (cond
-                   ((eq chunk 'word)
-                    (forward-word 1))
-                   ((eq chunk 'line)
-                    (end-of-line)))
-                  (point))))))
-    (if isearch-regexp (setq word (regexp-quote word)))
-    (setq isearch-string (concat isearch-string word)
+  (let ((string (save-excursion
+                 (and (not isearch-forward) isearch-other-end
+                      (goto-char isearch-other-end))
+                 (buffer-substring
+                  (point)
+                  (save-excursion
+                    (cond
+                     ((eq chunk 'word)
+                      (forward-word 1))
+                     ((eq chunk 'line)
+                      (end-of-line)))
+                    (point))))))
+    ;; Downcase the string if not supposed to case-fold yanked strings.
+    (if (and isearch-case-fold-search
+            (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)
          isearch-message
          (concat isearch-message
-                 (mapconcat 'text-char-description
-                            word ""))
+                 (mapconcat 'isearch-text-char-description
+                            string ""))
          ;; Don't move cursor in reverse search.
          isearch-yank-flag t))
   (isearch-search-and-update))
@@ -719,10 +957,10 @@ If no previous match was done, just beep."
 
 
 ;; *, ?, and | chars can make a regexp more liberal.
-;; They can make a regexp match sooner
-;; or make it succeed instead of failing.
+;; 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."
@@ -742,10 +980,9 @@ If no previous match was done, just beep."
           (if isearch-forward
               (max cs isearch-barrier)
             (min cs isearch-barrier))))))
-  (isearch-process-search-char last-command-char))
+  (isearch-process-search-char (isearch-last-command-char)))
   
 
-
 (defun isearch-|-char ()
   "If in regexp search, jump to the barrier."
   (interactive)
@@ -753,79 +990,83 @@ If no previous match was done, just beep."
       (progn
        (setq isearch-adjusted t)
        (goto-char isearch-barrier)))
-  (isearch-process-search-char last-command-char))
+  (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."
-  (interactive)
-  (if search-exit-option
-      (progn
-       (setq unread-command-char last-command-char)
-       (isearch-done))
-    ;; otherwise
-    (isearch-search-and-update)))
-
+(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)
-  (if search-exit-option
-      (unwind-protect
-         (isearch-done)  ;; this exits recursive edit
-       ;; Reexecute the key.
-       (command-execute (this-command-keys)))
-    ;; otherwise
-    (isearch-search-and-update)))
-
+  (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."
   (interactive)
   (isearch-process-search-char (read-quoted-char (isearch-message t))))
 
-
 (defun isearch-return-char ()
   "Convert return into newline for incremental search.
 Obsolete."
   (interactive)
   (isearch-process-search-char ?\n))
 
-
 (defun isearch-printing-char ()
-  "Any other printing character => add it to the search string and search."
-  (interactive)
-  (isearch-process-search-char last-command-char))
-
-
-(defun isearch-upper-case-char ()
-  "Any upper case char => turn off case fold search for remainder of search."
-  ;; This feature only applies to interactively entered chars,
-  ;; but not yanked chars, repeat default searches, or search ring searches.
-  ;; Support for these should be easy to add.
+  "Add this ordinary printing character to the search string and search."
   (interactive)
-  (if search-caps-disable-folding
-      (setq isearch-case-fold-search nil))
-  (isearch-printing-char))
+  (isearch-process-search-char (isearch-last-command-char)))
 
 (defun isearch-whitespace-chars ()
-  "Match all whitespace chars, if in regexp mode."
+  "Match all whitespace chars, if in regexp mode.
+If you want to search for just a space, type C-q SPC."
   (interactive)
-  (if (and isearch-regexp search-whitespace-regexp)
-      (isearch-process-search-string search-whitespace-regexp " ")
-    (isearch-other-meta-char)))
+  (if isearch-regexp 
+      (if search-whitespace-regexp
+         (isearch-process-search-string search-whitespace-regexp " ")
+       (isearch-printing-char))
+    (progn
+      ;; This way of doing word search doesn't correctly extend current search.
+      ;;      (setq isearch-word t)
+      ;;      (setq isearch-adjusted t)
+      ;;      (goto-char isearch-barrier)
+      (isearch-printing-char))))
 
 (defun isearch-process-search-char (char)
   ;; Append the char to the search string, update the message and re-search.
-  (isearch-process-search-string (char-to-string char) 
-
-                                (text-char-description char)))
+  (isearch-process-search-string 
+   (isearch-char-to-string char) 
+   (isearch-text-char-description char)))
 
 (defun isearch-process-search-string (string message)
   (setq isearch-string (concat isearch-string string)
@@ -836,32 +1077,41 @@ Obsolete."
 ;;===========================================================
 ;; Search Ring
 
-(defun isearch-ring-adjust (advance)
-  ;; helper for isearch-ring-advance and isearch-ring-retreat
-  (if (cdr isearch-cmds)
-      (isearch-pop-state))
-  (let* ((ring (if isearch-regexp regex-search-ring search-ring))
+(defun isearch-ring-adjust1 (advance)
+  ;; Helper for isearch-ring-adjust
+  (let* ((ring (if isearch-regexp regexp-search-ring search-ring))
         (length (length ring))
         (yank-pointer-name (if isearch-regexp
-                               'regex-search-ring-yank-pointer
+                               'regexp-search-ring-yank-pointer
                              'search-ring-yank-pointer))
         (yank-pointer (eval yank-pointer-name)))
     (if (zerop length)
        ()
       (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)
-           isearch-message (mapconcat 'text-char-description
-                                      isearch-string ""))))
+                (% (+ (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 "")))))
+
+(defun isearch-ring-adjust (advance)
+  ;; Helper for isearch-ring-advance and isearch-ring-retreat
+  (if (cdr isearch-cmds)  ;; is there more than one thing on stack?
+      (isearch-pop-state))
+  (isearch-ring-adjust1 advance)
   (isearch-push-state)
-  (isearch-search)
-  (isearch-update))
+  (if search-ring-update
+      (progn
+       (isearch-search)
+       (isearch-update))
+    (isearch-edit-string)
+    ))
 
 (defun isearch-ring-advance ()
   "Advance to the next search string in the ring."
+  ;; This could be more general to handle a prefix arg, but who would use it.
   (interactive)
   (isearch-ring-adjust 'advance))
 
@@ -870,75 +1120,113 @@ Obsolete."
   (interactive)
   (isearch-ring-adjust nil))
 
-\f
-;;;=============================================================
-;; Window-local variables
-;; (not used yet - and maybe never)
-
-(defvar window-local-variable-alist nil
-  "An alist of windows associated with window local variables and values.
-The cdr of each item is another alist of variables and values.")
-
-(defvar last-local-window nil)
-(defvar last-window-local-vars nil)
-
-(defun kill-window-local-variables ()
-  "Remove the old variable list, if any."
-  (setq window-local-variable-alist
-       (delq window-local-variable-alist
-             (assq (selected-window)
-                   window-local-variable-alist))))
-
-;; Assume that window-local variables are not buffer-local
-;; so we can delay storing until absolutely necessary.
-
-(defun store-window-local-variables (&rest vars-and-vals)
-  "Store the window local variables for selected window."
-  (setq last-local-window (selected-window))
-  (setq last-window-local-vars vars-and-vals))
-
+(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)))
+
+      (erase-buffer)
+      (insert (nth yank-pointer ring))
+      (goto-char (point-max)))))
+
+(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 ()
+  ;; Helper for isearch-complete and isearch-complete-edit
+  ;; Return t if completion OK, nil if no completion exists.
+  (let* ((ring (if isearch-regexp regexp-search-ring search-ring))
+         (alist (mapcar (function (lambda (string) (list string))) ring))
+         (completion-ignore-case case-fold-search)
+         (completion (try-completion isearch-string alist)))
+    (cond
+     ((eq completion t)
+      ;; isearch-string stays the same
+      t)
+     ((or completion ; not nil, must be a string
+         (= 0 (length isearch-string))) ; shouldnt have to say this
+      (if (equal completion isearch-string)  ;; no extension?
+         (if completion-auto-help
+             (with-output-to-temp-buffer "*Isearch completions*"
+               (display-completion-list 
+                (all-completions isearch-string alist))))
+       (setq isearch-string completion))
+      t)
+     (t
+      (message "No completion") ; waits a second if in minibuffer
+      nil))))
+
+(defun isearch-complete ()
+  "Complete the search string from the strings on the search ring.
+The completed string is then editable in the minibuffer.
+If there is no completion possible, say so and continue searching."
+  (interactive)
+  (if (isearch-complete1)
+      (isearch-edit-string)
+    ;; else
+    (sit-for 1)
+    (isearch-update)))
 
-(defun fetch-window-local-variables ()
- "Fetch the window local variables for selected window.
-Does nothing if the last store was for the same window."
-  (if (not (eq (selected-window) last-local-window))
+(defun isearch-complete-edit ()
+  "Same as `isearch-complete' except in the minibuffer."
+  (interactive)
+  (setq isearch-string (buffer-string))
+  (if (isearch-complete1)
       (progn
-       ;; First store the previous values.
-       (setq window-local-variable-alist
-             (cons (cons last-local-window
-                         last-window-local-vars)
-                   (delq window-local-variable-alist
-                         (assq last-local-window
-                               window-local-variable-alist))))
-       ;; Now fetch the values for the selected-window.
-       (setq last-local-window (selected-window))
-       (setq last-window-local-vars 
-               (cdr (assq last-local-window window-local-variable-alist)))
-       (let ((vars-and-vals last-window-local-vars))
-         (while vars-and-vals
-           (set (car vars-and-vals) (car (cdr vars-and-vals)))
-           (setq vars-and-vals (cdr (cdr vars-and-vals))))))))
-                   
+       (erase-buffer)
+       (insert isearch-string))))
 
 \f
 ;;;==============================================================
 ;; The search status stack (and isearch window-local variables, not used).
+;; Need a structure for this.
 
 (defun isearch-top-state ()
-;;  (fetch-window-local-variables)
   (let ((cmd (car isearch-cmds)))
     (setq isearch-string (car cmd)
          isearch-message (car (cdr cmd))
          isearch-success (nth 3 cmd)
          isearch-forward (nth 4 cmd)
          isearch-other-end (nth 5 cmd)
-         isearch-invalid-regexp (nth 6 cmd)
-         isearch-wrapped (nth 7 cmd)
-         isearch-barrier (nth 8 cmd))
+         isearch-word (nth 6 cmd)
+         isearch-invalid-regexp (nth 7 cmd)
+         isearch-wrapped (nth 8 cmd)
+         isearch-barrier (nth 9 cmd))
     (goto-char (car (cdr (cdr cmd))))))
 
 (defun isearch-pop-state ()
-;;  (fetch-window-local-variables)
   (setq isearch-cmds (cdr isearch-cmds))
   (isearch-top-state)
   )
@@ -947,23 +1235,10 @@ Does nothing if the last store was for the same window."
   (setq isearch-cmds 
        (cons (list isearch-string isearch-message (point)
                    isearch-success isearch-forward isearch-other-end 
+                   isearch-word
                    isearch-invalid-regexp isearch-wrapped isearch-barrier)
              isearch-cmds)))
 
-(defun isearch-store-variables ()
-  (store-window-local-variables 
-   'isearch-cmds isearch-cmds
-   'isearch-regexp isearch-regexp
-   'isearch-adjusted isearch-adjusted
-   'isearch-slow-terminal-mode isearch-slow-terminal-mode
-   'isearch-small-window isearch-small-window
-   'isearch-found-point isearch-found-point
-   'isearch-found-start isearch-found-start
-   'isearch-opoint isearch-opoint
-   'isearch-window-configuration isearch-window-configuration
-   'isearch-old-local-map isearch-old-local-map
-   ))
-
 \f
 ;;;==================================================================
 ;; Message string
@@ -972,13 +1247,13 @@ Does nothing if the last store was for the same window."
   ;; Generate and print the message string.
   (let ((cursor-in-echo-area ellipsis)
        (m (concat
-           (isearch-message-prefix c-q-hack ellipsis)
+           (isearch-message-prefix c-q-hack ellipsis isearch-nonincremental)
            isearch-message
            (isearch-message-suffix c-q-hack ellipsis)
            )))
     (if c-q-hack m (message "%s" m))))
 
-(defun isearch-message-prefix (&optional c-q-hack ellipsis)
+(defun isearch-message-prefix (&optional c-q-hack ellipsis nonincremental)
   ;; If about to search, and previous search regexp was invalid,
   ;; check that it still is.  If it is valid now,
   ;; let the message we display while searching say that it is valid.
@@ -991,8 +1266,9 @@ Does nothing if the last store was for the same window."
   (or isearch-success (setq ellipsis nil))
   (let ((m (concat (if isearch-success "" "failing ")
                   (if isearch-wrapped "wrapped ")
+                  (if isearch-word "word " "")
                   (if isearch-regexp "regexp " "")
-                  "I-search"
+                  (if nonincremental "search" "I-search")
                   (if isearch-forward ": " " backward: ")
                   )))
     (aset m 0 (upcase (aref m 0)))
@@ -1012,21 +1288,29 @@ Does nothing if the last store was for the same window."
 (defun isearch-search ()
   ;; Do the search with the current search string.
   (isearch-message nil t)
+  (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))
        (if isearch-regexp (setq isearch-invalid-regexp nil))
        (setq isearch-success
              (funcall
-              (if isearch-regexp
-                  (if isearch-forward 're-search-forward 're-search-backward)
-                (if isearch-forward 'search-forward 'search-backward))
+              (cond (isearch-word
+                     (if isearch-forward
+                         'word-search-forward 'word-search-backward))
+                    (isearch-regexp
+                     (if isearch-forward
+                         're-search-forward 're-search-backward))
+                    (t
+                     (if isearch-forward 'search-forward 'search-backward)))
               isearch-string nil t))
        (if isearch-success
            (setq isearch-other-end
                  (if isearch-forward (match-beginning 0) (match-end 0)))))
 
-    (quit (setq unread-command-char ?\C-g)
+    (quit (isearch-unread ?\C-g)
          (setq isearch-success nil))
 
     (invalid-regexp 
@@ -1034,7 +1318,10 @@ Does nothing if the last store was for the same window."
      (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
@@ -1043,56 +1330,77 @@ Does nothing if the last store was for the same window."
         (ding))
     (goto-char (nth 2 (car isearch-cmds)))))
 
-;;;=================================================
-;; This is called from incremental-search
-;; if the first input character is the exit character.
 
-;; We store the search string in `isearch-string'
-;; which has been bound already by `isearch-search'
-;; so that, when we exit, it is copied into `search-last-string'.
+\f
+;;;========================================================
+;;; Highlighting
+
+(defvar isearch-overlay nil)
 
-(defun nonincremental-search (forward regexp)
-  ;; This may be broken.  Anyway, it could be replaced by the
-  ;; isearch-edit-string command instead.
-  (setq isearch-forward forward
-       isearch-regexp regexp)
-  (let (char function
-       inhibit-quit
-       (cursor-in-echo-area t))
-    ;; Prompt assuming not word search,
-    (setq isearch-message 
-
-         (if isearch-regexp 
-
-             (if isearch-forward "Regexp search: "
-               "Regexp search backward: ")
-           (if isearch-forward "Search: " "Search backward: ")))
-    (message "%s" isearch-message)
-    ;; Read 1 char and switch to word search if it is ^W.
-    (setq char (read-char))
-    (if (eq char search-yank-word-char)
-       (setq isearch-message (if isearch-forward "Word search: " 
-
-                               "Word search backward: "))
-      ;; Otherwise let that 1 char be part of the search string.
-      (setq unread-command-char char))
-    (setq function
-         (if (eq char search-yank-word-char)
-             (if isearch-forward 'word-search-forward 'word-search-backward)
-           (if isearch-regexp
-               (if isearch-forward 're-search-forward 're-search-backward)
-             (if isearch-forward 'search-forward 'search-backward))))
-    ;; Read the search string with corrected prompt.
-    (setq isearch-string (read-string isearch-message isearch-string))
-    ;; Empty means use default.
-    (if (= 0 (length isearch-string))
-       (setq isearch-string search-last-string)
-      ;; Set last search string now so it is set even if we fail.
-      (setq search-last-string isearch-string))
-    ;; Since we used the minibuffer, we should be available for redo.
-    (setq command-history 
-
-         (cons (list function isearch-string) command-history))
-    ;; Go ahead and search.
-    (let ((case-fold-search isearch-case-fold-search))
-      (funcall function isearch-string))))
+(defun isearch-highlight (beg end)
+  (if (null search-highlight)
+      nil
+    (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
+
+
+(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 (if regexp-flag "\\(^\\|\\\\\\\\\\|[^\\]\\)[A-Z]"
+                        "[A-Z]")
+                      string))))
+
+
+;;;=================================================
+;; 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)
+    (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 (&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-event-data-type
+      last-command-event
+    last-command-char))
+
+;;; isearch.el ends here