]> code.delx.au - gnu-emacs/blobdiff - lisp/isearch.el
More accurate documentation of lax whitespace matching
[gnu-emacs] / lisp / isearch.el
index 99ca73f9f54d892eba9774a93b19074023025daa..8c98d36f4aa69553a874cea1f79e61c4c88cd050 100644 (file)
 ;; is completed.  It uses a recursive-edit to behave this way.
 
 ;; The key bindings active within isearch-mode are defined below in
-;; `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
+;; `isearch-mode-map'.  Also see minibuffer-local-isearch-map
 ;; for bindings active during `isearch-edit-string'.
 
 ;; isearch-mode should work even if you switch windows with the mouse,
 
 (defcustom search-exit-option t
   "Non-nil means random control characters terminate incremental search."
-  :type 'boolean
-  :group 'isearch)
+  :type 'boolean)
 
 (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."
-  :type 'integer
-  :group 'isearch)
+  :type 'integer)
 
 (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."
-  :type 'integer
-  :group 'isearch)
+  :type 'integer)
 
 (defcustom search-upper-case 'not-yanks
   "If non-nil, upper case chars disable case fold searching.
@@ -99,15 +92,17 @@ If this value is `not-yanks', text yanked into the search string
 in Isearch mode is always downcased."
   :type '(choice (const :tag "off" nil)
                 (const not-yanks)
