]> code.delx.au - gnu-emacs/blobdiff - lisp/isearch.el
Merge branch 'emacs-24'
[gnu-emacs] / lisp / isearch.el
index 345e7d8b4e96ec07bb6378784baacb87224a704a..c3e473a2ba6c9328407ea1148df3b94c4f7a700d 100644 (file)
@@ -1,9 +1,9 @@
 ;;; isearch.el --- incremental search minor mode
 
 ;;; isearch.el --- incremental search minor mode
 
-;; Copyright (C) 1992-1997, 1999-2013 Free Software Foundation, Inc.
+;; Copyright (C) 1992-1997, 1999-2014 Free Software Foundation, Inc.
 
 ;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
 
 ;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
-;; Maintainer: FSF
+;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: matching
 ;; Package: emacs
 
 ;; Keywords: matching
 ;; Package: emacs
 
@@ -131,12 +131,18 @@ a tab, a carriage return (control-M), a newline, and `]+'."
   :version "24.3")
 
 (defcustom search-invisible 'open
   :version "24.3")
 
 (defcustom search-invisible 'open
-  "If t incremental search can match hidden text.
+  "If t incremental search/query-replace can match hidden text.
 A nil value means don't match invisible text.
 When 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'.)
 A nil value means don't match invisible text.
 When 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'.)
+
+To temporarily change the value for an active incremental search,
+use \\<isearch-mode-map>\\[isearch-toggle-invisible].
+
+See also the related option `isearch-hide-immediately'.
+
 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)
 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)
