+(defun isearch-fallback (want-backslash &optional allow-invalid to-barrier)
+ "Return point to previous successful match to allow regexp liberalization.
+\\<isearch-mode-map>
+Respects \\[isearch-repeat-forward] and \\[isearch-repeat-backward] by
+stopping at `isearch-barrier' as needed.
+
+Do nothing if a backslash is escaping the liberalizing character.
+If WANT-BACKSLASH is non-nil, invert this behavior (for \\} and \\|).
+
+Do nothing if regexp has recently been invalid unless optional
+ALLOW-INVALID non-nil.
+
+If optional TO-BARRIER non-nil, ignore previous matches and go exactly
+to the barrier."
+ ;; (eq (not a) (not b)) makes all non-nil values equivalent
+ (when (and isearch-regexp (eq (not (isearch-backslash isearch-string))
+ (not want-backslash))
+ ;; We have to check 2 stack frames because the last might be
+ ;; invalid just because of a backslash.
+ (or (not isearch-error)
+ (not (isearch-error-state (cadr isearch-cmds)))
+ allow-invalid))
+ (if to-barrier
+ (progn (goto-char isearch-barrier)
+ (setq isearch-adjusted t))
+ (let* ((stack isearch-cmds)
+ (previous (cdr stack)) ; lookbelow in the stack
+ (frame (car stack)))
+ ;; Walk down the stack looking for a valid regexp (as of course only
+ ;; they can be the previous successful match); this conveniently
+ ;; removes all bracket-sets and groups that might be in the way, as
+ ;; well as partial \{\} constructs that the code below leaves behind.
+ ;; Also skip over postfix operators -- though horrid,
+ ;; 'ab?\{5,6\}+\{1,2\}*' is perfectly legal.
+ (while (and previous
+ (or (isearch-error-state frame)
+ (let* ((string (isearch-string-state frame))
+ (lchar (aref string (1- (length string)))))
+ ;; The operators aren't always operators; check
+ ;; backslashes. This doesn't handle the case of
+ ;; operators at the beginning of the regexp not
+ ;; being special, but then we should fall back to
+ ;; the barrier anyway because it's all optional.
+ (if (isearch-backslash
+ (isearch-string-state (car previous)))
+ (eq lchar ?\})
+ (memq lchar '(?* ?? ?+))))))
+ (setq stack previous previous (cdr previous) frame (car stack)))
+ (when stack
+ ;; `stack' now refers the most recent valid regexp that is not at
+ ;; all optional in its last term. Now dig one level deeper and find
+ ;; what matched before that.
+ (let ((last-other-end
+ (or (and (car previous)
+ (isearch-other-end-state (car previous)))
+ isearch-barrier)))
+ (goto-char (if isearch-forward
+ (max last-other-end isearch-barrier)
+ (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
+;;
+;; The idea here is that certain vertical scrolling commands (like C-l
+;; `recenter') should be usable WITHIN Isearch mode. For a command to be
+;; suitable, it must NOT alter the buffer, swap to another buffer or frame,
+;; tamper with isearch's state, or move point. It is unacceptable for the
+;; search string to be scrolled out of the current window. If a command
+;; attempts this, we scroll the text back again.
+;;
+;; We implement this feature with a property called `isearch-scroll'.
+;; If a command's symbol has the value t for this property it is a
+;; scrolling command. The feature needs to be enabled by setting the
+;; customizable variable `isearch-allow-scroll' to a non-nil value.
+;;
+;; The universal argument commands (e.g. C-u) in simple.el are marked
+;; as scrolling commands, and isearch.el has been amended to allow
+;; prefix arguments to be passed through to scrolling commands. Thus
+;; M-0 C-l will scroll point to the top of the window.
+;;
+;; Horizontal scrolling commands are currently not catered for.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Set the isearch-scroll property on some standard functions:
+;; 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 'reposition-window 'isearch-scroll t)
+(put 'scroll-up 'isearch-scroll t)
+(put 'scroll-down 'isearch-scroll t)
+
+;; Commands which act on the other window
+(put 'list-buffers 'isearch-scroll t)
+(put 'scroll-other-window 'isearch-scroll t)
+(put 'scroll-other-window-down 'isearch-scroll t)
+(put 'beginning-of-buffer-other-window 'isearch-scroll t)
+(put 'end-of-buffer-other-window 'isearch-scroll t)
+
+;; Commands which change the window layout
+(put 'delete-other-windows 'isearch-scroll t)
+(put 'balance-windows 'isearch-scroll t)
+(put 'split-window-vertically 'isearch-scroll t)
+(put 'split-window-horizontally 'isearch-scroll t)
+(put 'enlarge-window 'isearch-scroll t)
+
+;; Universal argument commands
+(put 'universal-argument 'isearch-scroll t)
+(put 'negative-argument 'isearch-scroll t)
+(put 'digit-argument 'isearch-scroll t)
+
+(defcustom isearch-allow-scroll nil
+ "If non-nil, scrolling commands are allowed during incremental search."
+ :type 'boolean
+ :group 'isearch)
+
+(defun isearch-string-out-of-window (isearch-point)
+ "Test whether the search string is currently outside of the window.
+Return nil if it's completely visible, or if point is visible,
+together with as much of the search string as will fit; the symbol
+`above' if we need to scroll the text downwards; the symbol `below',
+if upwards."
+ (let ((w-start (window-start))
+ (w-end (window-end nil t))
+ (w-L1 (save-excursion (move-to-window-line 1) (point)))
+ (w-L-1 (save-excursion (move-to-window-line -1) (point)))
+ start end) ; start and end of search string in buffer
+ (if isearch-forward
+ (setq end isearch-point start (or isearch-other-end isearch-point))
+ (setq start isearch-point end (or isearch-other-end isearch-point)))
+ (cond ((or (and (>= start w-start) (<= end w-end))
+ (if isearch-forward
+ (and (>= isearch-point w-L-1) (< isearch-point w-end)) ; point on Line -1
+ (and (>= isearch-point w-start) (< isearch-point w-L1)))) ; point on Line 0
+ nil)
+ ((and (< start w-start)
+ (< isearch-point w-L-1))
+ 'above)
+ (t 'below))))
+
+(defun isearch-back-into-window (above isearch-point)
+ "Scroll the window to bring the search string back into view.
+Restore point to ISEARCH-POINT in the process. ABOVE is t when the
+search string is above the top of the window, nil when it is beneath
+the bottom."
+ (let (start end)
+ (if isearch-forward
+ (setq end isearch-point start (or isearch-other-end isearch-point))
+ (setq start isearch-point end (or isearch-other-end isearch-point)))
+ (if above
+ (progn
+ (goto-char start)
+ (recenter 0)
+ (when (>= isearch-point (window-end nil t))
+ (goto-char isearch-point)
+ (recenter -1)))
+ (goto-char end)
+ (recenter -1)
+ (when (< isearch-point (window-start))
+ (goto-char isearch-point)
+ (recenter 0))))
+ (goto-char isearch-point))
+
+(defun isearch-reread-key-sequence-naturally (keylist)
+ "Reread key sequence KEYLIST with Isearch mode's keymap deactivated.
+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)
+ (eq (get binding 'isearch-scroll) t)
+ binding)))