-                (other :tag "on" t))
-  :group 'isearch)
+                (other :tag "on" t)))
 
 (defcustom search-nonincremental-instead t
   "If non-nil, do a nonincremental search instead of exiting immediately.
-Actually, `isearch-edit-string' is called to let you enter the search
-string, and RET terminates editing and does a nonincremental search."
-  :type 'boolean
-  :group 'isearch)
+This affects the behavior of `isearch-exit' and any key bound to that
+command: if this variable is nil, `isearch-exit' always exits the search;
+if the value is non-nil, and the search string is empty, `isearch-exit'
+starts a nonincremental search instead.  (Actually, `isearch-edit-string'
+is called to let you enter the search string, and RET terminates editing
+and does a nonincremental search.)"
+  :type 'boolean)
 
 (defcustom search-whitespace-regexp (purecopy "\\s-+")
   "If non-nil, regular expression to match a sequence of whitespace chars.
@@ -127,7 +122,6 @@ In the Customization buffer, that is `[' followed by a space,
 a tab, a carriage return (control-M), a newline, and `]+'."
   :type '(choice (const :tag "Match Spaces Literally" nil)
                 regexp)
-  :group 'isearch
   :version "24.3")
 
 (defcustom search-invisible 'open
@@ -147,24 +141,23 @@ See also `reveal-mode' if you want overlays to automatically be opened
 whenever point is in one of them."
   :type '(choice (const :tag "Match hidden text" t)
                 (const :tag "Open overlays" open)
-                (const :tag "Don't match hidden text" nil))
-  :group 'isearch)
+                (const :tag "Don't match hidden text" nil)))
 
 (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'.
+If non-nil, invisible matches are re-hidden as soon as the match moves
+off the invisible text surrounding the match.
 If nil then do not re-hide opened invisible text when the match moves.
 Whatever the value, all opened invisible text is hidden again after exiting
-the search."
-  :type 'boolean
-  :group 'isearch)
+the search, with the exception of the last successful match, if any."
+  :type 'boolean)
 
 (defcustom isearch-resume-in-command-history nil
   "If non-nil, `isearch-resume' commands are added to the command history.
 This allows you to resume earlier Isearch sessions through the
 command history."
-  :type 'boolean
-  :group 'isearch)
+  :type 'boolean)
 
 (defvar isearch-mode-hook nil
   "Function(s) to call after starting up an incremental search.")
@@ -212,12 +205,10 @@ displayed in the search message.")
 
 (defcustom search-ring-max 16
   "Maximum length of search ring before oldest elements are thrown away."
-  :type 'integer
-  :group 'isearch)
+  :type 'integer)
 (defcustom regexp-search-ring-max 16
   "Maximum length of regexp search ring before oldest elements are thrown away."
-  :type 'integer
-  :group 'isearch)
+  :type 'integer)
 
 (defvar search-ring-yank-pointer nil
   "Index in `search-ring' of last string reused.
@@ -229,15 +220,34 @@ It is nil if none yet.")
 (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."
-  :type 'boolean
-  :group 'isearch)
+  :type 'boolean)
+
+(autoload 'character-fold-to-regexp "character-fold")
+
+(defcustom search-default-regexp-mode #'character-fold-to-regexp
+  "Default mode to use when starting isearch.
+Value is nil, t, or a function.
+
+If nil, default to literal searches (note that `case-fold-search'
+and `isearch-lax-whitespace' may still be applied).\\<isearch-mode-map>
+If t, default to regexp searches (as if typing `\\[isearch-toggle-regexp]' during
+isearch).
+
+If a function, use that function as an `isearch-regexp-function'.
+Example functions are `word-search-regexp' \(`\\[isearch-toggle-word]'),
+`isearch-symbol-regexp' \(`\\[isearch-toggle-symbol]'), and
+`character-fold-to-regexp' \(`\\[isearch-toggle-character-fold]')."
+  ;; :type is set below by `isearch-define-mode-toggle'.
+  :type '(choice (const :tag "Literal search" nil)
+                 (const :tag "Regexp search" t)
+                 (function :tag "Other"))
+  :version "25.1")
 
 ;;; isearch highlight customization.
 
 (defcustom search-highlight t
   "Non-nil means incremental search highlights the current match."
-  :type 'boolean
-  :group 'isearch)
+  :type 'boolean)
 
 (defface isearch
   '((((class color) (min-colors 88) (background light))
@@ -269,8 +279,7 @@ Default value, nil, means edit the string instead."
      :foreground "grey")
     (t (:inverse-video t)))
   "Face for highlighting failed part in Isearch echo-area message."
-  :version "23.1"
-  :group 'isearch)
+  :version "23.1")
 
 (defcustom isearch-lazy-highlight t
   "Controls the lazy-highlighting during incremental search.
@@ -452,7 +461,7 @@ This is like `describe-bindings', but displays only Isearch keys."
     (define-key map "\M-\C-s" 'isearch-repeat-forward)
     (define-key map "\M-\C-r" 'isearch-repeat-backward)
     (define-key map "\177" 'isearch-delete-char)
-    (define-key map [backspace] 'isearch-delete-char)
+    (define-key map [backspace] 'undefined) ;bug#20466.
     (define-key map "\C-g" 'isearch-abort)
 
     ;; This assumes \e is the meta-prefix-char.
@@ -508,17 +517,10 @@ This is like `describe-bindings', but displays only Isearch keys."
     (define-key map "\M-r" 'isearch-toggle-regexp)
     (define-key map "\M-e" 'isearch-edit-string)
 
-    (put 'isearch-toggle-case-fold :advertised-binding "\M-sc")
-    (put 'isearch-toggle-regexp    :advertised-binding "\M-sr")
     (put 'isearch-edit-string      :advertised-binding "\M-se")
 
     (define-key map "\M-se" 'isearch-edit-string)
-    (define-key map "\M-sc" 'isearch-toggle-case-fold)
-    (define-key map "\M-si" 'isearch-toggle-invisible)
-    (define-key map "\M-sr" 'isearch-toggle-regexp)
-    (define-key map "\M-sw" 'isearch-toggle-word)
-    (define-key map "\M-s_" 'isearch-toggle-symbol)
-    (define-key map "\M-s " 'isearch-toggle-lax-whitespace)
+    ;; More toggles defined by `isearch-define-mode-toggle'.
 
     (define-key map [?\M-%] 'isearch-query-replace)
     (define-key map [?\C-\M-%] 'isearch-query-replace-regexp)
@@ -550,13 +552,16 @@ This is like `describe-bindings', but displays only Isearch keys."
 
 (defvar isearch-forward nil)   ; Searching in the forward direction.
 (defvar isearch-regexp nil)    ; Searching for a regexp.
-(defvar isearch-word nil
+(defvar isearch-regexp-function nil
   "Regexp-based search mode for words/symbols.
-If t, do incremental search for a sequence of words, ignoring punctuation.
-If the value is a function (e.g. `isearch-symbol-regexp'), it is called to
-convert the search string to a regexp used by regexp search functions.
-The property `isearch-message-prefix' put on this function specifies the
-prefix string displayed in the search message.")
+If the value is a function (e.g. `isearch-symbol-regexp'), it is
+called to convert a plain search string to a regexp used by
+regexp search functions.
+The symbol property `isearch-message-prefix' put on this function
+specifies the prefix string displayed in the search message.")
+;; We still support setting this to t for backwards compatibility.
+(define-obsolete-variable-alias 'isearch-word
+  'isearch-regexp-function "25.1")
 
 (defvar isearch-lax-whitespace t
   "If non-nil, a space will match a sequence of whitespace chars.
@@ -578,7 +583,7 @@ variable by the command `isearch-toggle-lax-whitespace'.")
   "Stack of search status elements.
 Each element is an `isearch--state' struct where the slots are
  [STRING MESSAGE POINT SUCCESS FORWARD OTHER-END WORD
-  INVALID-REGEXP WRAPPED BARRIER WITHIN-BRACKETS CASE-FOLD-SEARCH]")
+  ERROR WRAPPED BARRIER CASE-FOLD-SEARCH]")
 
 (defvar isearch-string "")  ; The current search string.
 (defvar isearch-message "") ; text-char-description version of isearch-string
@@ -657,8 +662,7 @@ Each element is an `isearch--state' struct where the slots are
     (nconc minor-mode-alist
           (list '(isearch-mode isearch-mode))))
 
-(defvar isearch-mode nil) ;; Name of the minor mode, if non-nil.
-(make-variable-buffer-local 'isearch-mode)
+(defvar-local isearch-mode nil) ;; Name of the minor mode, if non-nil.
 
 (define-key global-map "\C-s" 'isearch-forward)
 (define-key esc-map "\C-s" 'isearch-forward-regexp)
@@ -710,6 +714,7 @@ Type \\[isearch-toggle-invisible] to toggle search in invisible text.
 Type \\[isearch-toggle-regexp] to toggle regular-expression mode.
 Type \\[isearch-toggle-word] to toggle word mode.
 Type \\[isearch-toggle-symbol] to toggle symbol mode.
+Type \\[isearch-toggle-character-fold] to toggle character folding.
 
 Type \\[isearch-toggle-lax-whitespace] to toggle whitespace matching.
 In incremental searches, a space or spaces normally matches any whitespace
@@ -769,7 +774,8 @@ as a regexp.  See the command `isearch-forward' for more information.
 In incremental searches, a space or spaces normally matches any
 whitespace defined by the variable `search-whitespace-regexp'.
 To search for a literal space and nothing else, enter C-q SPC.
-To toggle whitespace matching, use `isearch-toggle-lax-whitespace'."
+To toggle whitespace matching, use `isearch-toggle-lax-whitespace'.
+This command does not support character folding."
   (interactive "P\np")
   (isearch-mode t (null not-regexp) nil (not no-recursive-edit)))
 
@@ -778,7 +784,9 @@ To toggle whitespace matching, use `isearch-toggle-lax-whitespace'."
 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."
+See the command `isearch-forward' for more information.
+This command does not support character folding, and lax space matching
+has no effect on it."
   (interactive "P\np")
   (isearch-mode t nil nil (not no-recursive-edit) (null not-word)))
 
@@ -787,7 +795,9 @@ See the command `isearch-forward' for more information."
 The prefix argument is currently unused.
 Like ordinary incremental search except that your input is treated
 as a symbol surrounded by symbol boundary constructs \\_< and \\_>.
-See the command `isearch-forward' for more information."
+See the command `isearch-forward' for more information.
+This command does not support character folding, and lax space matching
+has no effect on it."
   (interactive "P\np")
   (isearch-mode t nil nil (not no-recursive-edit) 'isearch-symbol-regexp))
 
@@ -802,7 +812,7 @@ See the command `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 the command `isearch-forward' for more information."
+as a regexp.  See the command `isearch-forward-regexp' for more information."
   (interactive "P\np")
   (isearch-mode nil (null not-regexp) nil (not no-recursive-edit)))
 
@@ -826,6 +836,7 @@ See the command `isearch-forward-symbol' for more information."
       (isearch-update)))))
 
 \f
+(defvar cursor-sensor-inhibit)
 ;; isearch-mode only sets up incremental search for the minor mode.
 ;; All the work is done by the isearch-mode commands.
 
@@ -834,8 +845,7 @@ See the command `isearch-forward-symbol' for more information."
 ;;                          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)
+(defun isearch-mode (forward &optional regexp op-fun recursive-edit regexp-function)
   "Start Isearch minor mode.
 It is called by the function `isearch-forward' and other related functions.
 
@@ -851,14 +861,18 @@ does not return to the calling function until the search is completed.
 To behave this way it enters a recursive-edit and exits it when done
 isearching.
 
-The arg WORD, if t, does incremental search for a sequence of words,
-ignoring punctuation.  If the value is a function, it is called to
-convert the search string to a regexp used by regexp search functions."
+The arg REGEXP-FUNCTION, if non-nil, should be a function.  It is
+used to set the value of `isearch-regexp-function'."
 
   ;; Initialize global vars.
   (setq isearch-forward forward
-       isearch-regexp regexp
-       isearch-word word
+       isearch-regexp (or regexp
+                           (and (not regexp-function)
+                                (eq search-default-regexp-mode t)))
+       isearch-regexp-function (or regexp-function
+                                    (and (functionp search-default-regexp-mode)
+                                         (not regexp)
+                                         search-default-regexp-mode))
        isearch-op-fun op-fun
        isearch-last-case-fold-search isearch-case-fold-search
        isearch-case-fold-search case-fold-search
@@ -943,10 +957,23 @@ convert the search string to a regexp used by regexp search functions."
 
 
 ;; Some high level utilities.  Others below.
+(defvar isearch--current-buffer nil)
 
 (defun isearch-update ()
   "This is called after every isearch command to update the display.
 The last thing it does is to run `isearch-update-post-hook'."
+  (unless (eq (current-buffer) isearch--current-buffer)
+    (when (buffer-live-p isearch--current-buffer)
+      (with-current-buffer isearch--current-buffer
+        (setq cursor-sensor-inhibit (delq 'isearch cursor-sensor-inhibit))))
+    (setq isearch--current-buffer (current-buffer))
+    (make-local-variable 'cursor-sensor-inhibit)
+    (unless (boundp 'cursor-sensor-inhibit)
+      (setq cursor-sensor-inhibit nil))
+    ;; Suspend things like cursor-intangible during Isearch so we can search
+    ;; even within intangible text.
+    (push 'isearch cursor-sensor-inhibit))
+
   (if (and (null unread-command-events)
           (null executing-kbd-macro))
       (progn
@@ -1009,7 +1036,7 @@ NOPUSH is t and EDIT is t."
 
   (if isearch-resume-in-command-history
       (let ((command `(isearch-resume ,isearch-string ,isearch-regexp
-                                     ,isearch-word ,isearch-forward
+                                     ,isearch-regexp-function ,isearch-forward
                                      ,isearch-message
                                      ',isearch-case-fold-search)))
        (unless (equal (car command-history) command)
@@ -1020,6 +1047,9 @@ NOPUSH is t and EDIT is t."
   (remove-hook 'mouse-leave-buffer-hook 'isearch-done)
   (remove-hook 'kbd-macro-termination-hook 'isearch-done)
   (setq isearch-lazy-highlight-start nil)
+  (with-current-buffer isearch--current-buffer
+    (setq isearch--current-buffer nil)
+    (setq cursor-sensor-inhibit (delq 'isearch cursor-sensor-inhibit)))
 
   ;; Called by all commands that terminate isearch-mode.
   ;; If NOPUSH is non-nil, we don't push the string on the search ring.
@@ -1108,7 +1138,7 @@ REGEXP if non-nil says use the regexp search ring."
                  (success isearch-success)
                  (forward isearch-forward)
                  (other-end isearch-other-end)
-                 (word isearch-word)
+                 (word isearch-regexp-function)
                  (error isearch-error)
                  (wrapped isearch-wrapped)
                  (barrier isearch-barrier)
@@ -1134,7 +1164,7 @@ REGEXP if non-nil says use the regexp search ring."
        isearch-success (isearch--state-success cmd)
        isearch-forward (isearch--state-forward cmd)
        isearch-other-end (isearch--state-other-end cmd)
-       isearch-word (isearch--state-word cmd)
+       isearch-regexp-function (isearch--state-word cmd)
        isearch-error (isearch--state-error cmd)
        isearch-wrapped (isearch--state-wrapped cmd)
        isearch-barrier (isearch--state-barrier cmd)
@@ -1162,8 +1192,8 @@ nonincremental search instead via `isearch-edit-string'."
   (if (and search-nonincremental-instead
           (= 0 (length isearch-string)))
       (let ((isearch-nonincremental t))
-       (isearch-edit-string)))
-  (isearch-done)
+       (isearch-edit-string)) ;; this calls isearch-done as well
+    (isearch-done))
   (isearch-clean-overlays))
 
 (defun isearch-fail-pos (&optional msg)
@@ -1186,11 +1216,19 @@ If MSG is non-nil, use variable `isearch-message', otherwise `isearch-string'."
          (length succ-msg)
        0))))
 
+(defvar isearch-new-regexp-function nil
+  "Holds the next `isearch-regexp-function' inside `with-isearch-suspended'.
+If this is set inside code wrapped by the macro
+`with-isearch-suspended', then the value set will be used as the
+`isearch-regexp-function' once isearch resumes.")
+(define-obsolete-variable-alias 'isearch-new-word
+  'isearch-new-regexp-function "25.1")
+
 (defmacro with-isearch-suspended (&rest body)
   "Exit Isearch mode, run BODY, and reinvoke the pending search.
 You can update the global isearch variables by setting new values to
 `isearch-new-string', `isearch-new-message', `isearch-new-forward',
-`isearch-new-word', `isearch-new-case-fold'."
+`isearch-new-regexp-function', `isearch-new-case-fold'."
   ;; 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,
@@ -1207,7 +1245,7 @@ You can update the global isearch variables by setting new values to
              (isearch-new-string isearch-string)
              (isearch-new-message isearch-message)
              (isearch-new-forward isearch-forward)
-             (isearch-new-word isearch-word)
+             (isearch-new-regexp-function isearch-regexp-function)
              (isearch-new-case-fold isearch-case-fold-search)
 
              (isearch-regexp isearch-regexp)
@@ -1273,13 +1311,13 @@ You can update the global isearch variables by setting new values to
                          isearch-regexp
                          isearch-op-fun
                          nil
-                         isearch-word)
+                         isearch-regexp-function)
 
            ;; 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
+                 isearch-regexp-function isearch-new-regexp-function
                  isearch-case-fold-search isearch-new-case-fold))
 
          ;; Empty isearch-string means use default.
@@ -1465,86 +1503,93 @@ Use `isearch-exit' to quit without signaling."
   (interactive)
   (isearch-repeat 'backward))
 
-(defun isearch-toggle-regexp ()
-  "Toggle regexp searching on or off."
-  ;; The status stack is left unchanged.
-  (interactive)
+\f
+;;; Toggles for `isearch-regexp-function' and `search-default-regexp-mode'.
+(defmacro isearch-define-mode-toggle (mode key function &optional docstring &rest body)
+  "Define a command called `isearch-toggle-MODE' and bind it to `M-s KEY'.
+The first line of the command's docstring is auto-generated, the
+remainder may be provided in DOCSTRING.
+If FUNCTION is a symbol, this command first toggles the value of
+`isearch-regexp-function' between nil and FUNCTION.  Also set the
+`isearch-message-prefix' property of FUNCTION.
+The command then executes BODY and updates the isearch prompt."
+  (declare (indent defun))
+  (let ((command-name (intern (format "isearch-toggle-%s" mode)))
+        (key (concat "\M-s" key)))
+    `(progn
+       (defun ,command-name ()
+         ,(format "Toggle %s searching on or off.%s" mode
+                  (if docstring (concat "\n" docstring) ""))
+         (interactive)
+         ,@(when function
+             `((setq isearch-regexp-function
+                     (unless (eq isearch-regexp-function #',function)
+                       #',function))
+               (when isearch-regexp-function (setq isearch-regexp nil))))
+         ,@body
+         (setq isearch-success t isearch-adjusted t)
+         (isearch-update))
+       (define-key isearch-mode-map ,key #',command-name)
+       ,@(when (symbolp function)
+           `((put ',function 'isearch-message-prefix ,(format "%s " mode))
+             (put ',function :advertised-binding ,key)
+             (cl-callf (lambda (types) (cons 'choice
+                                        (cons '(const :tag ,(capitalize (format "%s search" mode)) ,function)
+                                              (cdr types))))
+                 (get 'search-default-regexp-mode 'custom-type)))))))
+
+(isearch-define-mode-toggle word "w" word-search-regexp "\
+Turning on word search turns off regexp mode.")
+(isearch-define-mode-toggle symbol "_" isearch-symbol-regexp "\
+Turning on symbol search turns off regexp mode.")
+(isearch-define-mode-toggle character-fold "'" character-fold-to-regexp "\
+Turning on character-folding turns off regexp mode.")
+(put 'character-fold-to-regexp 'isearch-message-prefix "char-fold ")
+
+(isearch-define-mode-toggle regexp "r" nil nil
   (setq isearch-regexp (not isearch-regexp))
-  (if isearch-regexp (setq isearch-word nil))
-  (setq isearch-success t isearch-adjusted t)
-  (isearch-update))
-
-(defun isearch-toggle-word ()
-  "Toggle word searching on or off."
-  ;; The status stack is left unchanged.
-  (interactive)
-  (setq isearch-word (not isearch-word))
-  (if isearch-word (setq isearch-regexp nil))
-  (setq isearch-success t isearch-adjusted t)
-  (isearch-update))
-
-(defun isearch-toggle-symbol ()
-  "Toggle symbol searching on or off."
-  (interactive)
-  (setq isearch-word (unless (eq isearch-word 'isearch-symbol-regexp)
-                      'isearch-symbol-regexp))
-  (if isearch-word (setq isearch-regexp nil))
-  (setq isearch-success t isearch-adjusted t)
-  (isearch-update))
+  (if isearch-regexp (setq isearch-regexp-function nil)))
 
-(defun isearch-toggle-lax-whitespace ()
-  "Toggle whitespace matching in searching on or off.
-In ordinary search, toggles the value of the variable
-`isearch-lax-whitespace'.  In regexp search, toggles the
-value of the variable `isearch-regexp-lax-whitespace'."
-  (interactive)
-  (if isearch-regexp
-      (setq isearch-regexp-lax-whitespace (not isearch-regexp-lax-whitespace))
-    (setq isearch-lax-whitespace (not isearch-lax-whitespace)))
+(defun isearch--momentary-message (string)
+  "Print STRING at the end of the isearch prompt for 1 second"
   (let ((message-log-max nil))
     (message "%s%s [%s]"
-            (isearch-message-prefix nil isearch-nonincremental)
-            isearch-message
-            (if (if isearch-regexp
-                    isearch-regexp-lax-whitespace
-                  isearch-lax-whitespace)
-                "match spaces loosely"
-              "match spaces literally")))
-  (setq isearch-success t isearch-adjusted t)
-  (sit-for 1)
-  (isearch-update))
-
-(defun isearch-toggle-case-fold ()
-  "Toggle case folding in searching on or off.
-Toggles the value of the variable `isearch-case-fold-search'."
-  (interactive)
-  (setq isearch-case-fold-search
-       (if isearch-case-fold-search nil 'yes))
-  (let ((message-log-max nil))
-    (message "%s%s [case %ssensitive]"
-            (isearch-message-prefix nil isearch-nonincremental)
-            isearch-message
-            (if isearch-case-fold-search "in" "")))
-  (setq isearch-success t isearch-adjusted t)
-  (sit-for 1)
-  (isearch-update))
+             (isearch-message-prefix nil isearch-nonincremental)
+             isearch-message
+             string))
+  (sit-for 1))
 
-(defun isearch-toggle-invisible ()
-  "Toggle searching in invisible text on or off.
+(isearch-define-mode-toggle lax-whitespace " " nil
+  "In ordinary search, toggles the value of the variable
+`isearch-lax-whitespace'.  In regexp search, toggles the
+value of the variable `isearch-regexp-lax-whitespace'."
+  (isearch--momentary-message
+   (if (if isearch-regexp
+           (setq isearch-regexp-lax-whitespace (not isearch-regexp-lax-whitespace))
+         (setq isearch-lax-whitespace (not isearch-lax-whitespace)))
+       "match spaces loosely"
+     "match spaces literally")))
+
+(isearch-define-mode-toggle case-fold "c" nil
+  "Toggles the value of the variable `isearch-case-fold-search'."
+  (isearch--momentary-message
+   (if (setq isearch-case-fold-search
+             (if isearch-case-fold-search nil 'yes))
+       "case insensitive"
+     "case sensitive")))
+
+(isearch-define-mode-toggle invisible "i" nil
+  "This determines whether to search inside invisible text or not.
 Toggles the variable `isearch-invisible' between values
 nil and a non-nil value of the option `search-invisible'
 \(or `open' if `search-invisible' is nil)."
-  (interactive)
-  (setq isearch-invisible
-       (if isearch-invisible nil (or search-invisible 'open)))
-  (let ((message-log-max nil))
-    (message "%s%s [match %svisible text]"
-            (isearch-message-prefix nil isearch-nonincremental)
-            isearch-message
-            (if isearch-invisible "in" "")))
-  (setq isearch-success t isearch-adjusted t)
-  (sit-for 1)
-  (isearch-update))
+  "match %svisible text"
+  (isearch--momentary-message
+   (if (setq isearch-invisible
+             (if isearch-invisible
+                 nil (or search-invisible 'open)))
+       "match invisible text"
+     "match visible text")))
 
 \f
 ;; Word search
@@ -1581,7 +1626,9 @@ Optional fourth argument is repeat count--search for successive occurrences.
 
 Relies on the function `word-search-regexp' to convert a sequence
 of words in STRING to a regexp used to search words without regard
-to punctuation."
+to punctuation.
+This command does not support character folding, and lax space matching
+has no effect on it."
   (interactive "sWord search backward: ")
   (re-search-backward (word-search-regexp string nil) bound noerror count))
 
@@ -1596,7 +1643,9 @@ Optional fourth argument is repeat count--search for successive occurrences.
 
 Relies on the function `word-search-regexp' to convert a sequence
 of words in STRING to a regexp used to search words without regard
-to punctuation."
+to punctuation.
+This command does not support character folding, and lax space matching
+has no effect on it."
   (interactive "sWord search: ")
   (re-search-forward (word-search-regexp string nil) bound noerror count))
 
@@ -1615,7 +1664,9 @@ Optional fourth argument is repeat count--search for successive occurrences.
 
 Relies on the function `word-search-regexp' to convert a sequence
 of words in STRING to a regexp used to search words without regard
-to punctuation."
+to punctuation.
+This command does not support character folding, and lax space matching
+has no effect on it."
   (interactive "sWord search backward: ")
   (re-search-backward (word-search-regexp string t) bound noerror count))
 
@@ -1634,7 +1685,9 @@ Optional fourth argument is repeat count--search for successive occurrences.
 
 Relies on the function `word-search-regexp' to convert a sequence
 of words in STRING to a regexp used to search words without regard
-to punctuation."
+to punctuation.
+This command does not support character folding, and lax space matching
+has no effect on it."
   (interactive "sWord search: ")
   (re-search-forward (word-search-regexp string t) bound noerror count))
 
@@ -1686,6 +1739,13 @@ the beginning or the end of the string need not match a symbol boundary."
   (let ((search-spaces-regexp search-whitespace-regexp))
     (re-search-backward regexp bound noerror count)))
 
+(dolist (old '(re-search-forward-lax-whitespace search-backward-lax-whitespace
+               search-forward-lax-whitespace re-search-backward-lax-whitespace))
+  (make-obsolete old
+                 "instead, use (let ((search-spaces-regexp search-whitespace-regexp))
+               (re-search-... ...))"
+                 "25.1"))
+
 \f
 (defun isearch-query-replace (&optional arg regexp-flag)
   "Start `query-replace' with string to replace from last search string.
@@ -1735,20 +1795,11 @@ replacements from Isearch is `M-s w ... M-%'."
      (query-replace-read-to
       isearch-string
       (concat "Query replace"
-             (if (or delimited isearch-word)
-                 (let* ((symbol (or delimited isearch-word))
-                        (string (and symbol (symbolp symbol)
-                                     (get symbol 'isearch-message-prefix))))
-                   (if (stringp string)
-                       ;; Move space from the end to the beginning.
-                       (replace-regexp-in-string "\\(.*\\) \\'" " \\1" string)
-                     " word"))
-               "")
-             (if isearch-regexp " regexp" "")
+              (isearch--describe-regexp-mode (or delimited isearch-regexp-function) t)
              (if backward " backward" "")
              (if (and transient-mark-mode mark-active) " in region" ""))
       isearch-regexp)
-     t isearch-regexp (or delimited isearch-word) nil nil
+     t isearch-regexp (or delimited isearch-regexp-function) nil nil
      (if (and transient-mark-mode mark-active) (region-beginning))
      (if (and transient-mark-mode mark-active) (region-end))
      backward))
@@ -1775,9 +1826,9 @@ characters in that string."
   (interactive
    (let* ((perform-collect (consp current-prefix-arg))
          (regexp (cond
-                  ((functionp isearch-word)
-                   (funcall isearch-word isearch-string))
-                  (isearch-word (word-search-regexp isearch-string))
+                  ((functionp isearch-regexp-function)
+                   (funcall isearch-regexp-function isearch-string))
+                  (isearch-regexp-function (word-search-regexp isearch-string))
                   (isearch-regexp isearch-string)
                   (t (regexp-quote isearch-string)))))
      (list regexp
@@ -1807,7 +1858,13 @@ characters in that string."
                 isearch-regexp-lax-whitespace
               isearch-lax-whitespace)
             search-whitespace-regexp)))
-    (occur regexp nlines)))
+    (occur (if isearch-regexp-function
+              (propertize regexp
+                          'isearch-string isearch-string
+                          'isearch-regexp-function-descr
+                           (isearch--describe-regexp-mode isearch-regexp-function))
+            regexp)
+          nlines)))
 
 (declare-function hi-lock-read-face-name "hi-lock" ())
 
@@ -1826,9 +1883,9 @@ and reads its face argument using `hi-lock-read-face-name'."
     (isearch-done nil t)
     (isearch-clean-overlays))
   (require 'hi-lock nil t)
-  (let ((regexp (cond ((functionp isearch-word)
-                      (funcall isearch-word isearch-string))
-                     (isearch-word (word-search-regexp isearch-string))
+  (let ((regexp (cond ((functionp isearch-regexp-function)
+                       (funcall isearch-regexp-function isearch-string))
+                     (isearch-regexp-function (word-search-regexp isearch-string))
                      (isearch-regexp isearch-string)
                      ((if (and (eq isearch-case-fold-search t)
                                search-upper-case)
@@ -1917,8 +1974,8 @@ If search string is empty, just beep."
 (defun isearch-yank-x-selection ()
   "Pull current X selection into search string."
   (interactive)
-  (isearch-yank-string (x-get-selection))
-  ;; If `x-get-selection' returned the text from the active region,
+  (isearch-yank-string (gui-get-selection))
+  ;; If `gui-get-selection' returned the text from the active region,
   ;; then it "used" the mark which we should hence deactivate.
   (when select-active-regions (deactivate-mark)))
 
@@ -2033,9 +2090,9 @@ With argument, add COUNT copies of the character."
                       (setq case-fold-search
                             (isearch-no-upper-case-p isearch-string isearch-regexp)))
                   (looking-at (cond
-                               ((functionp isearch-word)
-                                (funcall isearch-word isearch-string t))
-                               (isearch-word (word-search-regexp isearch-string t))
+                               ((functionp isearch-regexp-function)
+                                (funcall isearch-regexp-function isearch-string t))
+                               (isearch-regexp-function (word-search-regexp isearch-string t))
                                (isearch-regexp isearch-string)
                                (t (regexp-quote isearch-string)))))
               (error nil))
@@ -2490,6 +2547,30 @@ If there is no completion possible, say so and continue searching."
             (isearch-message-suffix c-q-hack)))
     (if c-q-hack m (let ((message-log-max nil)) (message "%s" m)))))
 
+(defun isearch--describe-regexp-mode (regexp-function &optional space-before)
+  "Make a string for describing REGEXP-FUNCTION.
+If SPACE-BEFORE is non-nil, put a space before, instead of after,
+the word mode."
+  (when (eq regexp-function t)
+    (setq regexp-function #'word-search-regexp))
+  (let ((description
+         ;; Don't use a description on the default search mode.
+         (cond ((equal regexp-function search-default-regexp-mode) "")
+               (regexp-function
+                (and (symbolp regexp-function)
+                     (or (get regexp-function 'isearch-message-prefix)
+                         "")))
+               (isearch-regexp "regexp ")
+               ;; We're in literal mode. If the default mode is not
+               ;; literal, then describe it.
+               ((functionp search-default-regexp-mode) "literal "))))
+    (if space-before
+        ;; Move space from the end to the beginning.
+        (replace-regexp-in-string "\\(.*\\) \\'" " \\1" description)
+      description)))
+(define-obsolete-function-alias 'isearch--describe-word-mode
+  'isearch--describe-regexp-mode "25.1")
+
 (defun isearch-message-prefix (&optional ellipsis nonincremental)
   ;; If about to search, and previous search regexp was invalid,
   ;; check that it still is.  If it is valid now,
@@ -2516,13 +2597,8 @@ If there is no completion possible, say so and continue searching."
                         (let ((np (cdr (assq 'isearch-message-prefix props))))
                           (if np (setq prefix (concat np prefix)))))
                       isearch-filter-predicate)
-                    prefix)
-                  (if isearch-word
-                      (or (and (symbolp isearch-word)
-                               (get isearch-word 'isearch-message-prefix))
-                          "word ")
-                    "")
-                  (if isearch-regexp "regexp " "")
+                     prefix)
+                   (isearch--describe-regexp-mode isearch-regexp-function)
                   (cond
                    (multi-isearch-file-list "multi-file ")
                    (multi-isearch-buffer-list "multi-buffer ")
@@ -2565,38 +2641,41 @@ search for the first occurrence of STRING or its translation.")
 Can be changed via `isearch-search-fun-function' for special needs."
   (funcall (or isearch-search-fun-function 'isearch-search-fun-default)))
 
+(defun isearch--lax-regexp-function-p ()
+  "Non-nil if next regexp-function call should be lax."
+  (not (or isearch-nonincremental
+           (null (car isearch-cmds))
+           (eq (length isearch-string)
+               (length (isearch--state-string
+                        (car isearch-cmds)))))))
+
 (defun isearch-search-fun-default ()
   "Return default functions to use for the search."
-  (cond
-   (isearch-word
-    (lambda (string &optional bound noerror count)
-      ;; Use lax versions to not fail at the end of the word while
-      ;; the user adds and removes characters in the search string
-      ;; (or when using nonincremental word isearch)
-      (let ((lax (not (or isearch-nonincremental
-                         (null (car isearch-cmds))
-                         (eq (length isearch-string)
-                             (length (isearch--state-string
-                                       (car isearch-cmds))))))))
-       (funcall
-        (if isearch-forward #'re-search-forward #'re-search-backward)
-        (if (functionp isearch-word)
-            (funcall isearch-word string lax)
-          (word-search-regexp string lax))
-        bound noerror count))))
-   ((and isearch-regexp isearch-regexp-lax-whitespace
-        search-whitespace-regexp)
-    (if isearch-forward
-       're-search-forward-lax-whitespace
-      're-search-backward-lax-whitespace))
-   (isearch-regexp
-    (if isearch-forward 're-search-forward 're-search-backward))
-   ((and isearch-lax-whitespace search-whitespace-regexp)
-    (if isearch-forward
-       'search-forward-lax-whitespace
-      'search-backward-lax-whitespace))
-   (t
-    (if isearch-forward 'search-forward 'search-backward))))
+  (lambda (string &optional bound noerror count)
+    ;; Use lax versions to not fail at the end of the word while
+    ;; the user adds and removes characters in the search string
+    ;; (or when using nonincremental word isearch)
+    (let ((search-spaces-regexp (when (cond
+                                       (isearch-regexp isearch-regexp-lax-whitespace)
+                                       (t isearch-lax-whitespace))
+                                  search-whitespace-regexp)))
+      (condition-case er
+          (funcall
+           (if isearch-forward #'re-search-forward #'re-search-backward)
+           (cond (isearch-regexp-function
+                  (let ((lax (isearch--lax-regexp-function-p)))
+                    (if (functionp isearch-regexp-function)
+                        (funcall isearch-regexp-function string lax)
+                      (word-search-regexp string lax))))
+                 (isearch-regexp string)
+                 (t (regexp-quote string)))
+           bound noerror count)
+        (search-failed
+         (signal (car er)
+                 (let ((prefix (get isearch-regexp-function 'isearch-message-prefix)))
+                   (if (and isearch-regexp-function (stringp prefix))
+                       (list (format "%s   [using %ssearch]" string prefix))
+                     (cdr er)))))))))
 
 (defun isearch-search-string (string bound noerror)
   "Search for the first occurrence of STRING or its translation.
@@ -2686,7 +2765,7 @@ update the match data, and return point."
       ((and (not isearch-regexp)
            (string-match "\\`Regular expression too big" isearch-error))
        (cond
-       (isearch-word
+       (isearch-regexp-function
         (setq isearch-error "Too many words"))
        ((and isearch-lax-whitespace search-whitespace-regexp)
         (setq isearch-error "Too many spaces for whitespace matching"))))))
@@ -2717,17 +2796,12 @@ update the match data, and return point."
       ;; 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.
+    ;; Store the values for the `invisible' property, and then set it to nil.
+    ;; This way the text hidden by this overlay becomes visible.
 
-    ;; Do we really 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)))
+    (overlay-put ov 'invisible nil)))
 
 
 ;; This is called at the end of isearch.  It will open the overlays
@@ -2741,12 +2815,9 @@ update the match data, and return point."
        ;; 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
+      ;; restore the values for the `invisible' 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))
+      (overlay-put ov 'isearch-invisible nil))
     (if inside-overlay
        (funcall (overlay-get ov 'isearch-open-invisible)  ov)
       (if fct-temp
@@ -2784,9 +2855,7 @@ update the match data, and return point."
              ;; properties.
              (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)))))))
+           (overlay-put ov 'isearch-invisible nil)))))))
 
 
 (defun isearch-range-invisible (beg end)
@@ -2939,7 +3008,7 @@ since they have special meaning in a regexp."
 ;;  - `isearch-string' is expected to contain the current search
 ;;    string as entered by the user;
 ;;  - the type of the current search is expected to be given by
-;;    `isearch-word' and `isearch-regexp';
+;;    `isearch-regexp-function' and `isearch-regexp';
 ;;  - the direction of the current search is expected to be given by
 ;;    `isearch-forward';
 ;;  - the variable `isearch-error' is expected to be true
@@ -2960,7 +3029,9 @@ since they have special meaning in a regexp."
 (defvar isearch-lazy-highlight-regexp nil)
 (defvar isearch-lazy-highlight-lax-whitespace nil)
 (defvar isearch-lazy-highlight-regexp-lax-whitespace nil)
-(defvar isearch-lazy-highlight-word nil)
+(defvar isearch-lazy-highlight-regexp-function nil)
+(define-obsolete-variable-alias 'isearch-lazy-highlight-word
+  'isearch-lazy-highlight-regexp-function "25.1")
 (defvar isearch-lazy-highlight-forward nil)
 (defvar isearch-lazy-highlight-error nil)
 
@@ -2999,8 +3070,8 @@ by other Emacs features."
                          isearch-case-fold-search))
                 (not (eq isearch-lazy-highlight-regexp
                          isearch-regexp))
-                (not (eq isearch-lazy-highlight-word
-                         isearch-word))
+                (not (eq isearch-lazy-highlight-regexp-function
+                         isearch-regexp-function))
                 (not (eq isearch-lazy-highlight-lax-whitespace
                          isearch-lax-whitespace))
                 (not (eq isearch-lazy-highlight-regexp-lax-whitespace
@@ -3040,7 +3111,7 @@ by other Emacs features."
          isearch-lazy-highlight-regexp       isearch-regexp
          isearch-lazy-highlight-lax-whitespace   isearch-lax-whitespace
          isearch-lazy-highlight-regexp-lax-whitespace isearch-regexp-lax-whitespace
-         isearch-lazy-highlight-word         isearch-word
+         isearch-lazy-highlight-regexp-function  isearch-regexp-function
          isearch-lazy-highlight-forward      isearch-forward)
       (unless (equal isearch-string "")
        (setq isearch-lazy-highlight-timer
@@ -3053,7 +3124,7 @@ Attempt to do the search exactly the way the pending Isearch would."
   (condition-case nil
       (let ((case-fold-search isearch-lazy-highlight-case-fold-search)
            (isearch-regexp isearch-lazy-highlight-regexp)
-           (isearch-word isearch-lazy-highlight-word)
+           (isearch-regexp-function isearch-lazy-highlight-regexp-function)
            (isearch-lax-whitespace
             isearch-lazy-highlight-lax-whitespace)
            (isearch-regexp-lax-whitespace