@@ -147,9 +153,9 @@ whenever point is in one of them."
 (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'.
 (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."
+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)
 
   :type 'boolean
   :group 'isearch)
 
@@ -188,7 +194,7 @@ or to the end of the buffer for a backward search.")
 to the search status stack.")
 
 (defvar isearch-filter-predicate #'isearch-filter-visible
 to the search status stack.")
 
 (defvar isearch-filter-predicate #'isearch-filter-visible
-  "Predicate that filter the search hits that would normally be available.
+  "Predicate that filters the search hits that would normally be available.
 Search hits that dissatisfy the predicate are skipped.  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
 Search hits that dissatisfy the predicate are skipped.  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
@@ -349,7 +355,6 @@ A value of nil means highlight all matches."
 
 (defvar isearch-help-map
   (let ((map (make-sparse-keymap)))
 
 (defvar isearch-help-map
   (let ((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 (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)
@@ -423,9 +428,6 @@ This is like `describe-bindings', but displays only Isearch keys."
     ;; Make all multibyte characters search for themselves.
     (set-char-table-range (nth 1 map) (cons #x100 (max-char))
                          'isearch-printing-char)
     ;; Make all multibyte characters search for themselves.
     (set-char-table-range (nth 1 map) (cons #x100 (max-char))
                          'isearch-printing-char)
-    ;; Make function keys, etc, which aren't bound to a scrolling-function
-    ;; exit the search.
-    (define-key map [t] 'isearch-other-control-char)
 
     ;; Single-byte printing chars extend the search string by default.
     (setq i ?\s)
 
     ;; Single-byte printing chars extend the search string by default.
     (setq i ?\s)
@@ -439,9 +441,7 @@ This is like `describe-bindings', but displays only Isearch keys."
     ;; would be simpler to disable the global keymap, and/or have a
     ;; default local key binding for any key not otherwise bound.
     (let ((meta-map (make-sparse-keymap)))
     ;; would be simpler to disable the global keymap, and/or have a
     ;; default local key binding for any key not otherwise bound.
     (let ((meta-map (make-sparse-keymap)))
-      (define-key map (char-to-string meta-prefix-char) meta-map)
-      (define-key map [escape] meta-map)
-      (define-key meta-map [t] 'isearch-other-meta-char))
+      (define-key map (char-to-string meta-prefix-char) meta-map))
 
     ;; Several non-printing chars change the searching behavior.
     (define-key map "\C-s" 'isearch-repeat-forward)
 
     ;; Several non-printing chars change the searching behavior.
     (define-key map "\C-s" 'isearch-repeat-forward)
@@ -452,17 +452,18 @@ 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 "\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 "\C-g" 'isearch-abort)
 
     ;; This assumes \e is the meta-prefix-char.
     (or (= ?\e meta-prefix-char)
        (error "Inconsistency in isearch.el"))
     (define-key map "\e\e\e" 'isearch-cancel)
     (define-key map "\C-g" 'isearch-abort)
 
     ;; This assumes \e is the meta-prefix-char.
     (or (= ?\e meta-prefix-char)
        (error "Inconsistency in isearch.el"))
     (define-key map "\e\e\e" 'isearch-cancel)
-    (define-key map  [escape escape escape] 'isearch-cancel)
 
     (define-key map "\C-q" 'isearch-quote-char)
 
     (define-key map "\r" 'isearch-exit)
 
     (define-key map "\C-q" 'isearch-quote-char)
 
     (define-key map "\r" 'isearch-exit)
+    (define-key map [return] 'isearch-exit)
     (define-key map "\C-j" 'isearch-printing-char)
     (define-key map "\t" 'isearch-printing-char)
     (define-key map [?\S-\ ] 'isearch-printing-char)
     (define-key map "\C-j" 'isearch-printing-char)
     (define-key map "\t" 'isearch-printing-char)
     (define-key map [?\S-\ ] 'isearch-printing-char)
@@ -507,6 +508,11 @@ 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)
 
     (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-sc" 'isearch-toggle-case-fold)
     (define-key map "\M-si" 'isearch-toggle-invisible)
     (define-key map "\M-sr" 'isearch-toggle-regexp)
@@ -521,9 +527,6 @@ This is like `describe-bindings', but displays only Isearch keys."
 
     ;; The key translations defined in the C-x 8 prefix should add
     ;; characters to the search string.  See iso-transl.el.
 
     ;; The key translations defined in the C-x 8 prefix should add
     ;; characters to the search string.  See iso-transl.el.
-    (define-key map "\C-x" nil)
-    (define-key map [?\C-x t] 'isearch-other-control-char)
-    (define-key map "\C-x8" nil)
     (define-key map "\C-x8\r" 'isearch-char-by-name)
 
     map)
     (define-key map "\C-x8\r" 'isearch-char-by-name)
 
     map)
@@ -572,8 +575,8 @@ matches literally, against one space.  You can toggle the value of this
 variable by the command `isearch-toggle-lax-whitespace'.")
 
 (defvar isearch-cmds nil
 variable by the command `isearch-toggle-lax-whitespace'.")
 
 (defvar isearch-cmds nil
-  "Stack of search status sets.
-Each set is a vector of the form:
+  "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]")
 
  [STRING MESSAGE POINT SUCCESS FORWARD OTHER-END WORD
   INVALID-REGEXP WRAPPED BARRIER WITHIN-BRACKETS CASE-FOLD-SEARCH]")
 
@@ -645,6 +648,8 @@ Each set is a vector of the form:
 ;; isearch is invoked.
 (defvar isearch-input-method-local-p nil)
 
 ;; isearch is invoked.
 (defvar isearch-input-method-local-p nil)
 
+(defvar isearch--saved-overriding-local-map nil)
+
 ;; Minor-mode-alist changes - kind of redundant with the
 ;; echo area, but if isearching in multiple windows, it can be useful.
 
 ;; Minor-mode-alist changes - kind of redundant with the
 ;; echo area, but if isearching in multiple windows, it can be useful.
 
@@ -912,6 +917,9 @@ convert the search string to a regexp used by regexp search functions."
 
   (setq overriding-terminal-local-map isearch-mode-map)
   (run-hooks 'isearch-mode-hook)
 
   (setq overriding-terminal-local-map isearch-mode-map)
   (run-hooks 'isearch-mode-hook)
+  ;; Remember the initial map possibly modified
+  ;; by external packages in isearch-mode-hook.  (Bug#16035)
+  (setq isearch--saved-overriding-local-map overriding-terminal-local-map)
 
   ;; Pushing the initial state used to be before running isearch-mode-hook,
   ;; but a hook might set `isearch-push-state-function' used in
 
   ;; Pushing the initial state used to be before running isearch-mode-hook,
   ;; but a hook might set `isearch-push-state-function' used in
@@ -920,6 +928,8 @@ convert the search string to a regexp used by regexp search functions."
 
   (isearch-update)
 
 
   (isearch-update)
 
+  (add-hook 'pre-command-hook 'isearch-pre-command-hook)
+  (add-hook 'post-command-hook 'isearch-post-command-hook)
   (add-hook 'mouse-leave-buffer-hook 'isearch-done)
   (add-hook 'kbd-macro-termination-hook 'isearch-done)
 
   (add-hook 'mouse-leave-buffer-hook 'isearch-done)
   (add-hook 'kbd-macro-termination-hook 'isearch-done)
 
@@ -964,10 +974,17 @@ The last thing it does is to run `isearch-update-post-hook'."
                 (other-window 1))
               (goto-char found-point))
          ;; Keep same hscrolling as at the start of the search when possible
                 (other-window 1))
               (goto-char found-point))
          ;; Keep same hscrolling as at the start of the search when possible
-         (let ((current-scroll (window-hscroll)))
+         (let ((current-scroll (window-hscroll))
+               visible-p)
            (set-window-hscroll (selected-window) isearch-start-hscroll)
            (set-window-hscroll (selected-window) isearch-start-hscroll)
-           (unless (pos-visible-in-window-p)
-             (set-window-hscroll (selected-window) current-scroll))))
+           (setq visible-p (pos-visible-in-window-p nil nil t))
+           (if (or (not visible-p)
+                   ;; When point is not visible because of hscroll,
+                   ;; pos-visible-in-window-p returns non-nil, but
+                   ;; the X coordinate it returns is 1 pixel beyond
+                   ;; the last visible one.
+                   (>= (car visible-p) (window-body-width nil t)))
+               (set-window-hscroll (selected-window) current-scroll))))
        (if isearch-other-end
             (if (< isearch-other-end (point)) ; isearch-forward?
                 (isearch-highlight isearch-other-end (point))
        (if isearch-other-end
             (if (< isearch-other-end (point)) ; isearch-forward?
                 (isearch-highlight isearch-other-end (point))
@@ -998,6 +1015,8 @@ NOPUSH is t and EDIT is t."
        (unless (equal (car command-history) command)
          (setq command-history (cons command command-history)))))
 
        (unless (equal (car command-history) command)
          (setq command-history (cons command command-history)))))
 
+  (remove-hook 'pre-command-hook 'isearch-pre-command-hook)
+  (remove-hook 'post-command-hook 'isearch-post-command-hook)
   (remove-hook 'mouse-leave-buffer-hook 'isearch-done)
   (remove-hook 'kbd-macro-termination-hook 'isearch-done)
   (setq isearch-lazy-highlight-start nil)
   (remove-hook 'mouse-leave-buffer-hook 'isearch-done)
   (remove-hook 'kbd-macro-termination-hook 'isearch-done)
   (setq isearch-lazy-highlight-start nil)
@@ -1147,8 +1166,6 @@ nonincremental search instead via `isearch-edit-string'."
   (isearch-done)
   (isearch-clean-overlays))
 
   (isearch-done)
   (isearch-clean-overlays))
 
-(defvar minibuffer-history-symbol) ;; from external package gmhist.el
-
 (defun isearch-fail-pos (&optional msg)
   "Return position of first mismatch in search string, or nil if none.
 If MSG is non-nil, use variable `isearch-message', otherwise `isearch-string'."
 (defun isearch-fail-pos (&optional msg)
   "Return position of first mismatch in search string, or nil if none.
 If MSG is non-nil, use variable `isearch-message', otherwise `isearch-string'."
@@ -1301,6 +1318,8 @@ You can update the global isearch variables by setting new values to
      (isearch-abort)  ;; outside of let to restore outside global values
      )))
 
      (isearch-abort)  ;; outside of let to restore outside global values
      )))
 
+(defvar minibuffer-history-symbol) ;; from external package gmhist.el
+
 (defun isearch-edit-string ()
   "Edit the search string in the minibuffer.
 The following additional command keys are active while editing.
 (defun isearch-edit-string ()
   "Edit the search string in the minibuffer.
 The following additional command keys are active while editing.
@@ -1668,10 +1687,11 @@ the beginning or the end of the string need not match a symbol boundary."
     (re-search-backward regexp bound noerror count)))
 
 \f
     (re-search-backward regexp bound noerror count)))
 
 \f
-(defun isearch-query-replace (&optional delimited regexp-flag)
+(defun isearch-query-replace (&optional arg regexp-flag)
   "Start `query-replace' with string to replace from last search string.
   "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
+The ARG (prefix arg if interactive), if non-nil, means replace
+only matches surrounded by word boundaries.  A negative prefix
+arg means replace backward.  Note that using the prefix arg
 is possible only when `isearch-allow-scroll' is non-nil or
 `isearch-allow-prefix' is non-nil, and it doesn't always provide the
 correct matches for `query-replace', so the preferred way to run word
 is possible only when `isearch-allow-scroll' is non-nil or
 `isearch-allow-prefix' is non-nil, and it doesn't always provide the
 correct matches for `query-replace', so the preferred way to run word
@@ -1689,6 +1709,8 @@ replacements from Isearch is `M-s w ... M-%'."
         isearch-lax-whitespace)
        (replace-regexp-lax-whitespace
         isearch-regexp-lax-whitespace)
         isearch-lax-whitespace)
        (replace-regexp-lax-whitespace
         isearch-regexp-lax-whitespace)
+       (delimited (and arg (not (eq arg '-))))
+       (backward (and arg (eq arg '-)))
        ;; 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.
        ;; 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.
@@ -1697,9 +1719,13 @@ replacements from Isearch is `M-s w ... M-%'."
     (isearch-done nil t)
     (isearch-clean-overlays)
     (if (and isearch-other-end
     (isearch-done nil t)
     (isearch-clean-overlays)
     (if (and isearch-other-end
-            (< isearch-other-end (point))
+            (if backward
+                (> isearch-other-end (point))
+              (< isearch-other-end (point)))
              (not (and transient-mark-mode mark-active
              (not (and transient-mark-mode mark-active
-                       (< (mark) (point)))))
+                       (if backward
+                          (> (mark) (point))
+                        (< (mark) (point))))))
         (goto-char isearch-other-end))
     (set query-replace-from-history-variable
          (cons isearch-string
         (goto-char isearch-other-end))
     (set query-replace-from-history-variable
          (cons isearch-string
@@ -1719,19 +1745,21 @@ replacements from Isearch is `M-s w ... M-%'."
                      " word"))
                "")
              (if isearch-regexp " regexp" "")
                      " word"))
                "")
              (if isearch-regexp " regexp" "")
+             (if backward " backward" "")
              (if (and transient-mark-mode mark-active) " in region" ""))
       isearch-regexp)
      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) " in region" ""))
       isearch-regexp)
      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))
+     backward))
   (and isearch-recursive-edit (exit-recursive-edit)))
 
   (and isearch-recursive-edit (exit-recursive-edit)))
 
-(defun isearch-query-replace-regexp (&optional delimited)
+(defun isearch-query-replace-regexp (&optional arg)
   "Start `query-replace-regexp' with string to replace from last search string.
 See `isearch-query-replace' for more information."
   (interactive
    (list current-prefix-arg))
   "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))
+  (isearch-query-replace arg t))
 
 (defun isearch-occur (regexp &optional nlines)
   "Run `occur' using the last search string as the regexp.
 
 (defun isearch-occur (regexp &optional nlines)
   "Run `occur' using the last search string as the regexp.
@@ -1933,7 +1961,8 @@ or it might return the position of the end of the line."
     (forward-char arg)))
 
 (defun isearch-yank-char (&optional arg)
     (forward-char arg)))
 
 (defun isearch-yank-char (&optional arg)
-  "Pull next character from buffer into search string."
+  "Pull next character from buffer into search string.
+If optional ARG is non-nil, pull in the next ARG characters."
   (interactive "p")
   (isearch-yank-internal (lambda () (forward-char arg) (point))))
 
   (interactive "p")
   (isearch-yank-internal (lambda () (forward-char arg) (point))))
 
@@ -1946,18 +1975,22 @@ Subword is used when `subword-mode' is activated. "
    (lambda ()
      (if (or (= (char-syntax (or (char-after) 0)) ?w)
              (= (char-syntax (or (char-after (1+ (point))) 0)) ?w))
    (lambda ()
      (if (or (= (char-syntax (or (char-after) 0)) ?w)
              (= (char-syntax (or (char-after (1+ (point))) 0)) ?w))
-        (if (and (boundp 'subword-mode) subword-mode)
+        (if (or (and (boundp 'subword-mode) subword-mode)
+                (and (boundp 'superword-mode) superword-mode))
             (subword-forward 1)
           (forward-word 1))
             (subword-forward 1)
           (forward-word 1))
-       (forward-char 1)) (point))))
+       (forward-char 1))
+     (point))))
 
 (defun isearch-yank-word (&optional arg)
 
 (defun isearch-yank-word (&optional arg)
-  "Pull next word from buffer into search string."
+  "Pull next word from buffer into search string.
+If optional ARG is non-nil, pull in the next ARG words."
   (interactive "p")
   (isearch-yank-internal (lambda () (forward-word arg) (point))))
 
 (defun isearch-yank-line (&optional arg)
   (interactive "p")
   (isearch-yank-internal (lambda () (forward-word arg) (point))))
 
 (defun isearch-yank-line (&optional arg)
-  "Pull rest of line from buffer into search string."
+  "Pull rest of line from buffer into search string.
+If optional ARG is non-nil, yank the next ARG lines."
   (interactive "p")
   (isearch-yank-internal
    (lambda () (let ((inhibit-field-text-motion t))
   (interactive "p")
   (isearch-yank-internal
    (lambda () (let ((inhibit-field-text-motion t))
@@ -2100,26 +2133,6 @@ to the barrier."
                         (min last-other-end isearch-barrier)))
            (setq isearch-adjusted t)))))))
 
                         (min last-other-end isearch-barrier)))
            (setq isearch-adjusted t)))))))
 
-(defun isearch-unread-key-sequence (keylist)
-  "Unread the given key-sequence KEYLIST.
-Scroll-bar or mode-line events are processed appropriately."
-  (cancel-kbd-macro-events)
-  (apply 'isearch-unread keylist)
-  ;; If the event was a scroll-bar or mode-line click, the event will have
-  ;; been prefixed by a symbol such as vertical-scroll-bar.  We must remove
-  ;; it here, because this symbol will be attached to the event again next
-  ;; time it gets read by read-key-sequence.
-  ;;
-  ;; (Old comment from isearch-other-meta-char: "Note that we don't have to
-  ;; modify the event anymore in 21 because read_key_sequence no longer
-  ;; modifies events to produce fake prefix keys.")
-  (if (and (> (length keylist) 1)
-           (symbolp (car keylist))
-           (listp (cadr keylist))
-           (not (numberp (posn-point
-                          (event-start (cadr keylist)  )))))
-      (pop unread-command-events)))
-
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; scrolling within Isearch mode.  Alan Mackenzie (acm@muc.de), 2003/2/24
 ;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; scrolling within Isearch mode.  Alan Mackenzie (acm@muc.de), 2003/2/24
 ;;
@@ -2244,185 +2257,68 @@ the bottom."
         (recenter 0))))
   (goto-char isearch-point))
 
         (recenter 0))))
   (goto-char isearch-point))
 
-(defun isearch-reread-key-sequence-naturally (keylist)
-  "Reread key sequence KEYLIST with an inactive Isearch-mode keymap.
-Return the key sequence as a string/vector."
-  (isearch-unread-key-sequence keylist)
-  (let (overriding-terminal-local-map)
-    (read-key-sequence nil)))  ; This will go through function-key-map, if nec.
-
-(defun isearch-lookup-scroll-key (key-seq)
-  "If KEY-SEQ is bound to a scrolling command, return it as a symbol.
-Otherwise return nil."
-  (let* ((overriding-terminal-local-map nil)
-         (binding (key-binding key-seq)))
-    (and binding (symbolp binding) (commandp binding)
-         (or (eq (get binding 'isearch-scroll) t)
-            (eq (get binding 'scroll-command) t))
-         binding)))
-
-(defalias 'isearch-other-control-char 'isearch-other-meta-char)
-
-(defun isearch-other-meta-char (&optional arg)
-  "Process a miscellaneous key sequence in Isearch mode.
-
-Try to convert the current key-sequence to something usable in Isearch
-mode, either by converting it with `function-key-map', downcasing a
-key with C-<upper case>, or finding a \"scrolling command\" bound to
-it.  \(In the last case, we may have to read more events.)  If so,
-either unread the converted sequence or execute the command.
-
-Otherwise, if `search-exit-option' is non-nil (the default) unread the
-key-sequence and exit the search normally.  If it is the symbol
-`edit', the search string is edited in the minibuffer and the meta
-character is unread so that it applies to editing the string.
-
-ARG is the prefix argument.  It will be transmitted through to the
-scrolling command or to the command whose key-sequence exits
-Isearch mode."
-  (interactive "P")
-  (let* ((key (if current-prefix-arg    ; not nec the same as ARG
-                  (substring (this-command-keys) universal-argument-num-events)
-                (this-command-keys)))
-        (main-event (aref key 0))
-        (keylist (listify-key-sequence key))
-         scroll-command isearch-point)
-    (cond ((and (= (length key) 1)
-               (let ((lookup (lookup-key local-function-key-map key)))
-                 (not (or (null lookup) (integerp lookup)
-                          (keymapp lookup)))))
-          ;; Handle a function key that translates into something else.
-          ;; If the key has a global definition too,
-          ;; exit and unread the key itself, so its global definition runs.
-          ;; Otherwise, unread the translation,
-          ;; so that the translated key takes effect within isearch.
-          (cancel-kbd-macro-events)
-          (if (lookup-key global-map key)
-              (progn
-                (isearch-done)
-                (setq prefix-arg arg)
-                (apply 'isearch-unread keylist))
-            (setq keylist
-                  (listify-key-sequence
-                   (lookup-key local-function-key-map key)))
-            (while keylist
-              (setq key (car keylist))
-              ;; If KEY is a printing char, we handle it here
-              ;; directly to avoid the input method and keyboard
-              ;; coding system translating it.
-              (if (and (integerp key)
-                       (>= key ?\s) (/= key 127) (< key 256))
-                  (progn
-                    ;; Ensure that the processed char is recorded in
-                    ;; the keyboard macro, if any (Bug#4894)
-                    (store-kbd-macro-event key)
-                    (isearch-process-search-char key)
-                    (setq keylist (cdr keylist)))
-                ;; As the remaining keys in KEYLIST can't be handled
-                ;; here, we must reread them.
-                (setq prefix-arg arg)
-                (apply 'isearch-unread keylist)
-                (setq keylist nil)))))
-         (
-          ;; Handle an undefined shifted control character
-          ;; by downshifting it if that makes it defined.
-          ;; (As read-key-sequence would normally do,
-          ;; if we didn't have a default definition.)
-          (let ((mods (event-modifiers main-event)))
-            (and (integerp main-event)
-                 (memq 'shift mods)
-                 (memq 'control mods)
-                 (not (memq (lookup-key isearch-mode-map
-                                        (let ((copy (copy-sequence key)))
-                                          (aset copy 0
-                                                (- main-event
-                                                   (- ?\C-\S-a ?\C-a)))
-                                          copy)
-                                        nil)
-                            '(nil
-                              isearch-other-control-char)))))
-          (setcar keylist (- main-event (- ?\C-\S-a ?\C-a)))
-          (cancel-kbd-macro-events)
-          (setq prefix-arg arg)
-          (apply 'isearch-unread keylist))
-         ((eq search-exit-option 'edit)
-          (setq prefix-arg arg)
-          (apply 'isearch-unread keylist)
-          (isearch-edit-string))
-          ;; Handle a scrolling function or prefix argument.
-          ((progn
-            (setq key (isearch-reread-key-sequence-naturally keylist)
-                  keylist (listify-key-sequence key)
-                  main-event (aref key 0))
-            (or (and isearch-allow-scroll
-                     (setq scroll-command (isearch-lookup-scroll-key key)))
-                (and isearch-allow-prefix
-                     (let (overriding-terminal-local-map)
-                       (setq scroll-command (key-binding key))
-                       (memq scroll-command
-                             '(universal-argument
-                               negative-argument digit-argument))))))
-           ;; From this point onwards, KEY, KEYLIST and MAIN-EVENT hold a
-           ;; complete key sequence, possibly as modified by function-key-map,
-           ;; not merely the one or two event fragment which invoked
-           ;; isearch-other-meta-char in the first place.
-           (setq isearch-point (point))
-           (setq prefix-arg arg)
-           (command-execute scroll-command)
-           (let ((ab-bel (isearch-string-out-of-window isearch-point)))
-             (if ab-bel
-                 (isearch-back-into-window (eq ab-bel 'above) isearch-point)
-               (goto-char isearch-point)))
-           (isearch-update))
-         ;; A mouse click on the isearch message starts editing the search string
-         ((and (eq (car-safe main-event) 'down-mouse-1)
-               (window-minibuffer-p (posn-window (event-start main-event))))
-          ;; Swallow the up-event.
-          (read-event)
-          (isearch-edit-string))
-         (search-exit-option
-          (let (window)
-            (setq prefix-arg arg)
-             (isearch-unread-key-sequence keylist)
-             (setq main-event (car unread-command-events))
-
-            ;; If we got a mouse click event, that event contains the
-            ;; window clicked on. maybe it was read with the buffer
-            ;; it was clicked on.  If so, that buffer, not the current one,
-            ;; is in isearch mode.  So end the search in that buffer.
-
-            ;; ??? I have no idea what this if checks for, but it's
-            ;; obviously wrong for the case that a down-mouse event
-            ;; on another window invokes this function.  The event
-            ;; will contain the window clicked on and that window's
-            ;; buffer is certainly not always in Isearch mode.
-            ;;
-            ;; Leave the code in, but check for current buffer not
-            ;; being in Isearch mode for now, until someone tells
-            ;; what it's really supposed to do.
-            ;;
-            ;; --gerd 2001-08-10.
-
-            (if (and (not isearch-mode)
-                     (listp main-event)
-                     (setq window (posn-window (event-start main-event)))
-                     (windowp window)
-                     (or (> (minibuffer-depth) 0)
-                         (not (window-minibuffer-p window))))
-                (with-current-buffer (window-buffer window)
-                  (isearch-done)
-                  (isearch-clean-overlays))
-              (isearch-done)
-              (isearch-clean-overlays)
-               (setq prefix-arg arg))))
-          (t;; otherwise nil
-          (isearch-process-search-string key key)))))
+(defvar isearch-pre-scroll-point nil)
+
+(defun isearch-pre-command-hook ()
+  "Decide whether to exit Isearch mode before executing the command.
+Don't exit Isearch if the key sequence that invoked this command
+is bound in `isearch-mode-map', or if the invoked command is
+a prefix argument command (when `isearch-allow-prefix' is non-nil),
+or it is a scrolling command (when `isearch-allow-scroll' is non-nil).
+Otherwise, exit Isearch (when `search-exit-option' is non-nil)
+before the command is executed globally with terminated Isearch."
+  (let* ((key (this-single-command-keys))
+        (main-event (aref key 0)))
+    (cond
+     ;; Don't exit Isearch if we're in the middle of some
+     ;; `set-transient-map' thingy like `universal-argument--mode'.
+     ((not (eq overriding-terminal-local-map isearch--saved-overriding-local-map)))
+     ;; Don't exit Isearch for isearch key bindings.
+     ((commandp (lookup-key isearch-mode-map key nil)))
+     ;; Optionally edit the search string instead of exiting.
+     ((eq search-exit-option 'edit)
+      (setq this-command 'isearch-edit-string))
+     ;; Handle a scrolling function or prefix argument.
+     ((or (and isearch-allow-prefix
+              (memq this-command '(universal-argument
+                                   digit-argument negative-argument)))
+         (and isearch-allow-scroll
+              (symbolp this-command)
+              (or (eq (get this-command 'isearch-scroll) t)
+                  (eq (get this-command 'scroll-command) t))))
+      (when isearch-allow-scroll
+       (setq isearch-pre-scroll-point (point))))
+     ;; A mouse click on the isearch message starts editing the search string.
+     ((and (eq (car-safe main-event) 'down-mouse-1)
+          (window-minibuffer-p (posn-window (event-start main-event))))
+      ;; Swallow the up-event.
+      (read-event)
+      (setq this-command 'isearch-edit-string))
+     ;; Other characters terminate the search and are then executed normally.
+     (search-exit-option
+      (isearch-done)
+      (isearch-clean-overlays))
+     ;; If search-exit-option is nil, run the command without exiting Isearch.
+     (t
+      (isearch-process-search-string key key)))))
+
+(defun isearch-post-command-hook ()
+  (when isearch-pre-scroll-point
+    (let ((ab-bel (isearch-string-out-of-window isearch-pre-scroll-point)))
+      (if ab-bel
+         (isearch-back-into-window (eq ab-bel 'above) isearch-pre-scroll-point)
+       (goto-char isearch-pre-scroll-point)))
+    (setq isearch-pre-scroll-point nil)
+    (isearch-update)))
 
 (defun isearch-quote-char (&optional count)
   "Quote special characters for incremental search.
 With argument, add COUNT copies of the character."
   (interactive "p")
   (let ((char (read-quoted-char (isearch-message t))))
 
 (defun isearch-quote-char (&optional count)
   "Quote special characters for incremental search.
 With argument, add COUNT copies of the character."
   (interactive "p")
   (let ((char (read-quoted-char (isearch-message t))))
+    (unless (characterp char)
+      (user-error "%s is not a valid character"
+                 (key-description (vector char))))
     ;; Assume character codes 0200 - 0377 stand for characters in some
     ;; single-byte character set, and convert them to Emacs
     ;; characters.
     ;; Assume character codes 0200 - 0377 stand for characters in some
     ;; single-byte character set, and convert them to Emacs
     ;; characters.
@@ -2625,7 +2521,10 @@ If there is no completion possible, say so and continue searching."
                           "word ")
                     "")
                   (if isearch-regexp "regexp " "")
                           "word ")
                     "")
                   (if isearch-regexp "regexp " "")
-                  (if multi-isearch-next-buffer-current-function "multi " "")
+                  (cond
+                   (multi-isearch-file-list "multi-file ")
+                   (multi-isearch-buffer-list "multi-buffer ")
+                   (t ""))
                   (or isearch-message-prefix-add "")
                   (if nonincremental "search" "I-search")
                   (if isearch-forward "" " backward")
                   (or isearch-message-prefix-add "")
                   (if nonincremental "search" "I-search")
                   (if isearch-forward "" " backward")
@@ -2777,10 +2676,18 @@ update the match data, and return point."
 
     (invalid-regexp
      (setq isearch-error (car (cdr lossage)))
 
     (invalid-regexp
      (setq isearch-error (car (cdr lossage)))
-     (if (string-match
-         "\\`Premature \\|\\`Unmatched \\|\\`Invalid "
-         isearch-error)
-        (setq isearch-error "incomplete input")))
+     (cond
+      ((string-match
+       "\\`Premature \\|\\`Unmatched \\|\\`Invalid "
+       isearch-error)
+       (setq isearch-error "incomplete input"))
+      ((and (not isearch-regexp)
+           (string-match "\\`Regular expression too big" isearch-error))
+       (cond
+       (isearch-word
+        (setq isearch-error "Too many words"))
+       ((and isearch-lax-whitespace search-whitespace-regexp)
+        (setq isearch-error "Too many spaces for whitespace matching"))))))
 
     (search-failed
      (setq isearch-success nil)
 
     (search-failed
      (setq isearch-success nil)
@@ -2976,8 +2883,12 @@ since they have special meaning in a regexp."
 
 (defun isearch-text-char-description (c)
   (cond
 
 (defun isearch-text-char-description (c)
   (cond
-   ((< c ?\s) (propertize (format "^%c" (+ c 64)) 'face 'escape-glyph))
-   ((= c ?\^?) (propertize "^?" 'face 'escape-glyph))
+   ((< c ?\s) (propertize
+              (char-to-string c)
+              'display (propertize (format "^%c" (+ c 64)) 'face 'escape-glyph)))
+   ((= c ?\^?) (propertize
+               (char-to-string c)
+               'display (propertize "^?" 'face 'escape-glyph)))
    (t (char-to-string c))))
 
 ;; General function to unread characters or events.
    (t (char-to-string c))))
 
 ;; General function to unread characters or events.