]> code.delx.au - gnu-emacs/blobdiff - lisp/isearch.el
* w32-fns.el (w32-shell-dos-semantics):
[gnu-emacs] / lisp / isearch.el
index 750ed129b7e02dfcdf00006c7f6b2e4571db0d17..c343472767768f511bf6622f087a1a13a342ce5c 100644 (file)
@@ -9,10 +9,10 @@
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,9 +20,7 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -178,6 +176,12 @@ or to the end of the buffer for a backward search.")
   "Function to save a function restoring the mode-specific isearch state
 to the search status stack.")
 
+(defvar isearch-success-function 'isearch-success-function-default
+  "Function to report whether the new search match is considered successful.
+The function has two arguments: the positions of start and end of text
+matched by the search.  If this function returns nil, continue
+searching without stopping at this match.")
+
 ;; Search ring.
 
 (defvar search-ring nil
@@ -321,6 +325,73 @@ A value of nil means highlight all matches."
 (define-obsolete-variable-alias 'isearch-lazy-highlight-face
                                 'lazy-highlight-face
                                 "22.1")
+\f
+;; Define isearch help map.
+
+(defvar isearch-help-map
+  (let ((i 0)
+       (map (make-sparse-keymap)))
+    (define-key map [t] 'isearch-other-control-char)
+    (define-key map (char-to-string help-char) 'isearch-help-for-help)
+    (define-key map [help] 'isearch-help-for-help)
+    (define-key map [f1] 'isearch-help-for-help)
+    (define-key map "?" 'isearch-help-for-help)
+    (define-key map "b" 'isearch-describe-bindings)
+    (define-key map "k" 'isearch-describe-key)
+    (define-key map "m" 'isearch-describe-mode)
+    (define-key map "q" 'help-quit)
+    map)
+  "Keymap for characters following the Help key for isearch mode.")
+
+(eval-when-compile (require 'help-macro))
+
+(make-help-screen isearch-help-for-help-internal
+  "Type a help option: [bkm] or ?"
+  "You have typed %THIS-KEY%, the help character.  Type a Help option:
+\(Type \\<help-map>\\[help-quit] to exit the Help command.)
+
+b           Display all isearch key bindings.
+k KEYS      Display full documentation of isearch key sequence.
+m           Display documentation of isearch mode.
+
+You can't type here other help keys available in the global help map,
+but outise of this help window when you type them in isearch mode,
+they exit isearch mode before displaying global help."
+  isearch-help-map)
+
+(defun isearch-help-for-help ()
+  "Display isearch help menu."
+  (interactive)
+  (let (same-window-buffer-names same-window-regexps)
+    (isearch-help-for-help-internal))
+  (isearch-update))
+
+(defun isearch-describe-bindings ()
+  "Show a list of all keys defined in isearch mode, and their definitions.
+This is like `describe-bindings', but displays only isearch keys."
+  (interactive)
+  (let (same-window-buffer-names same-window-regexps)
+    (with-help-window "*Help*"
+      (with-current-buffer standard-output
+       (princ "Isearch Mode Bindings:\n")
+       (princ (substitute-command-keys "\\{isearch-mode-map}"))))))
+
+(defun isearch-describe-key ()
+  "Display documentation of the function invoked by isearch key."
+  (interactive)
+  (let (same-window-buffer-names same-window-regexps)
+    (call-interactively 'describe-key))
+  (isearch-update))
+
+(defun isearch-describe-mode ()
+  "Display documentation of isearch mode."
+  (interactive)
+  (let (same-window-buffer-names same-window-regexps)
+    (describe-function 'isearch-forward))
+  (isearch-update))
+
+(defalias 'isearch-mode-help 'isearch-describe-mode)
+
 \f
 ;; Define isearch-mode keymap.
 
@@ -388,9 +459,7 @@ A value of nil means highlight all matches."
     (define-key map "\M-\C-y" 'isearch-yank-char)
     (define-key map    "\C-y" 'isearch-yank-line)
 
-    ;; 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)
+    (define-key map "\C-h" isearch-help-map)
 
     (define-key map "\M-n" 'isearch-ring-advance)
     (define-key map "\M-p" 'isearch-ring-retreat)
@@ -422,9 +491,13 @@ A value of nil means highlight all matches."
     (define-key map "\M-r" 'isearch-toggle-regexp)
     (define-key map "\M-e" 'isearch-edit-string)
 
+    (define-key map "\M-sr" 'isearch-toggle-regexp)
+    (define-key map "\M-sw" 'isearch-toggle-word)
+
     (define-key map [?\M-%] 'isearch-query-replace)
     (define-key map [?\C-\M-%] 'isearch-query-replace-regexp)
     (define-key map "\M-so" 'isearch-occur)
+    (define-key map "\M-shr" 'isearch-highlight-regexp)
 
     map)
   "Keymap for `isearch-mode'.")
@@ -436,6 +509,7 @@ A value of nil means highlight all matches."
     (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)
+    (define-key map "\C-w"  'isearch-edit-string-set-word)
     (define-key map "\C-f"  'isearch-yank-char-in-minibuffer)
     (define-key map [right] 'isearch-yank-char-in-minibuffer)
     map)
@@ -459,6 +533,9 @@ Each set is a vector of the form:
 (defvar isearch-string "")  ; The current search string.
 (defvar isearch-message "") ; text-char-description version of isearch-string
 
+(defvar isearch-message-prefix-add nil) ; Additonal text for the message prefix
+(defvar isearch-message-suffix-add nil) ; Additonal text for the message suffix
+
 (defvar isearch-success t)     ; Searching is currently successful.
 (defvar isearch-error nil)     ; Error message for failed search.
 (defvar isearch-other-end nil) ; Start (end) of match if forward (backward).
@@ -526,6 +603,7 @@ Each set is a vector of the form:
 (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)
+(define-key search-map "w" 'isearch-forward-word)
 
 ;; Entry points to isearch-mode.
 
@@ -560,13 +638,9 @@ Type \\[isearch-quote-char] to quote control character to search for it.
 If you try to exit with the search string still empty, it invokes
  nonincremental search.
 
-Type \\[isearch-query-replace] to start `query-replace' with string to\
- replace from last search string.
-Type \\[isearch-query-replace-regexp] to start `query-replace-regexp'\
- with string to replace from last search string.
-
 Type \\[isearch-toggle-case-fold] to toggle search case-sensitivity.
 Type \\[isearch-toggle-regexp] to toggle regular-expression mode.
+Type \\[isearch-toggle-word] to toggle word mode.
 Type \\[isearch-edit-string] to edit the search string in the minibuffer.
 
 Also supported is a search ring of the previous 16 search strings.
@@ -575,6 +649,19 @@ 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.
 
+Type \\[isearch-query-replace] to run `query-replace' with string to\
+ replace from last search string.
+Type \\[isearch-query-replace-regexp] to run `query-replace-regexp'\
+ with the last search string.
+Type \\[isearch-occur] to run `occur' that shows\
+ the last search string.
+Type \\[isearch-highlight-regexp] to run `highlight-regexp'\
+ that highlights the last search string.
+
+Type \\[isearch-describe-bindings] to display all isearch key bindings.
+Type \\[isearch-describe-key] to display documentation of isearch key.
+Type \\[isearch-describe-mode] to display documentation of isearch mode.
+
 If an input method is turned on in the current buffer, that input
 method is also active while you are typing characters to search.  To
 toggle the input method, type \\[isearch-toggle-input-method].  It
@@ -600,8 +687,8 @@ the calling function until the search is done."
   "\
 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.
+Like ordinary incremental search except that your input is treated
+as a regexp.  See the command `isearch-forward' for more information.
 
 In regexp incremental searches, a space or spaces normally matches
 any whitespace (the variable `search-whitespace-regexp' controls
@@ -610,11 +697,21 @@ and nothing else, enter C-q SPC."
   (interactive "P\np")
   (isearch-mode t (null not-regexp) nil (not no-recursive-edit)))
 
+(defun isearch-forward-word (&optional not-word no-recursive-edit)
+  "\
+Do incremental search forward for a sequence of words.
+With a prefix argument, do a regular string search instead.
+Like ordinary incremental search except that your input is treated
+as a sequence of words without regard to how the words are separated.
+See the command `isearch-forward' for more information."
+  (interactive "P\np")
+  (isearch-mode t nil nil (not no-recursive-edit) (null not-word)))
+
 (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."
+See the command `isearch-forward' for more information."
   (interactive "P\np")
   (isearch-mode nil (not (null regexp-p)) nil (not no-recursive-edit)))
 
@@ -622,17 +719,11 @@ See \\[isearch-forward] for more information."
   "\
 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."
+Like ordinary incremental search except that your input is treated
+as a regexp.  See the command `isearch-forward' for more information."
   (interactive "P\np")
   (isearch-mode nil (null not-regexp) nil (not no-recursive-edit)))
 
-
-(defun isearch-mode-help ()
-  (interactive)
-  (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.
@@ -644,9 +735,8 @@ is treated as a regexp.  See \\[isearch-forward] for more info."
 
 
 (defun isearch-mode (forward &optional regexp op-fun recursive-edit word-p)
-  "Start isearch minor mode.  Called by `isearch-forward', etc.
-
-\\{isearch-mode-map}"
+  "Start isearch minor mode.
+It is called by the function `isearch-forward' and other related functions."
 
   ;; Initialize global vars.
   (setq isearch-forward forward
@@ -1025,37 +1115,21 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst
          ;; that can change their values.
          (setq old-point (point) old-other-end isearch-other-end)
 
-         (isearch-message) ;; for read-char
          (unwind-protect
-             (let* (;; Why does following read-char echo?
-                    ;;(echo-keystrokes 0) ;; not needed with above message
-                    (e (let ((cursor-in-echo-area t))
-                         (read-event)))
+             (let* ((message-log-max nil)
                     ;; Binding minibuffer-history-symbol to nil is a work-around
                     ;; for some incompatibility with gmhist.
-                    (minibuffer-history-symbol)
-                    (message-log-max nil))
-               ;; 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 "%s" (isearch-message-prefix nil nil t))
-               (if (memq (lookup-key isearch-mode-map (vector e))
-                         '(isearch-yank-word
-                           isearch-yank-word-or-char))
-                   (setq isearch-word t;; so message-prefix is right
-                         isearch-new-word t)
-                 (cancel-kbd-macro-events)
-                 (isearch-unread e))
-               (setq cursor-in-echo-area nil)
+                    (minibuffer-history-symbol))
                (setq isearch-new-string
                       (read-from-minibuffer
                        (isearch-message-prefix nil nil isearch-nonincremental)
                        isearch-string
                        minibuffer-local-isearch-map nil
-                       (if isearch-regexp 'regexp-search-ring 'search-ring)
+                       (if isearch-regexp
+                          (cons 'regexp-search-ring
+                                (1+ (or regexp-search-ring-yank-pointer -1)))
+                        (cons 'search-ring
+                              (1+ (or search-ring-yank-pointer -1))))
                        nil t)
                      isearch-new-message
                      (mapconcat 'isearch-text-char-description
@@ -1096,12 +1170,15 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst
            ;; Only the string actually used should be saved.
            ))
 
-       ;; Push the state as of before this C-s.
-       (isearch-push-state)
+       ;; This used to push the state as of before this C-s, but it adds
+       ;; an inconsistent state where part of variables are from the
+       ;; previous search (e.g. `isearch-success'), and part of variables
+       ;; are just entered from the minibuffer (e.g. `isearch-string').
+       ;; (isearch-push-state)
 
        ;; Reinvoke the pending search.
        (isearch-search)
-       (isearch-push-state)
+       (isearch-push-state)            ; this pushes the correct state
        (isearch-update)
        (if isearch-nonincremental
            (progn
@@ -1116,6 +1193,15 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst
      (isearch-abort)  ;; outside of let to restore outside global values
      )))
 
+;; Obsolete usage of `C-s M-e C-w'.  Remove after 23.1.
+(defvar isearch-new-word)
+(defun isearch-edit-string-set-word ()
+  "Do word search after exiting `isearch-edit-string'."
+  (interactive)
+  (message "This feature is obsolete since 23.1; use `M-s w' instead.")
+  (setq isearch-word t isearch-new-word t))
+
+
 (defun isearch-nonincremental-exit-minibuffer ()
   (interactive)
   (setq isearch-nonincremental t)
@@ -1229,6 +1315,13 @@ Use `isearch-exit' to quit without signaling."
   (setq isearch-success t isearch-adjusted t)
   (isearch-update))
 
+(defun isearch-toggle-word ()
+  "Toggle word searching on or off."
+  (interactive)
+  (setq isearch-word (not isearch-word))
+  (setq isearch-success t isearch-adjusted t)
+  (isearch-update))
+
 (defun isearch-toggle-case-fold ()
   "Toggle case folding in searching on or off."
   (interactive)
@@ -1243,16 +1336,27 @@ Use `isearch-exit' to quit without signaling."
   (sit-for 1)
   (isearch-update))
 
-(defun isearch-query-replace (&optional regexp-flag)
-  "Start `query-replace' with string to replace from last search string."
-  (interactive)
+(defun isearch-query-replace (&optional delimited regexp-flag)
+  "Start `query-replace' with string to replace from last search string.
+The arg DELIMITED (prefix arg if interactive), if non-nil, means replace
+only matches surrounded by word boundaries.  Note that using the prefix arg
+is possible only when `isearch-allow-scroll' is non-nil, and it don't
+always provides the correct matches for `query-replace', so the preferred
+way to run word replacements from Isearch is `M-s w ... M-%'."
+  (interactive
+   (list current-prefix-arg))
   (barf-if-buffer-read-only)
   (if regexp-flag (setq isearch-regexp t))
   (let ((case-fold-search isearch-case-fold-search)
        ;; set `search-upper-case' to nil to not call
        ;; `isearch-no-upper-case-p' in `perform-replace'
-       (search-upper-case nil))
-    (isearch-done)
+       (search-upper-case nil)
+       ;; Set `isearch-recursive-edit' to nil to prevent calling
+       ;; `exit-recursive-edit' in `isearch-done' that terminates
+       ;; the execution of this command when it is non-nil.
+       ;; We call `exit-recursive-edit' explicitly at the end below.
+       (isearch-recursive-edit nil))
+    (isearch-done nil t)
     (isearch-clean-overlays)
     (if (and isearch-other-end
             (< isearch-other-end (point))
@@ -1266,16 +1370,22 @@ Use `isearch-exit' to quit without signaling."
      isearch-string
      (query-replace-read-to
       isearch-string
-      (if isearch-regexp "Query replace regexp" "Query replace")
+      (concat "Query replace"
+             (if (or delimited isearch-word) " word" "")
+             (if isearch-regexp " regexp" "")
+             (if (and transient-mark-mode mark-active) " in region" ""))
       isearch-regexp)
-     t isearch-regexp isearch-word nil nil
+     t isearch-regexp (or delimited isearch-word) nil nil
      (if (and transient-mark-mode mark-active) (region-beginning))
-     (if (and transient-mark-mode mark-active) (region-end)))))
+     (if (and transient-mark-mode mark-active) (region-end))))
+  (and isearch-recursive-edit (exit-recursive-edit)))
 
-(defun isearch-query-replace-regexp ()
-  "Start `query-replace-regexp' with string to replace from last search string."
-  (interactive)
-  (isearch-query-replace t))
+(defun isearch-query-replace-regexp (&optional delimited)
+  "Start `query-replace-regexp' with string to replace from last search string.
+See `isearch-query-replace' for more information."
+  (interactive
+   (list current-prefix-arg))
+  (isearch-query-replace delimited t))
 
 (defun isearch-occur (regexp &optional nlines)
   "Run `occur' with regexp to search from the current search string.
@@ -1283,7 +1393,10 @@ Interactively, REGEXP is the current search regexp or a quoted search
 string.  NLINES has the same meaning as in `occur'."
   (interactive
    (list
-    (if isearch-regexp isearch-string (regexp-quote isearch-string))
+    (cond
+     (isearch-word (concat "\\b" (regexp-quote isearch-string) "\\b"))
+     (isearch-regexp isearch-string)
+     (t (regexp-quote isearch-string)))
     (if current-prefix-arg (prefix-numeric-value current-prefix-arg))))
   (let ((case-fold-search isearch-case-fold-search)
        ;; set `search-upper-case' to nil to not call
@@ -1291,6 +1404,43 @@ string.  NLINES has the same meaning as in `occur'."
        (search-upper-case nil))
     (occur regexp nlines)))
 
+(declare-function hi-lock-regexp-okay "hi-lock" (regexp))
+(declare-function hi-lock-read-face-name "hi-lock" ())
+
+(defun isearch-highlight-regexp ()
+  "Run `highlight-regexp' with regexp from the current search string.
+It exits Isearch mode and calls `hi-lock-face-buffer' with its regexp
+argument from the last search regexp or a quoted search string,
+and reads its face argument using `hi-lock-read-face-name'."
+  (interactive)
+  (let (
+       ;; Set `isearch-recursive-edit' to nil to prevent calling
+       ;; `exit-recursive-edit' in `isearch-done' that terminates
+       ;; the execution of this command when it is non-nil.
+       ;; We call `exit-recursive-edit' explicitly at the end below.
+       (isearch-recursive-edit nil))
+    (isearch-done nil t)
+    (isearch-clean-overlays))
+  (require 'hi-lock nil t)
+  (let ((string (cond (isearch-regexp isearch-string)
+                     ((if (and (eq isearch-case-fold-search t)
+                               search-upper-case)
+                          (isearch-no-upper-case-p
+                           isearch-string isearch-regexp)
+                        isearch-case-fold-search)
+                      ;; Turn isearch-string into a case-insensitive
+                      ;; regexp.
+                      (mapconcat
+                       (lambda (c)
+                         (let ((s (string c)))
+                           (if (string-match "[[:alpha:]]" s)
+                               (format "[%s%s]" (upcase s) (downcase s))
+                             (regexp-quote s))))
+                       isearch-string ""))
+                     (t (regexp-quote isearch-string)))))
+    (hi-lock-face-buffer string (hi-lock-read-face-name)))
+  (and isearch-recursive-edit (exit-recursive-edit)))
+
 \f
 (defun isearch-delete-char ()
   "Discard last input item and move point back.
@@ -1573,13 +1723,12 @@ Scroll-bar or mode-line events are processed appropriately."
 ;; Scroll-bar functions:
 (if (fboundp 'scroll-bar-toolkit-scroll)
     (put 'scroll-bar-toolkit-scroll 'isearch-scroll t))
-(if (fboundp 'mac-handle-scroll-bar-event)
-    (put 'mac-handle-scroll-bar-event 'isearch-scroll t))
 (if (fboundp 'w32-handle-scroll-bar-event)
     (put 'w32-handle-scroll-bar-event 'isearch-scroll t))
 
 ;; Commands which scroll the window:
 (put 'recenter 'isearch-scroll t)
+(put 'recenter-top-bottom 'isearch-scroll t)
 (put 'reposition-window 'isearch-scroll t)
 (put 'scroll-up 'isearch-scroll t)
 (put 'scroll-down 'isearch-scroll t)
@@ -1834,7 +1983,7 @@ Isearch mode."
   "Convert return into newline for incremental search."
   (interactive)
   (isearch-process-search-char ?\n))
-(make-obsolete 'isearch-return-char 'isearch-printing-char)
+(make-obsolete 'isearch-return-char 'isearch-printing-char "19.7")
 
 (defun isearch-printing-char ()
   "Add this ordinary printing character to the search string and search."
@@ -1895,10 +2044,12 @@ Isearch mode."
   (if search-ring-update
       (progn
        (isearch-search)
+       (isearch-push-state)
        (isearch-update))
-    (isearch-edit-string)
-    )
-  (isearch-push-state))
+    ;; Otherwise, edit the search string instead.  Note that there is
+    ;; no need to push the search state after isearch-edit-string here
+    ;; since isearch-edit-string already pushes its state
+    (isearch-edit-string)))
 
 (defun isearch-ring-advance ()
   "Advance to the next search string in the ring."
@@ -1975,9 +2126,13 @@ If there is no completion possible, say so and continue searching."
        (pop cmds))
       (setq succ-msg (and cmds (isearch-message-state (car cmds)))
            m (copy-sequence m))
-      (when (and (stringp succ-msg) (< (length succ-msg) (length m)))
-       (add-text-properties (length succ-msg) (length m)
-                            '(face isearch-fail) m))
+      (add-text-properties
+       (if (and (stringp succ-msg)
+               (< (length succ-msg) (length m))
+               (equal succ-msg (substring m 0 (length succ-msg))))
+          (length succ-msg)
+        0)
+       (length m) '(face isearch-fail) m)
       ;; Highlight failed trailing whitespace
       (when (string-match " +$" m)
        (add-text-properties (match-beginning 0) (match-end 0)
@@ -2010,6 +2165,8 @@ If there is no completion possible, say so and continue searching."
                   (if isearch-wrapped "wrapped ")
                   (if isearch-word "word " "")
                   (if isearch-regexp "regexp " "")
+                  (if multi-isearch-next-buffer-current-function "multi " "")
+                  (or isearch-message-prefix-add "")
                   (if nonincremental "search" "I-search")
                   (if isearch-forward "" " backward")
                   (if current-input-method
@@ -2023,7 +2180,8 @@ If there is no completion possible, say so and continue searching."
   (concat (if c-q-hack "^Q" "")
          (if isearch-error
              (concat " [" isearch-error "]")
-           "")))
+           "")
+         (or isearch-message-suffix-add "")))
 
 \f
 ;; Searching
@@ -2041,7 +2199,12 @@ Can be changed via `isearch-search-fun-function' for special needs."
       (funcall isearch-search-fun-function)
     (cond
      (isearch-word
-      (if isearch-forward 'word-search-forward 'word-search-backward))
+      ;; Use lax versions to not fail at the end of the word while the user
+      ;; adds and removes characters in the search string
+      (if (not (eq (length isearch-string)
+                  (length (isearch-string-state (car isearch-cmds)))))
+         (if isearch-forward 'word-search-forward-lax 'word-search-backward-lax)
+       (if isearch-forward 'word-search-forward 'word-search-backward)))
      (isearch-regexp
       (if isearch-forward 're-search-forward 're-search-backward))
      (t
@@ -2056,13 +2219,15 @@ Can be changed via `isearch-search-fun-function' for special needs."
        pos1 pos2)
     (setq pos1 (save-excursion (funcall func string bound noerror)))
     (if (and (char-table-p translation-table-for-input)
-            (> (string-bytes string) len))
-       (let (translated match-data)
-         (dotimes (i len)
-           (let ((x (aref translation-table-for-input (aref string i))))
-             (when x
-               (or translated (setq translated (copy-sequence string)))
-               (aset translated i x))))
+             (multibyte-string-p string)
+             ;; Minor optimization.
+             (string-match-p "[^[:ascii:]]" string))
+       (let ((translated
+               (apply 'string
+                      (mapcar (lambda (c)
+                                (or (aref translation-table-for-input c) c))
+                              string)))
+              match-data)
          (when translated
            (save-match-data
              (save-excursion
@@ -2076,9 +2241,9 @@ Can be changed via `isearch-search-fun-function' for special needs."
     (when pos1
       ;; When using multiple buffers isearch, switch to the new buffer here,
       ;; because `save-excursion' above doesn't allow doing it inside funcall.
-      (if (and isearch-buffers-next-buffer-function
-              (buffer-live-p isearch-buffers-current-buffer))
-         (switch-to-buffer isearch-buffers-current-buffer))
+      (if (and multi-isearch-next-buffer-current-function
+              (buffer-live-p multi-isearch-current-buffer))
+         (switch-to-buffer multi-isearch-current-buffer))
       (goto-char pos1))
     pos1))
 
@@ -2091,7 +2256,9 @@ Can be changed via `isearch-search-fun-function' for special needs."
       (setq isearch-case-fold-search
            (isearch-no-upper-case-p isearch-string isearch-regexp)))
   (condition-case lossage
-      (let ((inhibit-point-motion-hooks search-invisible)
+      (let ((inhibit-point-motion-hooks
+            (and (eq isearch-success-function 'isearch-success-function-default)
+                 search-invisible))
            (inhibit-quit nil)
            (case-fold-search isearch-case-fold-search)
            (search-spaces-regexp search-whitespace-regexp)
@@ -2102,12 +2269,11 @@ Can be changed via `isearch-search-fun-function' for special needs."
                (isearch-search-string isearch-string nil t))
          ;; Clear RETRY unless we matched some invisible text
          ;; and we aren't supposed to do that.
-         (if (or (eq search-invisible t)
-                 (not isearch-success)
+         (if (or (not isearch-success)
                  (bobp) (eobp)
                  (= (match-beginning 0) (match-end 0))
-                 (not (isearch-range-invisible
-                       (match-beginning 0) (match-end 0))))
+                 (funcall isearch-success-function
+                          (match-beginning 0) (match-end 0)))
              (setq retry nil)))
        (setq isearch-just-started nil)
        (if isearch-success
@@ -2285,6 +2451,13 @@ Can be changed via `isearch-search-fun-function' for special needs."
                  nil)
              (setq isearch-hidden t)))))))
 
+(defun isearch-success-function-default (beg end)
+  "Default function to report if the new search match is successful.
+Returns t if search can match hidden text, or otherwise checks if some
+text from BEG to END is visible."
+  (or (eq search-invisible t)
+      (not (isearch-range-invisible beg end))))
+
 \f
 ;; General utilities
 
@@ -2451,23 +2624,32 @@ by other Emacs features."
 (defun isearch-lazy-highlight-search ()
   "Search ahead for the next or previous match, for lazy highlighting.
 Attempt to do the search exactly the way the pending isearch would."
-  (let ((case-fold-search isearch-lazy-highlight-case-fold-search)
-       (isearch-regexp isearch-lazy-highlight-regexp)
-       (search-spaces-regexp isearch-lazy-highlight-space-regexp))
-    (condition-case nil
-       (isearch-search-string
-                isearch-lazy-highlight-last-string
-                (if isearch-forward
-                    (min (or isearch-lazy-highlight-end-limit (point-max))
+  (condition-case nil
+      (let ((case-fold-search isearch-lazy-highlight-case-fold-search)
+           (isearch-regexp isearch-lazy-highlight-regexp)
+           (search-spaces-regexp isearch-lazy-highlight-space-regexp)
+           (search-invisible nil)      ; don't match invisible text
+           (retry t)
+           (success nil)
+           (bound (if isearch-forward
+                      (min (or isearch-lazy-highlight-end-limit (point-max))
+                           (if isearch-lazy-highlight-wrapped
+                               isearch-lazy-highlight-start
+                             (window-end)))
+                    (max (or isearch-lazy-highlight-start-limit (point-min))
                          (if isearch-lazy-highlight-wrapped
-                             isearch-lazy-highlight-start
-                           (window-end)))
-                  (max (or isearch-lazy-highlight-start-limit (point-min))
-                       (if isearch-lazy-highlight-wrapped
-                           isearch-lazy-highlight-end
-                         (window-start))))
-                t)
-      (error nil))))
+                             isearch-lazy-highlight-end
+                           (window-start))))))
+       ;; Use a loop like in `isearch-search'
+       (while retry
+         (setq success (isearch-search-string
+                        isearch-lazy-highlight-last-string bound t))
+         (if (or (not success)
+                 (funcall isearch-success-function
+                          (match-beginning 0) (match-end 0)))
+             (setq retry nil)))
+       success)
+    (error nil)))
 
 (defun isearch-lazy-highlight-update ()
   "Update highlighting of other matches for current search."