]> code.delx.au - gnu-emacs/blobdiff - lisp/isearch.el
(Flookup_key, Faccessible_keymaps, describe_vector,
[gnu-emacs] / lisp / isearch.el
index 9e5ad7d4a2e477094ca257bdb44e7020a56c25e5..bb0afebb8ec9b46fdc2b5ea86587e7b38c028994 100644 (file)
@@ -1,6 +1,6 @@
 ;;; isearch.el --- incremental search minor mode.
 
-;; Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+;; Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
 
 ;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
 ;; Maintainer: FSF
 \f
 ;;; Some additional options and constants.
 
-(defvar search-exit-option t
-  "*Non-nil means random control characters terminate incremental search.")
+(defgroup isearch nil
+  "Incremental search minor mode."
+  :prefix "isearch-"
+  :prefix "search-"
+  :group 'matching)
 
-(defvar search-slow-window-lines 1
+
+(defcustom search-exit-option t
+  "*Non-nil means random control characters terminate incremental search."
+  :type 'boolean
+  :group 'isearch)
+
+(defcustom 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.")
+and the value is minus the number of lines."
+  :type 'integer
+  :group 'isearch)
 
-(defvar search-slow-speed 1200
+(defcustom 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.")
+that the search has reached."
+  :type 'integer
+  :group 'isearch)
 
-(defvar search-upper-case 'not-yanks
+(defcustom 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 in regexps that are prefixed with `\\'.
-If this value is `not-yanks', yanked text is always downcased.")
+If this value is `not-yanks', yanked text is always downcased."
+  :type '(choice (const :tag "off" nil)
+                (const not-yanks)
+                (other :tag "on" t))
+  :group 'isearch)
 
-(defvar search-nonincremental-instead t
+(defcustom search-nonincremental-instead t
   "*If non-nil, do a nonincremental search instead if exiting immediately.
 Actually, `isearch-edit-string' is called to let you enter the search
-string, and RET terminates editing and does a nonincremental search.")
+string, and RET terminates editing and does a nonincremental search."
+  :type 'boolean
+  :group 'isearch)
 
-(defvar search-whitespace-regexp "\\s-+"
+(defcustom 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.")
-
-(defvar search-highlight nil
-  "*Non-nil means incremental search highlights the current match.")
-
-(defvar search-invisible nil
-  "*Non-nil means incremental search can match text hidden by an overlay.
-\(This applies when using `noutline.el'.)")
+This applies to regular expression incremental search.
+You might want to use something like \"[ \\t\\r\\n]+\" instead.
+In the Customization buffer, that is `[' followed by a space,
+a tab, a carriage return (control-M), a newline, and `]+'."
+  :type 'regexp
+  :group 'isearch)
+
+(defcustom search-highlight t
+  "*Non-nil means incremental search highlights the current match."
+  :type 'boolean
+  :group 'isearch)
+
+(defcustom search-invisible 'open
+  "If t incremental search can match hidden text.
+nil means don't match invisible text.
+If the value is `open', if the text matched is made invisible by
+an overlay having an `invisible' property and that overlay has a property
+`isearch-open-invisible', then incremental search will show the contents.
+\(This applies when using `outline.el' and `hideshow.el'.)"
+  :type '(choice (const :tag "Match hidden text" t)
+                (const :tag "Open overlays" open)
+                (const :tag "Don't match hidden text" nil))
+  :group 'isearch)
+
+(defcustom isearch-hide-immediately t
+  "If non-nil, re-hide an invisible match right away.
+This variable makes a difference when `search-invisible' is set to `open'.
+It means that after search makes some invisible text visible
+to show the match, it makes the text invisible again when the match moves.
+Ordinarily the text becomes invisible again at the end of the search."  
+  :type 'boolean 
+  :group 'isearch)
 
 (defvar isearch-mode-hook nil
   "Function(s) to call after starting up an incremental search.")
@@ -155,10 +198,14 @@ You might want to use something like \"[ \\t\\r\\n]+\" instead.")
 (defvar regexp-search-ring nil
   "List of regular expression search string sequences.")
 
-(defvar search-ring-max 16
-  "*Maximum length of search ring before oldest elements are thrown away.")
-(defvar regexp-search-ring-max 16
-  "*Maximum length of regexp search ring before oldest elements are thrown away.")
+(defcustom search-ring-max 16
+  "*Maximum length of search ring before oldest elements are thrown away."
+  :type 'integer
+  :group 'isearch)
+(defcustom regexp-search-ring-max 16
+  "*Maximum length of regexp search ring before oldest elements are thrown away."
+  :type 'integer
+  :group 'isearch)
 
 (defvar search-ring-yank-pointer nil
   "Index in `search-ring' of last string reused.
@@ -167,9 +214,11 @@ nil if none yet.")
   "Index in `regexp-search-ring' of last string reused.
 nil if none yet.")
 
-(defvar search-ring-update nil
+(defcustom 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.")
+Default value, nil, means edit the string instead."
+  :type 'boolean
+  :group 'isearch)
 
 ;;; Define isearch-mode keymap.
 
@@ -180,11 +229,14 @@ Default value, nil, means edit the string instead.")
     (let* ((i 0)
           (map (make-keymap)))
       (or (vectorp (nth 1 map))
+         (char-table-p (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 all multibyte characters search for themselves.
+      (let ((l (generic-character-list))
+           (table (nth 1 map)))
+       (while l
+         (set-char-table-default table (car l) 'isearch-printing-char)
+         (setq l (cdr l))))
       ;; Make function keys, etc, exit the search.
       (define-key map [t] 'isearch-other-control-char)
       ;; Control chars, by default, end isearch mode transparently.
@@ -195,9 +247,9 @@ Default value, nil, means edit the string instead.")
        (define-key map (make-string 1 i) 'isearch-other-control-char)
        (setq i (1+ i)))
 
-      ;; Printing chars extend the search string by default.
+      ;; Single-byte printing chars extend the search string by default.
       (setq i ?\ )
-      (while (< i (length (nth 1 map)))
+      (while (< i 256)
        (define-key map (vector i) 'isearch-printing-char)
        (setq i (1+ i)))
 
@@ -228,6 +280,7 @@ Default value, nil, means edit the string instead.")
       (define-key map "\C-j" 'isearch-printing-char)
       (define-key map "\t" 'isearch-printing-char)
       (define-key map " " 'isearch-whitespace-chars)
+      (define-key map [?\S-\ ] 'isearch-whitespace-chars)
     
       (define-key map "\C-w" 'isearch-yank-word)
       (define-key map "\C-y" 'isearch-yank-line)
@@ -255,6 +308,14 @@ Default value, nil, means edit the string instead.")
       (define-key map [delete-frame] nil)
       (define-key map [iconify-frame] nil)
       (define-key map [make-frame-visible] nil)
+      ;; For searching multilingual text.
+      (define-key map "\C-\\" 'isearch-toggle-input-method)
+      (define-key map "\C-^" 'isearch-toggle-specified-input-method)
+
+;;; I think the normal meaning of Mouse-2 is more natural.
+;;;       ;; People expect to be able to paste with the mouse.
+;;;       (define-key map [mouse-2] #'isearch-yank-kill)
+;;;       (define-key map [down-mouse-2] nil)
 
       (setq isearch-mode-map map)
       ))
@@ -330,6 +391,15 @@ Default value, nil, means edit the string instead.")
 ;; New value of isearch-forward after isearch-edit-string.
 (defvar isearch-new-forward nil)
 
+;; Accumulate here the overlays opened during searching.
+(defvar isearch-opened-overlays nil)
+
+;; The value of input-method-function when isearch is invoked.
+(defvar isearch-input-method-function nil)
+
+;; A flag to tell if input-method-function is locally bound when
+;; isearch is invoked.
+(defvar isearch-input-method-local-p nil)
 
 ;; Minor-mode-alist changes - kind of redundant with the
 ;; echo area, but if isearching in multiple windows, it can be useful.
@@ -368,7 +438,8 @@ 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-yank-kill] to yank the last string of killed text.
+Type \\[isearch-yank-kill] to yank last killed text onto end of search string\
+ and search for it.
 Type \\[isearch-quote-char] to quote control character to search for it.
 \\[isearch-abort] while searching or when search has failed cancels input\
  back to what has
@@ -466,7 +537,18 @@ is treated as a regexp.  See \\[isearch-forward] for more info."
 
        isearch-opoint (point)
        search-ring-yank-pointer nil
+       isearch-opened-overlays nil
+       isearch-input-method-function input-method-function
+       isearch-input-method-local-p (local-variable-p 'input-method-function)
        regexp-search-ring-yank-pointer nil)
+
+  ;; We must bypass input method while reading key.  When a user type
+  ;; printable character, appropriate input method is turned on in
+  ;; minibuffer to read multibyte charactes.
+  (or isearch-input-method-local-p
+      (make-local-variable 'input-method-function))
+  (setq input-method-function nil)
+
   (looking-at "")
   (setq isearch-window-configuration
        (if isearch-slow-terminal-mode (current-window-configuration) nil))
@@ -564,8 +646,23 @@ is treated as a regexp.  See \\[isearch-forward] for more info."
                  (message "Mark saved where search started"))))))
 
   (setq isearch-mode nil)
+  (if isearch-input-method-local-p
+      (setq input-method-function isearch-input-method-function)
+    (kill-local-variable 'input-method-function))
+
   (force-mode-line-update)
 
+  ;; If we ended in the middle of some intangible text,
+  ;; move to the further end of that intangible text.
+  (let ((after (if (eobp) nil
+                (get-text-property (point) 'intangible)))
+       (before (if (bobp) nil
+                 (get-text-property (1- (point)) 'intangible))))
+    (when (and before after (eq before after))
+      (if isearch-forward
+         (goto-char (next-single-property-change (point) 'intangible))
+       (goto-char (previous-single-property-change (point) 'intangible)))))
+
   (if (and (> (length isearch-string) 0) (not nopush))
       ;; Update the ring data.
       (isearch-update-ring isearch-string isearch-regexp))
@@ -601,6 +698,7 @@ REGEXP says which ring to use."
   (interactive) ;; Is this necessary?
   ;; First terminate isearch-mode.
   (isearch-done)
+  (isearch-clean-overlays) 
   (handle-switch-frame (car (cdr (isearch-last-command-char)))))
 
 \f
@@ -616,7 +714,8 @@ nonincremental search instead via `isearch-edit-string'."
           (= 0 (length isearch-string)))
       (let ((isearch-nonincremental t))
        (isearch-edit-string)))
-  (isearch-done))
+  (isearch-done)
+  (isearch-clean-overlays))
 
 
 (defun isearch-edit-string ()
@@ -776,6 +875,7 @@ If first char entered is \\[isearch-yank-word], then do word search instead."
   (interactive)
   (goto-char isearch-opoint)
   (isearch-done t)
+  (isearch-clean-overlays)
   (signal 'quit nil))  ; and pass on quit signal
 
 (defun isearch-abort ()
@@ -791,6 +891,7 @@ Use `isearch-exit' to quit without signaling."
       (progn (goto-char isearch-opoint)
             (setq isearch-success nil)
             (isearch-done t)   ; exit isearch
+            (isearch-clean-overlays)
             (signal 'quit nil))  ; and pass on quit signal
     ;; If search is failing, or has an incomplete regexp,
     ;; rub out until it is once more successful.
@@ -882,53 +983,53 @@ If no previous match was done, just beep."
   (isearch-update))
 
 
-(defun isearch-yank (chunk)
-  ;; Helper for isearch-yank-word and isearch-yank-line
-  ;; CHUNK should be word, line or kill.
-  (let ((string (cond
-                 ((eq chunk 'kill)
-                  (current-kill 0))
-                 (t
-                 (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 'isearch-text-char-description
-                            string ""))
-         ;; Don't move cursor in reverse search.
-         isearch-yank-flag t))
+(defun isearch-yank-string (string)
+  "Pull STRING into search string."
+  ;; 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 'isearch-text-char-description
+                          string ""))
+       ;; Don't move cursor in reverse search.
+       isearch-yank-flag t)
   (isearch-search-and-update))
 
 (defun isearch-yank-kill ()
   "Pull string from kill ring into search string."
   (interactive)
-  (isearch-yank 'kill))
+  (isearch-yank-string (current-kill 0)))
+
+(defun isearch-yank-x-selection ()
+  "Pull current X selection into search string.
+Some users like to put this command on Mouse-2.
+To do that, evaluate these expressions:
+    (define-key isearch-mode-map [down-mouse-2] nil)
+    (define-key isearch-mode-map [mouse-2] 'isearch-yank-x-selection)"
+  (interactive)
+  (isearch-yank-string (x-get-selection)))
 
 (defun isearch-yank-word ()
   "Pull next word from buffer into search string."
   (interactive)
-  (isearch-yank 'word))
+  (isearch-yank-string
+   (save-excursion
+     (and (not isearch-forward) isearch-other-end
+         (goto-char isearch-other-end))
+     (buffer-substring (point) (progn (forward-word 1) (point))))))
 
 (defun isearch-yank-line ()
   "Pull rest of line from buffer into search string."
   (interactive)
-  (isearch-yank 'line))
+  (isearch-yank-string
+   (save-excursion
+     (and (not isearch-forward) isearch-other-end
+         (goto-char isearch-other-end))
+     (buffer-substring (point) (line-end-position)))))
 
 
 (defun isearch-search-and-update ()
@@ -947,16 +1048,23 @@ If no previous match was done, just beep."
     (if (and (not isearch-forward) (not isearch-adjusted)
             (condition-case ()
                 (let ((case-fold-search isearch-case-fold-search))
+                  (if (and (eq case-fold-search t) search-upper-case)
+                      (setq case-fold-search
+                            (isearch-no-upper-case-p isearch-string isearch-regexp)))
                   (looking-at (if isearch-regexp isearch-string
                                 (regexp-quote isearch-string))))
               (error nil))
-              (or isearch-yank-flag
-                  (<= (match-end 0) 
-                      (min isearch-opoint isearch-barrier))))
-       (setq isearch-success t 
-             isearch-invalid-regexp nil
-             isearch-within-brackets nil
-             isearch-other-end (match-end 0))
+            (or isearch-yank-flag
+                (<= (match-end 0) 
+                    (min isearch-opoint isearch-barrier))))
+       (progn
+         (setq isearch-success t 
+               isearch-invalid-regexp nil
+               isearch-within-brackets nil
+               isearch-other-end (match-end 0))
+         (if (and (eq isearch-case-fold-search t) search-upper-case)
+             (setq isearch-case-fold-search
+                   (isearch-no-upper-case-p isearch-string isearch-regexp))))
       ;; Not regexp, not reverse, or no match at point.
       (if (and isearch-other-end (not isearch-adjusted))
          (goto-char (if isearch-forward isearch-other-end
@@ -980,20 +1088,23 @@ If no previous match was done, just beep."
   "Handle * and ? specially in regexps."
   (interactive)
   (if isearch-regexp 
-
-      (progn
-       (setq isearch-adjusted t)
-       ;; Get the isearch-other-end from before the last search.
-       ;; We want to start from there,
-       ;; so that we don't retreat farther than that.
-       ;; (car isearch-cmds) is after last search;
-       ;; (car (cdr isearch-cmds)) is from before it.
-       (let ((cs (nth 5 (car (cdr isearch-cmds)))))
-         (setq cs (or cs isearch-barrier))
-         (goto-char
-          (if isearch-forward
-              (max cs isearch-barrier)
-            (min cs isearch-barrier))))))
+      (let ((idx (length isearch-string)))
+       (while (and (> idx 0)
+                   (eq (aref isearch-string (1- idx)) ?\\))
+         (setq idx (1- idx)))
+       (when (= (mod (- (length isearch-string) idx) 2) 0)
+         (setq isearch-adjusted t)
+         ;; Get the isearch-other-end from before the last search.
+         ;; We want to start from there,
+         ;; so that we don't retreat farther than that.
+         ;; (car isearch-cmds) is after last search;
+         ;; (car (cdr isearch-cmds)) is from before it.
+         (let ((cs (nth 5 (car (cdr isearch-cmds)))))
+           (setq cs (or cs isearch-barrier))
+           (goto-char
+            (if isearch-forward
+                (max cs isearch-barrier)
+              (min cs isearch-barrier)))))))
   (isearch-process-search-char (isearch-last-command-char)))
   
 
@@ -1078,18 +1189,30 @@ and the meta character is unread so that it applies to editing the string."
             ;; is in isearch mode.  So end the search in that buffer.
             (if (and (listp main-event)
                      (setq window (posn-window (event-start main-event)))
-                     (windowp window))
+                     (windowp window)
+                     (or (> (minibuffer-depth) 0)
+                         (not (window-minibuffer-p window))))
                 (save-excursion
                   (set-buffer (window-buffer window))
-                  (isearch-done))
-              (isearch-done))))
+                  (isearch-done)
+                  (isearch-clean-overlays))
+              (isearch-done)
+              (isearch-clean-overlays))))
          (t;; otherwise nil
           (isearch-process-search-string key key)))))
 
 (defun isearch-quote-char ()
   "Quote special characters for incremental search."
   (interactive)
-  (isearch-process-search-char (read-quoted-char (isearch-message t))))
+  (let ((char (read-quoted-char (isearch-message t))))
+    ;; Assume character codes 0200 - 0377 stand for characters in some
+    ;; single-byte character set, and convert them to Emacs
+    ;; characters.
+    (and enable-multibyte-characters
+        (>= char ?\200)
+        (<= char ?\377)
+        (setq char (unibyte-char-to-multibyte char)))
+    (isearch-process-search-char char)))
 
 (defun isearch-return-char ()
   "Convert return into newline for incremental search.
@@ -1100,7 +1223,16 @@ Obsolete."
 (defun isearch-printing-char ()
   "Add this ordinary printing character to the search string and search."
   (interactive)
-  (isearch-process-search-char (isearch-last-command-char)))
+  (let ((char (isearch-last-command-char)))
+    (if (= char ?\S-\ )
+       (setq char ?\ ))
+    (if (and enable-multibyte-characters
+            (>= char ?\200)
+            (<= char ?\377))
+       (isearch-process-search-char (unibyte-char-to-multibyte char))
+      (if current-input-method
+         (isearch-process-search-multibyte-characters char)
+       (isearch-process-search-char char)))))
 
 (defun isearch-whitespace-chars ()
   "Match all whitespace chars, if in regexp mode.
@@ -1122,7 +1254,9 @@ If you want to search for just a space, type C-q SPC."
   ;; Append the char to the search string, update the message and re-search.
   (isearch-process-search-string 
    (isearch-char-to-string char) 
-   (isearch-text-char-description char)))
+   (if (>= char ?\200)
+       (char-to-string char)
+     (isearch-text-char-description char))))
 
 (defun isearch-process-search-string (string message)
   (setq isearch-string (concat isearch-string string)
@@ -1331,7 +1465,10 @@ If there is no completion possible, say so and continue searching."
                   (if isearch-word "word " "")
                   (if isearch-regexp "regexp " "")
                   (if nonincremental "search" "I-search")
-                  (if isearch-forward ": " " backward: ")
+                  (if isearch-forward "" " backward")
+                  (if current-input-method
+                      (concat " [" current-input-method-title "]: ")
+                    ": ")
                   )))
     (aset m 0 (upcase (aref m 0)))
     m))
@@ -1353,7 +1490,8 @@ If there is no completion possible, say so and continue searching."
       (setq isearch-case-fold-search
            (isearch-no-upper-case-p isearch-string isearch-regexp)))
   (condition-case lossage
-      (let ((inhibit-quit nil)
+      (let ((inhibit-point-motion-hooks search-invisible)
+           (inhibit-quit nil)
            (case-fold-search isearch-case-fold-search)
            (retry t))
        (if isearch-regexp (setq isearch-invalid-regexp nil))
@@ -1372,7 +1510,7 @@ If there is no completion possible, say so and continue searching."
                 isearch-string nil t))
          ;; Clear RETRY unless we matched some invisible text
          ;; and we aren't supposed to do that.
-         (if (or search-invisible
+         (if (or (eq search-invisible t)
                  (not isearch-success)
                  (bobp) (eobp)
                  (= (match-beginning 0) (match-end 0))
@@ -1406,28 +1544,151 @@ If there is no completion possible, say so and continue searching."
         (ding))
     (goto-char (nth 2 (car isearch-cmds)))))
 
+
+;;; Called when opening an overlay, and we are still in isearch.
+(defun isearch-open-overlay-temporary (ov)
+  (if (not (null (overlay-get ov 'isearch-open-invisible-temporary))) 
+      ;; Some modes would want to open the overlays temporary during
+      ;; isearch in their own way, they should set the
+      ;; `isearch-open-invisible-temporary' to a function doing this.
+      (funcall  (overlay-get ov 'isearch-open-invisible-temporary)  ov nil)
+    ;; Store the values for the `invisible' and `intangible'
+    ;; properties, and then set them to nil. This way the text hidden
+    ;; by this overlay becomes visible.
+
+    ;; Do we realy need to set the `intangible' property to t? Can we
+    ;; have the point inside an overlay with an `intangible' property?
+    ;; In 19.34 this does not exist so I cannot test it.
+    (overlay-put ov 'isearch-invisible (overlay-get ov 'invisible))
+    (overlay-put ov 'isearch-intangible (overlay-get ov 'intangible))
+    (overlay-put ov 'invisible nil)
+    (overlay-put ov 'intangible nil)))
+
+
+;;; This is called at the end of isearch. I will open the overlays
+;;; that contain the latest match. Obviously in case of a C-g the
+;;; point returns to the original location which surely is not contain
+;;; in any of these overlays, se we are safe in this case too.
+(defun isearch-open-necessary-overlays (ov)
+  (let ((inside-overlay (and  (> (point) (overlay-start ov)) 
+                             (< (point) (overlay-end ov))))
+       ;; If this exists it means that the overlay was opened using
+       ;; this function, not by us tweaking the overlay properties.
+       (fct-temp (overlay-get ov 'isearch-open-invisible-temporary)))
+    (when (or inside-overlay (not fct-temp))
+      ;; restore the values for the `invisible' and `intangible'
+      ;; properties
+      (overlay-put ov 'invisible (overlay-get ov 'isearch-invisible))
+      (overlay-put ov 'intangible (overlay-get ov 'isearch-intangible))
+      (overlay-put ov 'isearch-invisible nil)
+      (overlay-put ov 'isearch-intangible nil))
+    (if inside-overlay
+       (funcall (overlay-get ov 'isearch-open-invisible)  ov)
+      (if fct-temp
+         (funcall fct-temp ov t)))))
+
+;;; This is called when exiting isearch. It closes the temporary
+;;; opened overlays, except the ones that contain the latest match.
+(defun isearch-clean-overlays ()
+  (when isearch-opened-overlays
+    ;; Use a cycle instead of a mapcar here?
+    (mapcar 
+     (function isearch-open-necessary-overlays) isearch-opened-overlays)
+    (setq isearch-opened-overlays nil)))
+
+;;; Verify if the current match is outside of each element of
+;;; `isearch-opened-overlays', if so close that overlay.
+(defun isearch-close-unecessary-overlays (begin end)
+  (let ((ov-list isearch-opened-overlays)
+       ov
+       inside-overlay
+       fct-temp)
+    (setq isearch-opened-overlays nil)
+    (while ov-list
+      (setq ov (car ov-list))
+      (setq ov-list (cdr ov-list))
+      (setq inside-overlay (or (and  (> begin (overlay-start ov)) 
+                                    (< begin (overlay-end ov)))
+                              (and  (> end (overlay-start ov)) 
+                                    (< end (overlay-end ov)))))
+      ;; If this exists it means that the overlay was opened using
+      ;; this function, not by us tweaking the overlay properties.
+      (setq fct-temp (overlay-get ov 'isearch-open-invisible-temporary))
+      (if inside-overlay
+       (setq isearch-opened-overlays (cons ov isearch-opened-overlays))
+       (if fct-temp
+           (funcall fct-temp ov t)
+         (overlay-put ov 'invisible (overlay-get ov 'isearch-invisible))
+         (overlay-put ov 'intangible (overlay-get ov 'isearch-intangible))
+         (overlay-put ov 'isearch-invisible nil)
+         (overlay-put ov 'isearch-intangible nil))))))
+
 (defun isearch-range-invisible (beg end)
-  "Return t if all the bext from BEG to END is invisible."
+  "Return t if all the text from BEG to END is invisible."
   (and (/= beg end)
        ;; Check that invisibility runs up to END.
        (save-excursion
         (goto-char beg)
-        ;; If the following character is currently invisible,
-        ;; skip all characters with that same `invisible' property value.
-        ;; Do that over and over.
-        (while (and (< (point) end)
-                    (let ((prop
-                           (get-char-property (point) 'invisible)))
-                      (if (eq buffer-invisibility-spec t)
-                          prop
-                        (or (memq prop buffer-invisibility-spec)
-                            (assq prop buffer-invisibility-spec)))))
-          (if (get-text-property (point) 'invisible)
-              (goto-char (next-single-property-change (point) 'invisible
-                                                      nil end))
-            (goto-char (next-overlay-change (point)))))
+        (let (
+              ;; can-be-opened keeps track if we can open some overlays.
+              (can-be-opened (eq search-invisible 'open))
+              ;; the list of overlays that could be opened
+              (crt-overlays nil))
+          (when (and can-be-opened isearch-hide-immediately) 
+            (isearch-close-unecessary-overlays beg end))
+          ;; If the following character is currently invisible,
+          ;; skip all characters with that same `invisible' property value.
+          ;; Do that over and over.
+          (while (and (< (point) end)
+                      (let ((prop
+                             (get-char-property (point) 'invisible)))
+                        (if (eq buffer-invisibility-spec t)
+                            prop
+                          (or (memq prop buffer-invisibility-spec)
+                              (assq prop buffer-invisibility-spec)))))
+            (if (get-text-property (point) 'invisible)
+                (progn 
+                  (goto-char (next-single-property-change (point) 'invisible
+                                                          nil end))
+                  ;; if text is hidden by an `invisible' text property
+                  ;; we cannot open it at all.
+                  (setq can-be-opened nil))
+              (unless (null can-be-opened)
+                (let ((overlays (overlays-at (point)))
+                      ov-list
+                      o
+                      invis-prop)
+                  (while overlays
+                    (setq o (car overlays)
+                          invis-prop (overlay-get o 'invisible))
+                    (if (if (eq buffer-invisibility-spec t)
+                            invis-prop
+                          (or (memq invis-prop buffer-invisibility-spec)
+                              (assq invis-prop buffer-invisibility-spec)))
+                        (if (overlay-get o 'isearch-open-invisible)
+                            (setq ov-list (cons o ov-list))
+                          ;; We found one overlay that cannot be
+                          ;; opened, that means the whole chunk
+                          ;; cannot be opened.
+                          (setq can-be-opened nil)))
+                    (setq overlays (cdr overlays)))
+                  (if can-be-opened 
+                      ;; It makes sense to append to the open
+                      ;; overlays list only if we know that this is
+                      ;; t.
+                      (setq crt-overlays (append ov-list crt-overlays)))))
+              (goto-char (next-overlay-change (point)))))
         ;; See if invisibility reaches up thru END.
-        (>= (point) end))))
+        (if (>= (point) end)
+            (if (and (not (null can-be-opened)) (consp crt-overlays))
+                (progn
+                  (setq isearch-opened-overlays
+                        (append isearch-opened-overlays crt-overlays))
+                  ;; maybe use a cycle instead of mapcar?
+                  (mapcar (function isearch-open-overlay-temporary)
+                          crt-overlays)
+                  nil)
+              t))))))
 
 \f
 ;;; Highlighting
@@ -1467,7 +1728,7 @@ since they have special meaning in a regexp."
 ;; Portability functions to support various Emacs versions.
 
 (defun isearch-char-to-string (c)
-  (make-string 1 c))
+  (char-to-string c))
 
 (defun isearch-text-char-description (c)
   (if (and (integerp c) (or (< c ?\ ) (= c ?\^?)))