LCOV - code coverage report
Current view: top level - lisp - isearch.el (source / functions) Hit Total Coverage
Test: tramp-tests-after.info Lines: 21 1149 1.8 %
Date: 2017-08-30 10:12:24 Functions: 2 115 1.7 %

          Line data    Source code
       1             : ;;; isearch.el --- incremental search minor mode -*- lexical-binding: t -*-
       2             : 
       3             : ;; Copyright (C) 1992-1997, 1999-2017 Free Software Foundation, Inc.
       4             : 
       5             : ;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
       6             : ;; Maintainer: emacs-devel@gnu.org
       7             : ;; Keywords: matching
       8             : ;; Package: emacs
       9             : 
      10             : ;; This file is part of GNU Emacs.
      11             : 
      12             : ;; GNU Emacs is free software: you can redistribute it and/or modify
      13             : ;; it under the terms of the GNU General Public License as published by
      14             : ;; the Free Software Foundation, either version 3 of the License, or
      15             : ;; (at your option) any later version.
      16             : 
      17             : ;; GNU Emacs is distributed in the hope that it will be useful,
      18             : ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
      19             : ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20             : ;; GNU General Public License for more details.
      21             : 
      22             : ;; You should have received a copy of the GNU General Public License
      23             : ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
      24             : 
      25             : ;;; Commentary:
      26             : 
      27             : ;; Instructions
      28             : 
      29             : ;; For programmed use of isearch-mode, e.g. calling (isearch-forward),
      30             : ;; isearch-mode behaves modally and does not return until the search
      31             : ;; is completed.  It uses a recursive-edit to behave this way.
      32             : 
      33             : ;; The key bindings active within isearch-mode are defined below in
      34             : ;; `isearch-mode-map'.  Also see minibuffer-local-isearch-map
      35             : ;; for bindings active during `isearch-edit-string'.
      36             : 
      37             : ;; isearch-mode should work even if you switch windows with the mouse,
      38             : ;; in which case isearch-mode is terminated automatically before the
      39             : ;; switch.
      40             : 
      41             : ;; The search ring and completion commands automatically put you in
      42             : ;; the minibuffer to edit the string.  This gives you a chance to
      43             : ;; modify the search string before executing the search.  There are
      44             : ;; three commands to terminate the editing: C-s and C-r exit the
      45             : ;; minibuffer and search forward and reverse respectively, while C-m
      46             : ;; exits and searches in the last search direction.
      47             : 
      48             : ;; Exiting immediately from isearch uses isearch-edit-string instead
      49             : ;; of nonincremental-search, if search-nonincremental-instead is non-nil.
      50             : ;; The name of this option should probably be changed if we decide to
      51             : ;; keep the behavior.  No point in forcing nonincremental search until
      52             : ;; the last possible moment.
      53             : 
      54             : ;;; Code:
      55             : 
      56             : (eval-when-compile (require 'cl-lib))
      57             : 
      58             : ;; Some additional options and constants.
      59             : 
      60             : (defgroup isearch nil
      61             :   "Incremental search minor mode."
      62             :   :link '(emacs-commentary-link "isearch")
      63             :   :link '(custom-manual "(emacs)Incremental Search")
      64             :   :prefix "isearch-"
      65             :   :prefix "search-"
      66             :   :group 'matching)
      67             : 
      68             : 
      69             : (defcustom search-exit-option t
      70             :   "Non-nil means random control characters terminate incremental search."
      71             :   :type 'boolean)
      72             : 
      73             : (defcustom search-slow-window-lines 1
      74             :   "Number of lines in slow search display windows.
      75             : These are the short windows used during incremental search on slow terminals.
      76             : Negative means put the slow search window at the top (normally it's at bottom)
      77             : and the value is minus the number of lines."
      78             :   :type 'integer)
      79             : 
      80             : (defcustom search-slow-speed 1200
      81             :   "Highest terminal speed at which to use \"slow\" style incremental search.
      82             : This is the style where a one-line window is created to show the line
      83             : that the search has reached."
      84             :   :type 'integer)
      85             : 
      86             : (defcustom search-upper-case 'not-yanks
      87             :   "If non-nil, upper case chars disable case fold searching.
      88             : That is, upper and lower case chars must match exactly.
      89             : This applies no matter where the chars come from, but does not
      90             : apply to chars in regexps that are prefixed with `\\'.
      91             : If this value is `not-yanks', text yanked into the search string
      92             : in Isearch mode is always downcased."
      93             :   :type '(choice (const :tag "off" nil)
      94             :                  (const not-yanks)
      95             :                  (other :tag "on" t)))
      96             : 
      97             : (defcustom search-nonincremental-instead t
      98             :   "If non-nil, do a nonincremental search instead of exiting immediately.
      99             : This affects the behavior of `isearch-exit' and any key bound to that
     100             : command: if this variable is nil, `isearch-exit' always exits the search;
     101             : if the value is non-nil, and the search string is empty, `isearch-exit'
     102             : starts a nonincremental search instead.  (Actually, `isearch-edit-string'
     103             : is called to let you enter the search string, and RET terminates editing
     104             : and does a nonincremental search.)"
     105             :   :type 'boolean)
     106             : 
     107             : (defcustom search-whitespace-regexp (purecopy "\\s-+")
     108             :   "If non-nil, regular expression to match a sequence of whitespace chars.
     109             : When you enter a space or spaces in the incremental search, it
     110             : will match any sequence matched by this regexp.  As an exception,
     111             : spaces are treated normally in regexp incremental search if they
     112             : occur in a regexp construct like [...] or *, + or ?.
     113             : 
     114             : If the value is a string, it applies to both ordinary and
     115             : regexp incremental search.  If the value is nil, or
     116             : `isearch-lax-whitespace' is nil for ordinary incremental search, or
     117             : `isearch-regexp-lax-whitespace' is nil for regexp incremental search,
     118             : then each space you type matches literally, against one space.
     119             : 
     120             : You might want to use something like \"[ \\t\\r\\n]+\" instead.
     121             : In the Customization buffer, that is `[' followed by a space,
     122             : a tab, a carriage return (control-M), a newline, and `]+'."
     123             :   :type '(choice (const :tag "Match Spaces Literally" nil)
     124             :                  regexp)
     125             :   :version "24.3")
     126             : 
     127             : (defcustom search-invisible 'open
     128             :   "If t incremental search/query-replace can match hidden text.
     129             : A nil value means don't match invisible text.
     130             : When the value is `open', if the text matched is made invisible by
     131             : an overlay having an `invisible' property and that overlay has a property
     132             : `isearch-open-invisible', then incremental search will show the contents.
     133             : \(This applies when using `outline.el' and `hideshow.el'.)
     134             : 
     135             : To temporarily change the value for an active incremental search,
     136             : use \\<isearch-mode-map>\\[isearch-toggle-invisible].
     137             : 
     138             : See also the related option `isearch-hide-immediately'.
     139             : 
     140             : See also `reveal-mode' if you want overlays to automatically be opened
     141             : whenever point is in one of them."
     142             :   :type '(choice (const :tag "Match hidden text" t)
     143             :                  (const :tag "Open overlays" open)
     144             :                  (const :tag "Don't match hidden text" nil)))
     145             : 
     146             : (defcustom isearch-hide-immediately t
     147             :   "If non-nil, re-hide an invisible match right away.
     148             : This variable makes a difference when `search-invisible' is set to `open'.
     149             : If non-nil, invisible matches are re-hidden as soon as the match moves
     150             : off the invisible text surrounding the match.
     151             : If nil then do not re-hide opened invisible text when the match moves.
     152             : Whatever the value, all opened invisible text is hidden again after exiting
     153             : the search, with the exception of the last successful match, if any."
     154             :   :type 'boolean)
     155             : 
     156             : (defcustom isearch-resume-in-command-history nil
     157             :   "If non-nil, `isearch-resume' commands are added to the command history.
     158             : This allows you to resume earlier Isearch sessions through the
     159             : command history."
     160             :   :type 'boolean)
     161             : 
     162             : (defvar isearch-mode-hook nil
     163             :   "Function(s) to call after starting up an incremental search.")
     164             : 
     165             : (defvar isearch-update-post-hook nil
     166             :   "Function(s) to call after isearch has found matches in the buffer.")
     167             : 
     168             : (defvar isearch-mode-end-hook nil
     169             :   "Function(s) to call after terminating an incremental search.
     170             : When these functions are called, `isearch-mode-end-hook-quit'
     171             : is non-nil if the user quits the search.")
     172             : 
     173             : (defvar isearch-mode-end-hook-quit nil
     174             :   "Non-nil while running `isearch-mode-end-hook' if the user quits the search.")
     175             : 
     176             : (defvar isearch-message-function nil
     177             :   "Function to call to display the search prompt.
     178             : If nil, use function `isearch-message'.")
     179             : 
     180             : (defvar isearch-wrap-function nil
     181             :   "Function to call to wrap the search when search is failed.
     182             : If nil, move point to the beginning of the buffer for a forward search,
     183             : or to the end of the buffer for a backward search.")
     184             : 
     185             : (defvar isearch-push-state-function nil
     186             :   "Function to save a function restoring the mode-specific Isearch state
     187             : to the search status stack.")
     188             : 
     189             : (defvar isearch-filter-predicate #'isearch-filter-visible
     190             :   "Predicate that filters the search hits that would normally be available.
     191             : Search hits that dissatisfy the predicate are skipped.  The function
     192             : has two arguments: the positions of start and end of text matched by
     193             : the search.  If this function returns nil, continue searching without
     194             : stopping at this match.
     195             : If you use `add-function' to modify this variable, you can use the
     196             : `isearch-message-prefix' advice property to specify the prefix string
     197             : displayed in the search message.")
     198             : 
     199             : ;; Search ring.
     200             : 
     201             : (defvar search-ring nil
     202             :   "List of search string sequences.")
     203             : (defvar regexp-search-ring nil
     204             :   "List of regular expression search string sequences.")
     205             : 
     206             : (defcustom search-ring-max 16
     207             :   "Maximum length of search ring before oldest elements are thrown away."
     208             :   :type 'integer)
     209             : (defcustom regexp-search-ring-max 16
     210             :   "Maximum length of regexp search ring before oldest elements are thrown away."
     211             :   :type 'integer)
     212             : 
     213             : (defvar search-ring-yank-pointer nil
     214             :   "Index in `search-ring' of last string reused.
     215             : It is nil if none yet.")
     216             : (defvar regexp-search-ring-yank-pointer nil
     217             :   "Index in `regexp-search-ring' of last string reused.
     218             : It is nil if none yet.")
     219             : 
     220             : (defcustom search-ring-update nil
     221             :   "Non-nil if advancing or retreating in the search ring should cause search.
     222             : Default value, nil, means edit the string instead."
     223             :   :type 'boolean)
     224             : 
     225             : (autoload 'char-fold-to-regexp "char-fold")
     226             : 
     227             : (defcustom search-default-mode nil
     228             :   "Default mode to use when starting isearch.
     229             : Value is nil, t, or a function.
     230             : 
     231             : If nil, default to literal searches (note that `case-fold-search'
     232             : and `isearch-lax-whitespace' may still be applied).\\<isearch-mode-map>
     233             : If t, default to regexp searches (as if typing `\\[isearch-toggle-regexp]' during
     234             : isearch).
     235             : 
     236             : If a function, use that function as an `isearch-regexp-function'.
     237             : Example functions (and the keys to toggle them during isearch)
     238             : are `word-search-regexp' \(`\\[isearch-toggle-word]'), `isearch-symbol-regexp'
     239             : \(`\\[isearch-toggle-symbol]'), and `char-fold-to-regexp' \(`\\[isearch-toggle-char-fold]')."
     240             :   ;; :type is set below by `isearch-define-mode-toggle'.
     241             :   :type '(choice (const :tag "Literal search" nil)
     242             :                  (const :tag "Regexp search" t)
     243             :                  (function :tag "Other"))
     244             :   :version "25.1")
     245             : 
     246             : ;;; isearch highlight customization.
     247             : 
     248             : (defcustom search-highlight t
     249             :   "Non-nil means incremental search highlights the current match."
     250             :   :type 'boolean)
     251             : 
     252             : (defface isearch
     253             :   '((((class color) (min-colors 88) (background light))
     254             :      ;; The background must not be too dark, for that means
     255             :      ;; the character is hard to see when the cursor is there.
     256             :      (:background "magenta3" :foreground "lightskyblue1"))
     257             :     (((class color) (min-colors 88) (background dark))
     258             :      (:background "palevioletred2" :foreground "brown4"))
     259             :     (((class color) (min-colors 16))
     260             :      (:background "magenta4" :foreground "cyan1"))
     261             :     (((class color) (min-colors 8))
     262             :      (:background "magenta4" :foreground "cyan1"))
     263             :     (t (:inverse-video t)))
     264             :   "Face for highlighting Isearch matches."
     265             :   :group 'isearch
     266             :   :group 'basic-faces)
     267             : (defvar isearch-face 'isearch)
     268             : 
     269             : (defface isearch-fail
     270             :   '((((class color) (min-colors 88) (background light))
     271             :      (:background "RosyBrown1"))
     272             :     (((class color) (min-colors 88) (background dark))
     273             :      (:background "red4"))
     274             :     (((class color) (min-colors 16))
     275             :      (:background "red"))
     276             :     (((class color) (min-colors 8))
     277             :      (:background "red"))
     278             :     (((class color grayscale))
     279             :      :foreground "grey")
     280             :     (t (:inverse-video t)))
     281             :   "Face for highlighting failed part in Isearch echo-area message."
     282             :   :version "23.1")
     283             : 
     284             : (defcustom isearch-lazy-highlight t
     285             :   "Controls the lazy-highlighting during incremental search.
     286             : When non-nil, all text in the buffer matching the current search
     287             : string is highlighted lazily (see `lazy-highlight-initial-delay'
     288             : and `lazy-highlight-interval').
     289             : 
     290             : When multiple windows display the current buffer, the
     291             : highlighting is displayed only on the selected window, unless
     292             : this variable is set to the symbol `all-windows'."
     293             :   :type '(choice boolean
     294             :                  (const :tag "On, and applied to all windows" all-windows))
     295             :   :group 'lazy-highlight
     296             :   :group 'isearch)
     297             : 
     298             : ;;; Lazy highlight customization.
     299             : 
     300             : (defgroup lazy-highlight nil
     301             :   "Lazy highlighting feature for matching strings."
     302             :   :prefix "lazy-highlight-"
     303             :   :version "21.1"
     304             :   :group 'isearch
     305             :   :group 'matching)
     306             : 
     307             : (define-obsolete-variable-alias 'isearch-lazy-highlight-cleanup
     308             :                                 'lazy-highlight-cleanup
     309             :                                 "22.1")
     310             : 
     311             : (defcustom lazy-highlight-cleanup t
     312             :   "Controls whether to remove extra highlighting after a search.
     313             : If this is nil, extra highlighting can be \"manually\" removed with
     314             : \\[lazy-highlight-cleanup]."
     315             :   :type 'boolean
     316             :   :group 'lazy-highlight)
     317             : 
     318             : (define-obsolete-variable-alias 'isearch-lazy-highlight-initial-delay
     319             :                                 'lazy-highlight-initial-delay
     320             :                                 "22.1")
     321             : 
     322             : (defcustom lazy-highlight-initial-delay 0.25
     323             :   "Seconds to wait before beginning to lazily highlight all matches."
     324             :   :type 'number
     325             :   :group 'lazy-highlight)
     326             : 
     327             : (define-obsolete-variable-alias 'isearch-lazy-highlight-interval
     328             :                                 'lazy-highlight-interval
     329             :                                 "22.1")
     330             : 
     331             : (defcustom lazy-highlight-interval 0 ; 0.0625
     332             :   "Seconds between lazily highlighting successive matches."
     333             :   :type 'number
     334             :   :group 'lazy-highlight)
     335             : 
     336             : (define-obsolete-variable-alias 'isearch-lazy-highlight-max-at-a-time
     337             :                                 'lazy-highlight-max-at-a-time
     338             :                                 "22.1")
     339             : 
     340             : (defcustom lazy-highlight-max-at-a-time nil ; 20 (bug#25751)
     341             :   "Maximum matches to highlight at a time (for `lazy-highlight').
     342             : Larger values may reduce Isearch's responsiveness to user input;
     343             : smaller values make matches highlight slowly.
     344             : A value of nil means highlight all matches shown on the screen."
     345             :   :type '(choice (const :tag "All" nil)
     346             :                  (integer :tag "Some"))
     347             :   :group 'lazy-highlight)
     348             : 
     349             : (defface lazy-highlight
     350             :   '((((class color) (min-colors 88) (background light))
     351             :      (:background "paleturquoise"))
     352             :     (((class color) (min-colors 88) (background dark))
     353             :      (:background "paleturquoise4"))
     354             :     (((class color) (min-colors 16))
     355             :      (:background "turquoise3"))
     356             :     (((class color) (min-colors 8))
     357             :      (:background "turquoise3"))
     358             :     (t (:underline t)))
     359             :   "Face for lazy highlighting of matches other than the current one."
     360             :   :group 'lazy-highlight
     361             :   :group 'basic-faces)
     362             : 
     363             : 
     364             : ;; Define isearch help map.
     365             : 
     366             : (defvar isearch-help-map
     367             :   (let ((map (make-sparse-keymap)))
     368             :     (define-key map (char-to-string help-char) 'isearch-help-for-help)
     369             :     (define-key map [help] 'isearch-help-for-help)
     370             :     (define-key map [f1] 'isearch-help-for-help)
     371             :     (define-key map "?" 'isearch-help-for-help)
     372             :     (define-key map "b" 'isearch-describe-bindings)
     373             :     (define-key map "k" 'isearch-describe-key)
     374             :     (define-key map "m" 'isearch-describe-mode)
     375             :     (define-key map "q" 'help-quit)
     376             :     map)
     377             :   "Keymap for characters following the Help key for Isearch mode.")
     378             : 
     379             : (eval-when-compile (require 'help-macro))
     380             : 
     381             : (make-help-screen isearch-help-for-help-internal
     382             :   (purecopy "Type a help option: [bkm] or ?")
     383             :   "You have typed %THIS-KEY%, the help character.  Type a Help option:
     384             : \(Type \\<help-map>\\[help-quit] to exit the Help command.)
     385             : 
     386             : b           Display all Isearch key bindings.
     387             : k KEYS      Display full documentation of Isearch key sequence.
     388             : m           Display documentation of Isearch mode.
     389             : 
     390             : You can't type here other help keys available in the global help map,
     391             : but outside of this help window when you type them in Isearch mode,
     392             : they exit Isearch mode before displaying global help."
     393             :   isearch-help-map)
     394             : 
     395             : (defvar isearch--display-help-action '(nil (inhibit-same-window . t)))
     396             : 
     397             : (defun isearch-help-for-help ()
     398             :   "Display Isearch help menu."
     399             :   (interactive)
     400           0 :   (let ((display-buffer-overriding-action isearch--display-help-action))
     401           0 :     (isearch-help-for-help-internal))
     402           0 :   (isearch-update))
     403             : 
     404             : (defun isearch-describe-bindings ()
     405             :   "Show a list of all keys defined in Isearch mode, and their definitions.
     406             : This is like `describe-bindings', but displays only Isearch keys."
     407             :   (interactive)
     408           0 :   (let ((display-buffer-overriding-action isearch--display-help-action))
     409           0 :     (with-help-window "*Help*"
     410           0 :       (with-current-buffer standard-output
     411           0 :         (princ "Isearch Mode Bindings:\n")
     412           0 :         (princ (substitute-command-keys "\\{isearch-mode-map}"))))))
     413             : 
     414             : (defun isearch-describe-key ()
     415             :   "Display documentation of the function invoked by isearch key."
     416             :   (interactive)
     417           0 :   (let ((display-buffer-overriding-action isearch--display-help-action))
     418           0 :     (call-interactively 'describe-key))
     419           0 :   (isearch-update))
     420             : 
     421             : (defun isearch-describe-mode ()
     422             :   "Display documentation of Isearch mode."
     423             :   (interactive)
     424           0 :   (let ((display-buffer-overriding-action isearch--display-help-action))
     425           0 :     (describe-function 'isearch-forward))
     426           0 :   (isearch-update))
     427             : 
     428             : (defalias 'isearch-mode-help 'isearch-describe-mode)
     429             : 
     430             : 
     431             : ;; Define isearch-mode keymap.
     432             : 
     433             : (defvar isearch-mode-map
     434             :   (let ((i 0)
     435             :         (map (make-keymap)))
     436             :     (or (char-table-p (nth 1 map))
     437             :         (error "The initialization of isearch-mode-map must be updated"))
     438             :     ;; Make all multibyte characters search for themselves.
     439             :     (set-char-table-range (nth 1 map) (cons #x100 (max-char))
     440             :                           'isearch-printing-char)
     441             : 
     442             :     ;; Single-byte printing chars extend the search string by default.
     443             :     (setq i ?\s)
     444             :     (while (< i 256)
     445             :       (define-key map (vector i) 'isearch-printing-char)
     446             :       (setq i (1+ i)))
     447             : 
     448             :     ;; To handle local bindings with meta char prefix keys, define
     449             :     ;; another full keymap.  This must be done for any other prefix
     450             :     ;; keys as well, one full keymap per char of the prefix key.  It
     451             :     ;; would be simpler to disable the global keymap, and/or have a
     452             :     ;; default local key binding for any key not otherwise bound.
     453             :     (let ((meta-map (make-sparse-keymap)))
     454             :       (define-key map (char-to-string meta-prefix-char) meta-map))
     455             : 
     456             :     ;; Several non-printing chars change the searching behavior.
     457             :     (define-key map "\C-s" 'isearch-repeat-forward)
     458             :     (define-key map "\C-r" 'isearch-repeat-backward)
     459             :     ;; Define M-C-s and M-C-r like C-s and C-r so that the same key
     460             :     ;; combinations can be used to repeat regexp isearches that can
     461             :     ;; be used to start these searches.
     462             :     (define-key map "\M-\C-s" 'isearch-repeat-forward)
     463             :     (define-key map "\M-\C-r" 'isearch-repeat-backward)
     464             :     (define-key map "\177" 'isearch-delete-char)
     465             :     (define-key map [backspace] 'undefined) ;bug#20466.
     466             :     (define-key map "\C-g" 'isearch-abort)
     467             : 
     468             :     ;; This assumes \e is the meta-prefix-char.
     469             :     (or (= ?\e meta-prefix-char)
     470             :         (error "Inconsistency in isearch.el"))
     471             :     (define-key map "\e\e\e" 'isearch-cancel)
     472             : 
     473             :     (define-key map "\C-q" 'isearch-quote-char)
     474             : 
     475             :     (define-key map "\r" 'isearch-exit)
     476             :     (define-key map [return] 'isearch-exit)
     477             :     (define-key map "\C-j" 'isearch-printing-char)
     478             :     (define-key map "\t" 'isearch-printing-char)
     479             :     (define-key map [?\S-\ ] 'isearch-printing-char)
     480             : 
     481             :     (define-key map    "\C-w" 'isearch-yank-word-or-char)
     482             :     (define-key map "\M-\C-w" 'isearch-del-char)
     483             :     (define-key map "\M-\C-y" 'isearch-yank-char)
     484             :     (define-key map    "\C-y" 'isearch-yank-kill)
     485             :     (define-key map "\M-s\C-e" 'isearch-yank-line)
     486             : 
     487             :     (define-key map (char-to-string help-char) isearch-help-map)
     488             :     (define-key map [help] isearch-help-map)
     489             :     (define-key map [f1] isearch-help-map)
     490             : 
     491             :     (define-key map "\M-n" 'isearch-ring-advance)
     492             :     (define-key map "\M-p" 'isearch-ring-retreat)
     493             :     (define-key map "\M-y" 'isearch-yank-pop)
     494             : 
     495             :     (define-key map "\M-\t" 'isearch-complete)
     496             : 
     497             :     ;; Pass frame events transparently so they won't exit the search.
     498             :     ;; In particular, if we have more than one display open, then a
     499             :     ;; switch-frame might be generated by someone typing at another keyboard.
     500             :     (define-key map [switch-frame] nil)
     501             :     (define-key map [delete-frame] nil)
     502             :     (define-key map [iconify-frame] nil)
     503             :     (define-key map [make-frame-visible] nil)
     504             :     (define-key map [mouse-movement] nil)
     505             :     (define-key map [language-change] nil)
     506             : 
     507             :     ;; For searching multilingual text.
     508             :     (define-key map "\C-\\" 'isearch-toggle-input-method)
     509             :     (define-key map "\C-^" 'isearch-toggle-specified-input-method)
     510             : 
     511             :     ;; People expect to be able to paste with the mouse.
     512             :     (define-key map [mouse-2] #'isearch-mouse-2)
     513             :     (define-key map [down-mouse-2] nil)
     514             :     (define-key map [xterm-paste] #'isearch-xterm-paste)
     515             : 
     516             :     ;; Some bindings you may want to put in your isearch-mode-hook.
     517             :     ;; Suggest some alternates...
     518             :     (define-key map "\M-c" 'isearch-toggle-case-fold)
     519             :     (define-key map "\M-r" 'isearch-toggle-regexp)
     520             :     (define-key map "\M-e" 'isearch-edit-string)
     521             : 
     522             :     (put 'isearch-edit-string      :advertised-binding "\M-se")
     523             : 
     524             :     (define-key map "\M-se" 'isearch-edit-string)
     525             :     ;; More toggles defined by `isearch-define-mode-toggle'.
     526             : 
     527             :     (define-key map [?\M-%] 'isearch-query-replace)
     528             :     (define-key map [?\C-\M-%] 'isearch-query-replace-regexp)
     529             :     (define-key map "\M-so" 'isearch-occur)
     530             :     (define-key map "\M-shr" 'isearch-highlight-regexp)
     531             : 
     532             :     ;; The key translations defined in the C-x 8 prefix should add
     533             :     ;; characters to the search string.  See iso-transl.el.
     534             :     (define-key map "\C-x8\r" 'isearch-char-by-name)
     535             : 
     536             :     map)
     537             :   "Keymap for `isearch-mode'.")
     538             : 
     539             : (defvar minibuffer-local-isearch-map
     540             :   (let ((map (make-sparse-keymap)))
     541             :     (set-keymap-parent map minibuffer-local-map)
     542             :     (define-key map "\r"    'exit-minibuffer)
     543             :     (define-key map "\M-\t" 'isearch-complete-edit)
     544             :     (define-key map "\C-s"  'isearch-forward-exit-minibuffer)
     545             :     (define-key map "\C-r"  'isearch-reverse-exit-minibuffer)
     546             :     (define-key map "\C-f"  'isearch-yank-char-in-minibuffer)
     547             :     (define-key map [right] 'isearch-yank-char-in-minibuffer)
     548             :     map)
     549             :   "Keymap for editing Isearch strings in the minibuffer.")
     550             : 
     551             : ;; Internal variables declared globally for byte-compiler.
     552             : ;; These are all set with setq while isearching
     553             : ;; and bound locally while editing the search string.
     554             : 
     555             : (defvar isearch-forward nil)    ; Searching in the forward direction.
     556             : (defvar isearch-regexp nil)     ; Searching for a regexp.
     557             : (defvar isearch-regexp-function nil
     558             :   "Regexp-based search mode for words/symbols.
     559             : If the value is a function (e.g. `isearch-symbol-regexp'), it is
     560             : called to convert a plain search string to a regexp used by
     561             : regexp search functions.
     562             : The symbol property `isearch-message-prefix' put on this function
     563             : specifies the prefix string displayed in the search message.
     564             : 
     565             : This variable is set and changed during isearch.  To change the
     566             : default behavior used for searches, see `search-default-mode'
     567             : instead.")
     568             : ;; We still support setting this to t for backwards compatibility.
     569             : (define-obsolete-variable-alias 'isearch-word
     570             :   'isearch-regexp-function "25.1")
     571             : 
     572             : (defvar isearch-lax-whitespace t
     573             :   "If non-nil, a space will match a sequence of whitespace chars.
     574             : When you enter a space or spaces in ordinary incremental search, it
     575             : will match any sequence matched by the regexp defined by the variable
     576             : `search-whitespace-regexp'.  If the value is nil, each space you type
     577             : matches literally, against one space.  You can toggle the value of this
     578             : variable by the command `isearch-toggle-lax-whitespace'.")
     579             : 
     580             : (defvar isearch-regexp-lax-whitespace nil
     581             :   "If non-nil, a space will match a sequence of whitespace chars.
     582             : When you enter a space or spaces in regexp incremental search, it
     583             : will match any sequence matched by the regexp defined by the variable
     584             : `search-whitespace-regexp'.  If the value is nil, each space you type
     585             : matches literally, against one space.  You can toggle the value of this
     586             : variable by the command `isearch-toggle-lax-whitespace'.")
     587             : 
     588             : (defvar isearch-cmds nil
     589             :   "Stack of search status elements.
     590             : Each element is an `isearch--state' struct where the slots are
     591             :  [STRING MESSAGE POINT SUCCESS FORWARD OTHER-END WORD
     592             :   ERROR WRAPPED BARRIER CASE-FOLD-SEARCH]")
     593             : 
     594             : (defvar isearch-string "")  ; The current search string.
     595             : (defvar isearch-message "") ; text-char-description version of isearch-string
     596             : 
     597             : (defvar isearch-message-prefix-add nil) ; Additional text for the message prefix
     598             : (defvar isearch-message-suffix-add nil) ; Additional text for the message suffix
     599             : 
     600             : (defvar isearch-success t)      ; Searching is currently successful.
     601             : (defvar isearch-error nil)      ; Error message for failed search.
     602             : (defvar isearch-other-end nil)  ; Start (end) of match if forward (backward).
     603             : (defvar isearch-wrapped nil)    ; Searching restarted from the top (bottom).
     604             : (defvar isearch-barrier 0
     605             :   "Recorded minimum/maximal point for the current search.")
     606             : (defvar isearch-just-started nil)
     607             : (defvar isearch-start-hscroll 0)        ; hscroll when starting the search.
     608             : 
     609             : ;; case-fold-search while searching.
     610             : ;;   either nil, t, or 'yes.  'yes means the same as t except that mixed
     611             : ;;   case in the search string is ignored.
     612             : (defvar isearch-case-fold-search nil)
     613             : 
     614             : ;; search-invisible while searching.
     615             : ;;   either nil, t, or 'open.  'open means the same as t except that
     616             : ;;   opens hidden overlays.
     617             : (defvar isearch-invisible search-invisible)
     618             : 
     619             : (defvar isearch-last-case-fold-search nil)
     620             : 
     621             : ;; Used to save default value while isearch is active
     622             : (defvar isearch-original-minibuffer-message-timeout nil)
     623             : 
     624             : (defvar isearch-adjusted nil)
     625             : (defvar isearch-slow-terminal-mode nil)
     626             : ;; If t, using a small window.
     627             : (defvar isearch-small-window nil)
     628             : (defvar isearch-opoint 0)
     629             : ;; The window configuration active at the beginning of the search.
     630             : (defvar isearch-window-configuration nil)
     631             : 
     632             : ;; Flag to indicate a yank occurred, so don't move the cursor.
     633             : (defvar isearch-yank-flag nil)
     634             : 
     635             : ;; A function to be called after each input character is processed.
     636             : ;; (It is not called after characters that exit the search.)
     637             : ;; It is only set from an optional argument to `isearch-mode'.
     638             : (defvar isearch-op-fun nil)
     639             : 
     640             : ;;  Is isearch-mode in a recursive edit for modal searching.
     641             : (defvar isearch-recursive-edit nil)
     642             : 
     643             : ;; Should isearch be terminated after doing one search?
     644             : (defvar isearch-nonincremental nil)
     645             : 
     646             : ;; New value of isearch-nonincremental after isearch-edit-string.
     647             : (defvar isearch-new-nonincremental nil)
     648             : 
     649             : ;; New value of isearch-forward after isearch-edit-string.
     650             : (defvar isearch-new-forward nil)
     651             : 
     652             : ;; Accumulate here the overlays opened during searching.
     653             : (defvar isearch-opened-overlays nil)
     654             : 
     655             : ;; Non-nil if the string exists but is invisible.
     656             : (defvar isearch-hidden nil)
     657             : 
     658             : ;; The value of input-method-function when isearch is invoked.
     659             : (defvar isearch-input-method-function nil)
     660             : 
     661             : ;; A flag to tell if input-method-function is locally bound when
     662             : ;; isearch is invoked.
     663             : (defvar isearch-input-method-local-p nil)
     664             : 
     665             : (defvar isearch--saved-overriding-local-map nil)
     666             : 
     667             : ;; Minor-mode-alist changes - kind of redundant with the
     668             : ;; echo area, but if isearching in multiple windows, it can be useful.
     669             : 
     670             : (or (assq 'isearch-mode minor-mode-alist)
     671             :     (nconc minor-mode-alist
     672             :            (list '(isearch-mode isearch-mode))))
     673             : 
     674             : (defvar-local isearch-mode nil) ;; Name of the minor mode, if non-nil.
     675             : 
     676             : (define-key global-map "\C-s" 'isearch-forward)
     677             : (define-key esc-map "\C-s" 'isearch-forward-regexp)
     678             : (define-key global-map "\C-r" 'isearch-backward)
     679             : (define-key esc-map "\C-r" 'isearch-backward-regexp)
     680             : (define-key search-map "w" 'isearch-forward-word)
     681             : (define-key search-map "_" 'isearch-forward-symbol)
     682             : (define-key search-map "." 'isearch-forward-symbol-at-point)
     683             : 
     684             : ;; Entry points to isearch-mode.
     685             : 
     686             : (defun isearch-forward (&optional regexp-p no-recursive-edit)
     687             :   "\
     688             : Do incremental search forward.
     689             : With a prefix argument, do an incremental regular expression search instead.
     690             : \\<isearch-mode-map>
     691             : As you type characters, they add to the search string and are found.
     692             : The following non-printing keys are bound in `isearch-mode-map'.
     693             : 
     694             : Type \\[isearch-delete-char] to cancel last input item from end of search string.
     695             : Type \\[isearch-exit] to exit, leaving point at location found.
     696             : Type LFD (C-j) to match end of line.
     697             : Type \\[isearch-repeat-forward] to search again forward,\
     698             :  \\[isearch-repeat-backward] to search again backward.
     699             : Type \\[isearch-yank-word-or-char] to yank next word or character in buffer
     700             :   onto the end of the search string, and search for it.
     701             : Type \\[isearch-del-char] to delete character from end of search string.
     702             : Type \\[isearch-yank-char] to yank char from buffer onto end of search\
     703             :  string and search for it.
     704             : Type \\[isearch-yank-line] to yank rest of line onto end of search string\
     705             :  and search for it.
     706             : Type \\[isearch-yank-kill] to yank the last string of killed text.
     707             : Type \\[isearch-yank-pop] to replace string just yanked into search prompt
     708             :  with string killed before it.
     709             : Type \\[isearch-quote-char] to quote control character to search for it.
     710             : Type \\[isearch-char-by-name] to add a character to search by Unicode name,\
     711             :  with completion.
     712             : \\[isearch-abort] while searching or when search has failed cancels input\
     713             :  back to what has
     714             :  been found successfully.
     715             : \\[isearch-abort] when search is successful aborts and moves point to\
     716             :  starting point.
     717             : 
     718             : If you try to exit with the search string still empty, it invokes
     719             :  nonincremental search.
     720             : 
     721             : Type \\[isearch-toggle-case-fold] to toggle search case-sensitivity.
     722             : Type \\[isearch-toggle-invisible] to toggle search in invisible text.
     723             : Type \\[isearch-toggle-regexp] to toggle regular-expression mode.
     724             : Type \\[isearch-toggle-word] to toggle word mode.
     725             : Type \\[isearch-toggle-symbol] to toggle symbol mode.
     726             : Type \\[isearch-toggle-char-fold] to toggle character folding.
     727             : 
     728             : Type \\[isearch-toggle-lax-whitespace] to toggle whitespace matching.
     729             : In incremental searches, a space or spaces normally matches any whitespace
     730             : defined by the variable `search-whitespace-regexp'; see also the variables
     731             : `isearch-lax-whitespace' and `isearch-regexp-lax-whitespace'.
     732             : 
     733             : Type \\[isearch-edit-string] to edit the search string in the minibuffer.
     734             : 
     735             : Also supported is a search ring of the previous 16 search strings.
     736             : Type \\[isearch-ring-advance] to search for the next item in the search ring.
     737             : Type \\[isearch-ring-retreat] to search for the previous item in the search\
     738             :  ring.
     739             : Type \\[isearch-complete] to complete the search string using the search ring.
     740             : 
     741             : Type \\[isearch-query-replace] to run `query-replace' with string to\
     742             :  replace from last search string.
     743             : Type \\[isearch-query-replace-regexp] to run `query-replace-regexp'\
     744             :  with the last search string.
     745             : Type \\[isearch-occur] to run `occur' that shows\
     746             :  the last search string.
     747             : Type \\[isearch-highlight-regexp] to run `highlight-regexp'\
     748             :  that highlights the last search string.
     749             : 
     750             : Type \\[isearch-describe-bindings] to display all Isearch key bindings.
     751             : Type \\[isearch-describe-key] to display documentation of Isearch key.
     752             : Type \\[isearch-describe-mode] to display documentation of Isearch mode.
     753             : 
     754             : If an input method is turned on in the current buffer, that input
     755             : method is also active while you are typing characters to search.
     756             : To toggle the input method, type \\[isearch-toggle-input-method].  \
     757             : It also toggles the input
     758             : method in the current buffer.
     759             : 
     760             : To use a different input method for searching, type \
     761             : \\[isearch-toggle-specified-input-method],
     762             : and specify an input method you want to use.
     763             : 
     764             : The above keys, bound in `isearch-mode-map', are often controlled by
     765             :  options; do \\[apropos] on search-.* to find them.
     766             : Other control and meta characters terminate the search
     767             :  and are then executed normally (depending on `search-exit-option').
     768             : Likewise for function keys and mouse button events.
     769             : 
     770             : If this function is called non-interactively with a nil NO-RECURSIVE-EDIT,
     771             : it does not return to the calling function until the search is done.
     772             : See the function `isearch-mode' for more information."
     773             : 
     774             :   (interactive "P\np")
     775           0 :   (isearch-mode t (not (null regexp-p)) nil (not no-recursive-edit)))
     776             : 
     777             : (defun isearch-forward-regexp (&optional not-regexp no-recursive-edit)
     778             :   "Do incremental search forward for regular expression.
     779             : With a prefix argument, do a regular string search instead.
     780             : Like ordinary incremental search except that your input is treated
     781             : as a regexp.  See the command `isearch-forward' for more information.
     782             : 
     783             : In incremental searches, a space or spaces normally matches any
     784             : whitespace defined by the variable `search-whitespace-regexp'.
     785             : To search for a literal space and nothing else, enter C-q SPC.
     786             : To toggle whitespace matching, use `isearch-toggle-lax-whitespace'.
     787             : This command does not support character folding."
     788             :   (interactive "P\np")
     789           0 :   (isearch-mode t (null not-regexp) nil (not no-recursive-edit)))
     790             : 
     791             : (defun isearch-forward-word (&optional not-word no-recursive-edit)
     792             :   "Do incremental search forward for a sequence of words.
     793             : With a prefix argument, do a regular string search instead.
     794             : Like ordinary incremental search except that your input is treated
     795             : as a sequence of words without regard to how the words are separated.
     796             : See the command `isearch-forward' for more information.
     797             : This command does not support character folding, and lax space matching
     798             : has no effect on it."
     799             :   (interactive "P\np")
     800           0 :   (isearch-mode t nil nil (not no-recursive-edit) (null not-word)))
     801             : 
     802             : (defun isearch-forward-symbol (&optional _not-symbol no-recursive-edit)
     803             :   "Do incremental search forward for a symbol.
     804             : The prefix argument is currently unused.
     805             : Like ordinary incremental search except that your input is treated
     806             : as a symbol surrounded by symbol boundary constructs \\_< and \\_>.
     807             : See the command `isearch-forward' for more information.
     808             : This command does not support character folding, and lax space matching
     809             : has no effect on it."
     810             :   (interactive "P\np")
     811           0 :   (isearch-mode t nil nil (not no-recursive-edit) 'isearch-symbol-regexp))
     812             : 
     813             : (defun isearch-backward (&optional regexp-p no-recursive-edit)
     814             :   "Do incremental search backward.
     815             : With a prefix argument, do a regular expression search instead.
     816             : See the command `isearch-forward' for more information."
     817             :   (interactive "P\np")
     818           0 :   (isearch-mode nil (not (null regexp-p)) nil (not no-recursive-edit)))
     819             : 
     820             : (defun isearch-backward-regexp (&optional not-regexp no-recursive-edit)
     821             :   "Do incremental search backward for regular expression.
     822             : With a prefix argument, do a regular string search instead.
     823             : Like ordinary incremental search except that your input is treated
     824             : as a regexp.  See the command `isearch-forward-regexp' for more information."
     825             :   (interactive "P\np")
     826           0 :   (isearch-mode nil (null not-regexp) nil (not no-recursive-edit)))
     827             : 
     828             : (defun isearch-forward-symbol-at-point ()
     829             :   "Do incremental search forward for a symbol found near point.
     830             : Like ordinary incremental search except that the symbol found at point
     831             : is added to the search string initially as a regexp surrounded
     832             : by symbol boundary constructs \\_< and \\_>.
     833             : See the command `isearch-forward-symbol' for more information."
     834             :   (interactive)
     835           0 :   (isearch-forward-symbol nil 1)
     836           0 :   (let ((bounds (find-tag-default-bounds)))
     837           0 :     (cond
     838           0 :      (bounds
     839           0 :       (when (< (car bounds) (point))
     840           0 :         (goto-char (car bounds)))
     841           0 :       (isearch-yank-string
     842           0 :        (buffer-substring-no-properties (car bounds) (cdr bounds))))
     843             :      (t
     844           0 :       (setq isearch-error "No symbol at point")
     845           0 :       (isearch-push-state)
     846           0 :       (isearch-update)))))
     847             : 
     848             : 
     849             : ;; isearch-mode only sets up incremental search for the minor mode.
     850             : ;; All the work is done by the isearch-mode commands.
     851             : 
     852             : ;; Not used yet:
     853             : ;;(defvar isearch-commands '(isearch-forward isearch-backward
     854             : ;;                           isearch-forward-regexp isearch-backward-regexp)
     855             : ;;  "List of commands for which isearch-mode does not recursive-edit.")
     856             : 
     857             : (defun isearch-mode (forward &optional regexp op-fun recursive-edit regexp-function)
     858             :   "Start Isearch minor mode.
     859             : It is called by the function `isearch-forward' and other related functions.
     860             : 
     861             : The non-nil arg FORWARD means searching in the forward direction.
     862             : 
     863             : The non-nil arg REGEXP does an incremental regular expression search.
     864             : 
     865             : The arg OP-FUN is a function to be called after each input character
     866             : is processed.  (It is not called after characters that exit the search.)
     867             : 
     868             : When the arg RECURSIVE-EDIT is non-nil, this function behaves modally and
     869             : does not return to the calling function until the search is completed.
     870             : To behave this way it enters a recursive-edit and exits it when done
     871             : isearching.
     872             : 
     873             : The arg REGEXP-FUNCTION, if non-nil, should be a function.  It is
     874             : used to set the value of `isearch-regexp-function'."
     875             : 
     876             :   ;; Initialize global vars.
     877           0 :   (setq isearch-forward forward
     878           0 :         isearch-regexp (or regexp
     879           0 :                            (and (not regexp-function)
     880           0 :                                 (eq search-default-mode t)))
     881           0 :         isearch-regexp-function (or regexp-function
     882           0 :                                     (and (functionp search-default-mode)
     883           0 :                                          (not regexp)
     884           0 :                                          search-default-mode))
     885           0 :         isearch-op-fun op-fun
     886           0 :         isearch-last-case-fold-search isearch-case-fold-search
     887           0 :         isearch-case-fold-search case-fold-search
     888           0 :         isearch-invisible search-invisible
     889             :         isearch-string ""
     890             :         isearch-message ""
     891             :         isearch-cmds nil
     892             :         isearch-success t
     893             :         isearch-wrapped nil
     894           0 :         isearch-barrier (point)
     895             :         isearch-adjusted nil
     896             :         isearch-yank-flag nil
     897             :         isearch-error nil
     898           0 :         isearch-slow-terminal-mode (and (<= baud-rate search-slow-speed)
     899           0 :                                         (> (window-height)
     900           0 :                                            (* 4
     901           0 :                                               (abs search-slow-window-lines))))
     902             :         isearch-other-end nil
     903             :         isearch-small-window nil
     904             :         isearch-just-started t
     905           0 :         isearch-start-hscroll (window-hscroll)
     906             : 
     907           0 :         isearch-opoint (point)
     908             :         search-ring-yank-pointer nil
     909             :         isearch-opened-overlays nil
     910           0 :         isearch-input-method-function input-method-function
     911           0 :         isearch-input-method-local-p (local-variable-p 'input-method-function)
     912             :         regexp-search-ring-yank-pointer nil
     913             : 
     914             :         ;; Save the original value of `minibuffer-message-timeout', and
     915             :         ;; set it to nil so that isearch's messages don't get timed out.
     916           0 :         isearch-original-minibuffer-message-timeout minibuffer-message-timeout
     917           0 :         minibuffer-message-timeout nil)
     918             : 
     919             :   ;; We must bypass input method while reading key.  When a user type
     920             :   ;; printable character, appropriate input method is turned on in
     921             :   ;; minibuffer to read multibyte characters.
     922           0 :   (or isearch-input-method-local-p
     923           0 :       (make-local-variable 'input-method-function))
     924           0 :   (setq input-method-function nil)
     925             : 
     926           0 :   (looking-at "")
     927           0 :   (setq isearch-window-configuration
     928           0 :         (if isearch-slow-terminal-mode (current-window-configuration) nil))
     929             : 
     930             :   ;; Maybe make minibuffer frame visible and/or raise it.
     931           0 :   (let ((frame (window-frame (minibuffer-window))))
     932           0 :     (unless (memq (frame-live-p frame) '(nil t))
     933           0 :       (unless (frame-visible-p frame)
     934           0 :         (make-frame-visible frame))
     935           0 :       (if minibuffer-auto-raise
     936           0 :           (raise-frame frame))))
     937             : 
     938           0 :   (setq isearch-mode " Isearch")  ;; forward? regexp?
     939           0 :   (force-mode-line-update)
     940             : 
     941           0 :   (setq overriding-terminal-local-map isearch-mode-map)
     942           0 :   (run-hooks 'isearch-mode-hook)
     943             :   ;; Remember the initial map possibly modified
     944             :   ;; by external packages in isearch-mode-hook.  (Bug#16035)
     945           0 :   (setq isearch--saved-overriding-local-map overriding-terminal-local-map)
     946             : 
     947             :   ;; Pushing the initial state used to be before running isearch-mode-hook,
     948             :   ;; but a hook might set `isearch-push-state-function' used in
     949             :   ;; `isearch-push-state' to save mode-specific initial state.  (Bug#4994)
     950           0 :   (isearch-push-state)
     951             : 
     952           0 :   (isearch-update)
     953             : 
     954           0 :   (add-hook 'pre-command-hook 'isearch-pre-command-hook)
     955           0 :   (add-hook 'post-command-hook 'isearch-post-command-hook)
     956           0 :   (add-hook 'mouse-leave-buffer-hook 'isearch-done)
     957           0 :   (add-hook 'kbd-macro-termination-hook 'isearch-done)
     958             : 
     959             :   ;; isearch-mode can be made modal (in the sense of not returning to
     960             :   ;; the calling function until searching is completed) by entering
     961             :   ;; a recursive-edit and exiting it when done isearching.
     962           0 :   (if recursive-edit
     963           0 :       (let ((isearch-recursive-edit t))
     964           0 :         (recursive-edit)))
     965           0 :   isearch-success)
     966             : 
     967             : 
     968             : ;; Some high level utilities.  Others below.
     969             : (defvar isearch--current-buffer nil)
     970             : 
     971             : (defun isearch-update ()
     972             :   "This is called after every isearch command to update the display.
     973             : The second last thing it does is to run `isearch-update-post-hook'.
     974             : The last thing is to trigger a new round of lazy highlighting."
     975           0 :   (unless (eq (current-buffer) isearch--current-buffer)
     976           0 :     (when (buffer-live-p isearch--current-buffer)
     977           0 :       (with-current-buffer isearch--current-buffer
     978           0 :         (setq cursor-sensor-inhibit (delq 'isearch cursor-sensor-inhibit))))
     979           0 :     (setq isearch--current-buffer (current-buffer))
     980           0 :     (make-local-variable 'cursor-sensor-inhibit)
     981             :     ;; Suspend things like cursor-intangible during Isearch so we can search
     982             :     ;; even within intangible text.
     983           0 :     (push 'isearch cursor-sensor-inhibit))
     984             : 
     985           0 :   (if (and (null unread-command-events)
     986           0 :            (null executing-kbd-macro))
     987           0 :       (progn
     988           0 :         (if (not (input-pending-p))
     989           0 :           (funcall (or isearch-message-function #'isearch-message)))
     990           0 :         (if (and isearch-slow-terminal-mode
     991           0 :                  (not (or isearch-small-window
     992           0 :                           (pos-visible-in-window-group-p))))
     993           0 :             (let ((found-point (point)))
     994           0 :               (setq isearch-small-window t)
     995           0 :               (move-to-window-line 0)
     996           0 :               (let ((window-min-height 1))
     997           0 :                 (split-window nil (if (< search-slow-window-lines 0)
     998           0 :                                       (1+ (- search-slow-window-lines))
     999           0 :                                     (- (window-height)
    1000           0 :                                        (1+ search-slow-window-lines)))))
    1001           0 :               (if (< search-slow-window-lines 0)
    1002           0 :                   (progn (vertical-motion (- 1 search-slow-window-lines))
    1003           0 :                          (set-window-start (next-window) (point))
    1004           0 :                          (set-window-hscroll (next-window)
    1005           0 :                                              (window-hscroll))
    1006           0 :                          (set-window-hscroll (selected-window) 0))
    1007           0 :                 (other-window 1))
    1008           0 :               (goto-char found-point))
    1009             :           ;; Keep same hscrolling as at the start of the search when possible
    1010           0 :           (let ((current-scroll (window-hscroll))
    1011             :                 visible-p)
    1012           0 :             (set-window-hscroll (selected-window) isearch-start-hscroll)
    1013           0 :             (setq visible-p (pos-visible-in-window-group-p nil nil t))
    1014           0 :             (if (or (not visible-p)
    1015             :                     ;; When point is not visible because of hscroll,
    1016             :                     ;; pos-visible-in-window-group-p returns non-nil, but
    1017             :                     ;; the X coordinate it returns is 1 pixel beyond
    1018             :                     ;; the last visible one.
    1019           0 :                     (>= (car visible-p)
    1020           0 :                         (* (window-max-chars-per-line) (frame-char-width))))
    1021           0 :                 (set-window-hscroll (selected-window) current-scroll))))
    1022           0 :         (if isearch-other-end
    1023           0 :             (if (< isearch-other-end (point)) ; isearch-forward?
    1024           0 :                 (isearch-highlight isearch-other-end (point))
    1025           0 :               (isearch-highlight (point) isearch-other-end))
    1026           0 :           (isearch-dehighlight))))
    1027           0 :   (setq ;; quit-flag nil  not for isearch-mode
    1028             :    isearch-adjusted nil
    1029           0 :    isearch-yank-flag nil)
    1030             :   ;; We must prevent the point moving to the end of composition when a
    1031             :   ;; part of the composition has just been searched.
    1032           0 :   (setq disable-point-adjustment t)
    1033           0 :   (run-hooks 'isearch-update-post-hook)
    1034           0 :   (when isearch-lazy-highlight
    1035           0 :     (isearch-lazy-highlight-new-loop)))
    1036             : 
    1037             : (defun isearch-done (&optional nopush edit)
    1038             :   "Exit Isearch mode.
    1039             : For successful search, pass no args.
    1040             : For a failing search, NOPUSH is t.
    1041             : For going to the minibuffer to edit the search string,
    1042             : NOPUSH is t and EDIT is t."
    1043             : 
    1044           0 :   (if isearch-resume-in-command-history
    1045           0 :       (let ((command `(isearch-resume ,isearch-string ,isearch-regexp
    1046           0 :                                       ,isearch-regexp-function ,isearch-forward
    1047           0 :                                       ,isearch-message
    1048           0 :                                       ',isearch-case-fold-search)))
    1049           0 :         (unless (equal (car command-history) command)
    1050           0 :           (setq command-history (cons command command-history)))))
    1051             : 
    1052           0 :   (remove-hook 'pre-command-hook 'isearch-pre-command-hook)
    1053           0 :   (remove-hook 'post-command-hook 'isearch-post-command-hook)
    1054           0 :   (remove-hook 'mouse-leave-buffer-hook 'isearch-done)
    1055           0 :   (remove-hook 'kbd-macro-termination-hook 'isearch-done)
    1056           0 :   (setq isearch-lazy-highlight-start nil)
    1057           0 :   (when (buffer-live-p isearch--current-buffer)
    1058           0 :     (with-current-buffer isearch--current-buffer
    1059           0 :       (setq isearch--current-buffer nil)
    1060           0 :       (setq cursor-sensor-inhibit (delq 'isearch cursor-sensor-inhibit))))
    1061             : 
    1062             :   ;; Called by all commands that terminate isearch-mode.
    1063             :   ;; If NOPUSH is non-nil, we don't push the string on the search ring.
    1064           0 :   (setq overriding-terminal-local-map nil)
    1065             :   ;; (setq pre-command-hook isearch-old-pre-command-hook) ; for lemacs
    1066           0 :   (setq minibuffer-message-timeout isearch-original-minibuffer-message-timeout)
    1067           0 :   (isearch-dehighlight)
    1068           0 :   (lazy-highlight-cleanup lazy-highlight-cleanup)
    1069           0 :   (let ((found-start (window-group-start))
    1070           0 :         (found-point (point)))
    1071           0 :     (when isearch-window-configuration
    1072           0 :       (set-window-configuration isearch-window-configuration)
    1073           0 :       (if isearch-small-window
    1074           0 :           (goto-char found-point)
    1075             :         ;; set-window-configuration clobbers window-start; restore it.
    1076             :         ;; This has an annoying side effect of clearing the last_modiff
    1077             :         ;; field of the window, which can cause unwanted scrolling,
    1078             :         ;; so don't do it unless truly necessary.
    1079           0 :         (set-window-group-start (selected-window) found-start t))))
    1080             : 
    1081           0 :   (setq isearch-mode nil)
    1082           0 :   (if isearch-input-method-local-p
    1083           0 :       (setq input-method-function isearch-input-method-function)
    1084           0 :     (kill-local-variable 'input-method-function))
    1085             : 
    1086           0 :   (force-mode-line-update)
    1087             : 
    1088             :   ;; If we ended in the middle of some intangible text,
    1089             :   ;; move to the further end of that intangible text.
    1090           0 :   (let ((after (if (eobp) nil
    1091           0 :                  (get-text-property (point) 'intangible)))
    1092           0 :         (before (if (bobp) nil
    1093           0 :                   (get-text-property (1- (point)) 'intangible))))
    1094           0 :     (when (and before after (eq before after))
    1095           0 :       (goto-char
    1096           0 :        (if isearch-forward
    1097           0 :            (next-single-property-change (point) 'intangible)
    1098           0 :          (previous-single-property-change (point) 'intangible)))))
    1099             : 
    1100           0 :   (if (and (> (length isearch-string) 0) (not nopush))
    1101             :       ;; Update the ring data.
    1102           0 :       (isearch-update-ring isearch-string isearch-regexp))
    1103             : 
    1104           0 :   (let ((isearch-mode-end-hook-quit (and nopush (not edit))))
    1105           0 :     (run-hooks 'isearch-mode-end-hook))
    1106             : 
    1107             :   ;; If there was movement, mark the starting position.
    1108             :   ;; Maybe should test difference between and set mark only if > threshold.
    1109           0 :   (if (/= (point) isearch-opoint)
    1110           0 :       (or (and transient-mark-mode mark-active)
    1111           0 :           (progn
    1112           0 :             (push-mark isearch-opoint t)
    1113           0 :             (or executing-kbd-macro (> (minibuffer-depth) 0) edit
    1114           0 :                 (message "Mark saved where search started")))))
    1115             : 
    1116           0 :   (and (not edit) isearch-recursive-edit (exit-recursive-edit)))
    1117             : 
    1118             : (defun isearch-update-ring (string &optional regexp)
    1119             :   "Add STRING to the beginning of the search ring.
    1120             : REGEXP if non-nil says use the regexp search ring."
    1121           0 :   (add-to-history
    1122           0 :    (if regexp 'regexp-search-ring 'search-ring)
    1123           0 :    string
    1124           0 :    (if regexp regexp-search-ring-max search-ring-max)))
    1125             : 
    1126             : ;; Switching buffers should first terminate isearch-mode.
    1127             : ;; ;; For Emacs 19, the frame switch event is handled.
    1128             : ;; (defun isearch-switch-frame-handler ()
    1129             : ;;   (interactive) ;; Is this necessary?
    1130             : ;;   ;; First terminate isearch-mode.
    1131             : ;;   (isearch-done)
    1132             : ;;   (isearch-clean-overlays)
    1133             : ;;   (handle-switch-frame (car (cdr last-command-event))))
    1134             : 
    1135             : 
    1136             : ;; The search status structure and stack.
    1137             : 
    1138             : (cl-defstruct (isearch--state
    1139             :                (:constructor nil)
    1140             :                (:copier nil)
    1141             :                (:constructor isearch--get-state
    1142             :                 (&aux
    1143           0 :                  (string isearch-string)
    1144           0 :                  (message isearch-message)
    1145           0 :                  (point (point))
    1146           0 :                  (success isearch-success)
    1147           0 :                  (forward isearch-forward)
    1148           0 :                  (other-end isearch-other-end)
    1149           0 :                  (word isearch-regexp-function)
    1150           0 :                  (error isearch-error)
    1151           0 :                  (wrapped isearch-wrapped)
    1152           0 :                  (barrier isearch-barrier)
    1153           0 :                  (case-fold-search isearch-case-fold-search)
    1154           0 :                  (pop-fun (if isearch-push-state-function
    1155           0 :                               (funcall isearch-push-state-function))))))
    1156             :   (string nil :read-only t)
    1157             :   (message nil :read-only t)
    1158             :   (point nil :read-only t)
    1159             :   (success nil :read-only t)
    1160             :   (forward nil :read-only t)
    1161             :   (other-end nil :read-only t)
    1162             :   (word nil :read-only t)
    1163             :   (error nil :read-only t)
    1164             :   (wrapped nil :read-only t)
    1165             :   (barrier nil :read-only t)
    1166             :   (case-fold-search nil :read-only t)
    1167             :   (pop-fun nil :read-only t))
    1168             : 
    1169             : (defun isearch--set-state (cmd)
    1170           0 :   (setq isearch-string (isearch--state-string cmd)
    1171           0 :         isearch-message (isearch--state-message cmd)
    1172           0 :         isearch-success (isearch--state-success cmd)
    1173           0 :         isearch-forward (isearch--state-forward cmd)
    1174           0 :         isearch-other-end (isearch--state-other-end cmd)
    1175           0 :         isearch-regexp-function (isearch--state-word cmd)
    1176           0 :         isearch-error (isearch--state-error cmd)
    1177           0 :         isearch-wrapped (isearch--state-wrapped cmd)
    1178           0 :         isearch-barrier (isearch--state-barrier cmd)
    1179           0 :         isearch-case-fold-search (isearch--state-case-fold-search cmd))
    1180           0 :   (if (functionp (isearch--state-pop-fun cmd))
    1181           0 :       (funcall (isearch--state-pop-fun cmd) cmd))
    1182           0 :   (goto-char (isearch--state-point cmd)))
    1183             : 
    1184             : (defun isearch-pop-state ()
    1185           0 :   (setq isearch-cmds (cdr isearch-cmds))
    1186           0 :   (isearch--set-state (car isearch-cmds)))
    1187             : 
    1188             : (defun isearch-push-state ()
    1189           0 :   (push (isearch--get-state) isearch-cmds))
    1190             : 
    1191             : 
    1192             : ;; Commands active while inside of the isearch minor mode.
    1193             : 
    1194             : (defun isearch-exit ()
    1195             :   "Exit search normally.
    1196             : However, if this is the first command after starting incremental
    1197             : search and `search-nonincremental-instead' is non-nil, do a
    1198             : nonincremental search instead via `isearch-edit-string'."
    1199             :   (interactive)
    1200           0 :   (if (and search-nonincremental-instead
    1201           0 :            (= 0 (length isearch-string)))
    1202           0 :       (let ((isearch-nonincremental t))
    1203           0 :         (isearch-edit-string)) ;; this calls isearch-done as well
    1204           0 :     (isearch-done))
    1205           0 :   (isearch-clean-overlays))
    1206             : 
    1207             : (defun isearch-fail-pos (&optional msg)
    1208             :   "Return position of first mismatch in search string, or nil if none.
    1209             : If MSG is non-nil, use variable `isearch-message', otherwise `isearch-string'."
    1210           0 :   (let ((cmds isearch-cmds)
    1211           0 :         (curr-msg (if msg isearch-message isearch-string))
    1212             :         succ-msg)
    1213           0 :     (when (or (not isearch-success) isearch-error)
    1214           0 :       (while (and cmds
    1215           0 :                   (or (not (isearch--state-success (car cmds)))
    1216           0 :                       (isearch--state-error (car cmds))))
    1217           0 :         (pop cmds))
    1218           0 :       (setq succ-msg (and cmds (if msg (isearch--state-message (car cmds))
    1219           0 :                                  (isearch--state-string (car cmds)))))
    1220           0 :       (if (and (stringp succ-msg)
    1221           0 :                (< (length succ-msg) (length curr-msg))
    1222           0 :                (equal succ-msg
    1223           0 :                       (substring curr-msg 0 (length succ-msg))))
    1224           0 :           (length succ-msg)
    1225           0 :         0))))
    1226             : 
    1227             : (defvar isearch-new-regexp-function nil
    1228             :   "Holds the next `isearch-regexp-function' inside `with-isearch-suspended'.
    1229             : If this is set inside code wrapped by the macro
    1230             : `with-isearch-suspended', then the value set will be used as the
    1231             : `isearch-regexp-function' once isearch resumes.")
    1232             : (define-obsolete-variable-alias 'isearch-new-word
    1233             :   'isearch-new-regexp-function "25.1")
    1234             : 
    1235             : (defmacro with-isearch-suspended (&rest body)
    1236             :   "Exit Isearch mode, run BODY, and reinvoke the pending search.
    1237             : You can update the global isearch variables by setting new values to
    1238             : `isearch-new-string', `isearch-new-message', `isearch-new-forward',
    1239             : `isearch-new-regexp-function', `isearch-new-case-fold', `isearch-new-nonincremental'."
    1240             :   ;; This code is very hairy for several reasons, explained in the code.
    1241             :   ;; Mainly, isearch-mode must be terminated while editing and then restarted.
    1242             :   ;; If there were a way to catch any change of buffer from the minibuffer,
    1243             :   ;; this could be simplified greatly.
    1244             :   ;; Editing doesn't back up the search point.  Should it?
    1245           3 :   `(condition-case nil
    1246             :       (progn
    1247             :         (let ((isearch-new-nonincremental isearch-nonincremental)
    1248             : 
    1249             :               ;; Locally bind all isearch global variables to protect them
    1250             :               ;; from recursive isearching.
    1251             :               ;; isearch-string -message and -forward are not bound
    1252             :               ;; so they may be changed.  Instead, save the values.
    1253             :               (isearch-new-string isearch-string)
    1254             :               (isearch-new-message isearch-message)
    1255             :               (isearch-new-forward isearch-forward)
    1256             :               (isearch-new-regexp-function isearch-regexp-function)
    1257             :               (isearch-new-case-fold isearch-case-fold-search)
    1258             : 
    1259             :               (isearch-regexp isearch-regexp)
    1260             :               (isearch-op-fun isearch-op-fun)
    1261             :               (isearch-cmds isearch-cmds)
    1262             :               (isearch-success isearch-success)
    1263             :               (isearch-wrapped isearch-wrapped)
    1264             :               (isearch-barrier isearch-barrier)
    1265             :               (isearch-adjusted isearch-adjusted)
    1266             :               (isearch-yank-flag isearch-yank-flag)
    1267             :               (isearch-error isearch-error)
    1268             : 
    1269             :               (multi-isearch-file-list-new multi-isearch-file-list)
    1270             :               (multi-isearch-buffer-list-new multi-isearch-buffer-list)
    1271             :               (multi-isearch-next-buffer-function multi-isearch-next-buffer-current-function)
    1272             :               (multi-isearch-current-buffer-new multi-isearch-current-buffer)
    1273             :   ;;; Don't bind this.  We want isearch-search, below, to set it.
    1274             :   ;;; And the old value won't matter after that.
    1275             :   ;;;       (isearch-other-end isearch-other-end)
    1276             :   ;;; Perhaps some of these other variables should be bound for a
    1277             :   ;;; shorter period, ending before the next isearch-search.
    1278             :   ;;; But there doesn't seem to be a real bug, so let's not risk it now.
    1279             :               (isearch-opoint isearch-opoint)
    1280             :               (isearch-slow-terminal-mode isearch-slow-terminal-mode)
    1281             :               (isearch-small-window isearch-small-window)
    1282             :               (isearch-recursive-edit isearch-recursive-edit)
    1283             :               ;; Save current configuration so we can restore it here.
    1284             :               (isearch-window-configuration (current-window-configuration))
    1285             : 
    1286             :               ;; This could protect the index of the search rings,
    1287             :               ;; but we can't reliably count the number of typed M-p
    1288             :               ;; in `read-from-minibuffer' to adjust the index accordingly.
    1289             :               ;; So when the following is commented out, `isearch-mode'
    1290             :               ;; below resets the index to the predictable value nil.
    1291             :               ;; (search-ring-yank-pointer search-ring-yank-pointer)
    1292             :               ;; (regexp-search-ring-yank-pointer regexp-search-ring-yank-pointer)
    1293             : 
    1294             :               ;; Temporarily restore `minibuffer-message-timeout'.
    1295             :               (minibuffer-message-timeout
    1296             :                isearch-original-minibuffer-message-timeout)
    1297             :               (isearch-original-minibuffer-message-timeout
    1298             :                isearch-original-minibuffer-message-timeout)
    1299             :               old-point old-other-end)
    1300             : 
    1301             :           ;; Actually terminate isearching until editing is done.
    1302             :           ;; This is so that the user can do anything without failure,
    1303             :           ;; like switch buffers and start another isearch, and return.
    1304             :           (condition-case nil
    1305             :               (isearch-done t t)
    1306             :             (exit nil))                 ; was recursive editing
    1307             : 
    1308             :           ;; Save old point and isearch-other-end before reading from minibuffer
    1309             :           ;; that can change their values.
    1310             :           (setq old-point (point) old-other-end isearch-other-end)
    1311             : 
    1312             :           (unwind-protect
    1313           3 :               (progn ,@body)
    1314             : 
    1315             :             ;; Always resume isearching by restarting it.
    1316             :             (isearch-mode isearch-forward
    1317             :                           isearch-regexp
    1318             :                           isearch-op-fun
    1319             :                           nil
    1320             :                           isearch-regexp-function)
    1321             : 
    1322             :             ;; Copy new local values to isearch globals
    1323             :             (setq isearch-string isearch-new-string
    1324             :                   isearch-message isearch-new-message
    1325             :                   isearch-forward isearch-new-forward
    1326             :                   isearch-nonincremental isearch-new-nonincremental
    1327             :                   isearch-regexp-function isearch-new-regexp-function
    1328             :                   isearch-case-fold-search isearch-new-case-fold
    1329             :                   multi-isearch-current-buffer multi-isearch-current-buffer-new
    1330             :                   multi-isearch-file-list multi-isearch-file-list-new
    1331             :                   multi-isearch-buffer-list multi-isearch-buffer-list-new)
    1332             : 
    1333             :             ;; Restore the minibuffer message before moving point.
    1334             :             (funcall (or isearch-message-function #'isearch-message) nil t)
    1335             : 
    1336             :             ;; Set point at the start (end) of old match if forward (backward),
    1337             :             ;; so after exiting minibuffer isearch resumes at the start (end)
    1338             :             ;; of this match and can find it again.
    1339             :             (if (and old-other-end (eq old-point (point))
    1340             :                      (eq isearch-forward isearch-new-forward))
    1341             :                 (goto-char old-other-end)))
    1342             : 
    1343             :           ;; Empty isearch-string means use default.
    1344             :           (when (= 0 (length isearch-string))
    1345             :             (setq isearch-string (or (car (if isearch-regexp
    1346             :                                               regexp-search-ring
    1347             :                                             search-ring))
    1348             :                                      "")
    1349             : 
    1350             :                   isearch-message
    1351             :                   (mapconcat 'isearch-text-char-description
    1352             :                              isearch-string ""))
    1353             :             ;; After taking the last element, adjust ring to previous one.
    1354             :             (isearch-ring-adjust1 nil)))
    1355             : 
    1356             :         ;; This used to push the state as of before this C-s, but it adds
    1357             :         ;; an inconsistent state where part of variables are from the
    1358             :         ;; previous search (e.g. `isearch-success'), and part of variables
    1359             :         ;; are just entered from the minibuffer (e.g. `isearch-string').
    1360             :         ;; (isearch-push-state)
    1361             : 
    1362             :         ;; Reinvoke the pending search.
    1363             :         (isearch-search)
    1364             :         (isearch-push-state)            ; this pushes the correct state
    1365             :         (isearch-update)
    1366             :         (if isearch-nonincremental
    1367             :             (progn
    1368             :               ;; (sit-for 1) ;; needed if isearch-done does: (message "")
    1369             :               (isearch-done)
    1370             :               ;; The search done message is confusing when the string
    1371             :               ;; is empty, so erase it.
    1372             :               (if (equal isearch-string "")
    1373             :                   (message "")))))
    1374             : 
    1375             :     (quit  ; handle abort-recursive-edit
    1376             :      (isearch-abort)  ;; outside of let to restore outside global values
    1377           3 :      )))
    1378             : 
    1379             : (defvar minibuffer-history-symbol) ;; from external package gmhist.el
    1380             : 
    1381             : (defun isearch-edit-string ()
    1382             :   "Edit the search string in the minibuffer.
    1383             : The following additional command keys are active while editing.
    1384             : \\<minibuffer-local-isearch-map>
    1385             : \\[exit-minibuffer] to resume incremental searching with the edited string.
    1386             : \\[isearch-forward-exit-minibuffer] to resume isearching forward.
    1387             : \\[isearch-reverse-exit-minibuffer] to resume isearching backward.
    1388             : \\[isearch-complete-edit] to complete the search string using the search ring."
    1389             :   (interactive)
    1390           0 :   (with-isearch-suspended
    1391             :    (let* ((message-log-max nil)
    1392             :           ;; Don't add a new search string to the search ring here
    1393             :           ;; in `read-from-minibuffer'. It should be added only
    1394             :           ;; by `isearch-update-ring' called from `isearch-done'.
    1395             :           (history-add-new-input nil)
    1396             :           ;; Binding minibuffer-history-symbol to nil is a work-around
    1397             :           ;; for some incompatibility with gmhist.
    1398             :           (minibuffer-history-symbol))
    1399             :      (setq isearch-new-string
    1400             :            (read-from-minibuffer
    1401             :             (isearch-message-prefix nil isearch-nonincremental)
    1402             :             (cons isearch-string (1+ (or (isearch-fail-pos)
    1403             :                                          (length isearch-string))))
    1404             :             minibuffer-local-isearch-map nil
    1405             :             (if isearch-regexp
    1406             :                 (cons 'regexp-search-ring
    1407             :                       (1+ (or regexp-search-ring-yank-pointer -1)))
    1408             :               (cons 'search-ring
    1409             :                     (1+ (or search-ring-yank-pointer -1))))
    1410             :             nil t)
    1411             :            isearch-new-message
    1412             :            (mapconcat 'isearch-text-char-description
    1413           0 :                       isearch-new-string "")))))
    1414             : 
    1415             : (defun isearch-nonincremental-exit-minibuffer ()
    1416             :   (interactive)
    1417           0 :   (setq isearch-new-nonincremental t)
    1418           0 :   (exit-minibuffer))
    1419             : ;; It makes no sense to change the value of `isearch-new-nonincremental'
    1420             : ;; from nil to t during `isearch-edit-string'.   Thus marked as obsolete.
    1421             : (make-obsolete 'isearch-nonincremental-exit-minibuffer 'exit-minibuffer "24.4")
    1422             : 
    1423             : (defun isearch-forward-exit-minibuffer ()
    1424             :   "Resume isearching forward from the minibuffer that edits the search string."
    1425             :   (interactive)
    1426           0 :   (setq isearch-new-forward t isearch-new-nonincremental nil)
    1427           0 :   (exit-minibuffer))
    1428             : 
    1429             : (defun isearch-reverse-exit-minibuffer ()
    1430             :   "Resume isearching backward from the minibuffer that edits the search string."
    1431             :   (interactive)
    1432           0 :   (setq isearch-new-forward nil isearch-new-nonincremental nil)
    1433           0 :   (exit-minibuffer))
    1434             : 
    1435             : (defun isearch-cancel ()
    1436             :   "Terminate the search and go back to the starting point."
    1437             :   (interactive)
    1438           0 :   (if (and isearch-push-state-function isearch-cmds)
    1439             :       ;; For defined push-state function, restore the first state.
    1440             :       ;; This calls pop-state function and restores original point.
    1441           0 :       (let ((isearch-cmds (last isearch-cmds)))
    1442           0 :         (isearch--set-state (car isearch-cmds)))
    1443           0 :     (goto-char isearch-opoint))
    1444           0 :   (isearch-done t)                      ; Exit isearch..
    1445           0 :   (isearch-clean-overlays)
    1446           0 :   (signal 'quit nil))                   ; ..and pass on quit signal.
    1447             : 
    1448             : (defun isearch-abort ()
    1449             :   "Abort incremental search mode if searching is successful, signaling quit.
    1450             : Otherwise, revert to previous successful search and continue searching.
    1451             : Use `isearch-exit' to quit without signaling."
    1452             :   (interactive)
    1453             :   ;; (ding)  signal instead below, if quitting
    1454           0 :   (discard-input)
    1455           0 :   (if (and isearch-success (not isearch-error))
    1456             :       ;; If search is successful and has no incomplete regexp,
    1457             :       ;; move back to starting point and really do quit.
    1458           0 :       (progn
    1459           0 :         (setq isearch-success nil)
    1460           0 :         (isearch-cancel))
    1461             :     ;; If search is failing, or has an incomplete regexp,
    1462             :     ;; rub out until it is once more successful.
    1463           0 :     (while (or (not isearch-success) isearch-error)
    1464           0 :       (isearch-pop-state))
    1465           0 :     (isearch-update)))
    1466             : 
    1467             : (defun isearch-repeat (direction)
    1468             :   ;; Utility for isearch-repeat-forward and -backward.
    1469           0 :   (if (eq isearch-forward (eq direction 'forward))
    1470             :       ;; C-s in forward or C-r in reverse.
    1471           0 :       (if (equal isearch-string "")
    1472             :           ;; If search string is empty, use last one.
    1473           0 :           (if (null (if isearch-regexp regexp-search-ring search-ring))
    1474           0 :               (setq isearch-error "No previous search string")
    1475           0 :             (setq isearch-string
    1476           0 :                   (car (if isearch-regexp regexp-search-ring search-ring))
    1477             :                   isearch-message
    1478           0 :                   (mapconcat 'isearch-text-char-description
    1479           0 :                              isearch-string "")
    1480           0 :                   isearch-case-fold-search isearch-last-case-fold-search)
    1481             :             ;; After taking the last element, adjust ring to previous one.
    1482           0 :             (isearch-ring-adjust1 nil))
    1483             :         ;; If already have what to search for, repeat it.
    1484           0 :         (or isearch-success
    1485           0 :             (progn
    1486             :               ;; Set isearch-wrapped before calling isearch-wrap-function
    1487           0 :               (setq isearch-wrapped t)
    1488           0 :               (if isearch-wrap-function
    1489           0 :                   (funcall isearch-wrap-function)
    1490           0 :                 (goto-char (if isearch-forward (point-min) (point-max)))))))
    1491             :     ;; C-s in reverse or C-r in forward, change direction.
    1492           0 :     (setq isearch-forward (not isearch-forward)
    1493           0 :           isearch-success t))
    1494             : 
    1495           0 :   (setq isearch-barrier (point)) ; For subsequent \| if regexp.
    1496             : 
    1497           0 :   (if (equal isearch-string "")
    1498           0 :       (setq isearch-success t)
    1499           0 :     (if (and isearch-success
    1500           0 :              (equal (point) isearch-other-end)
    1501           0 :              (not isearch-just-started))
    1502             :         ;; If repeating a search that found
    1503             :         ;; an empty string, ensure we advance.
    1504           0 :         (if (if isearch-forward (eobp) (bobp))
    1505             :             ;; If there's nowhere to advance to, fail (and wrap next time).
    1506           0 :             (progn
    1507           0 :               (setq isearch-success nil)
    1508           0 :               (ding))
    1509           0 :           (forward-char (if isearch-forward 1 -1))
    1510           0 :           (isearch-search))
    1511           0 :       (isearch-search)))
    1512             : 
    1513           0 :   (isearch-push-state)
    1514           0 :   (isearch-update))
    1515             : 
    1516             : (defun isearch-repeat-forward ()
    1517             :   "Repeat incremental search forwards."
    1518             :   (interactive)
    1519           0 :   (isearch-repeat 'forward))
    1520             : 
    1521             : (defun isearch-repeat-backward ()
    1522             :   "Repeat incremental search backwards."
    1523             :   (interactive)
    1524           0 :   (isearch-repeat 'backward))
    1525             : 
    1526             : 
    1527             : ;;; Toggles for `isearch-regexp-function' and `search-default-mode'.
    1528             : (defmacro isearch-define-mode-toggle (mode key function &optional docstring &rest body)
    1529             :   "Define a command called `isearch-toggle-MODE' and bind it to `M-s KEY'.
    1530             : The first line of the command's docstring is auto-generated, the
    1531             : remainder may be provided in DOCSTRING.
    1532             : If FUNCTION is a symbol, this command first toggles the value of
    1533             : `isearch-regexp-function' between nil and FUNCTION.  Also set the
    1534             : `isearch-message-prefix' property of FUNCTION.
    1535             : The command then executes BODY and updates the isearch prompt."
    1536             :   (declare (indent defun))
    1537           7 :   (let ((command-name (intern (format "isearch-toggle-%s" mode)))
    1538           7 :         (key (concat "\M-s" key)))
    1539           7 :     `(progn
    1540           7 :        (defun ,command-name ()
    1541           7 :          ,(format "Toggle %s searching on or off.%s" mode
    1542           7 :                   (if docstring (concat "\n" docstring) ""))
    1543             :          (interactive)
    1544           7 :          ,@(when function
    1545           3 :              `((setq isearch-regexp-function
    1546           3 :                      (unless (eq isearch-regexp-function #',function)
    1547           3 :                        #',function))
    1548           7 :                (setq isearch-regexp nil)))
    1549           7 :          ,@body
    1550             :          (setq isearch-success t isearch-adjusted t)
    1551             :          (isearch-update))
    1552           7 :        (define-key isearch-mode-map ,key #',command-name)
    1553           7 :        ,@(when (and function (symbolp function))
    1554           3 :            `((put ',function 'isearch-message-prefix ,(format "%s " mode))
    1555           3 :              (put ',function :advertised-binding ,key)
    1556             :              (cl-callf (lambda (types) (cons 'choice
    1557           3 :                                         (cons '(const :tag ,(capitalize (format "%s search" mode)) ,function)
    1558             :                                               (cdr types))))
    1559           7 :                  (get 'search-default-mode 'custom-type)))))))
    1560             : 
    1561             : (isearch-define-mode-toggle word "w" word-search-regexp "\
    1562             : Turning on word search turns off regexp mode.")
    1563             : (isearch-define-mode-toggle symbol "_" isearch-symbol-regexp "\
    1564             : Turning on symbol search turns off regexp mode.")
    1565             : (isearch-define-mode-toggle char-fold "'" char-fold-to-regexp "\
    1566             : Turning on character-folding turns off regexp mode.")
    1567             : (put 'char-fold-to-regexp 'isearch-message-prefix "char-fold ")
    1568             : 
    1569             : (isearch-define-mode-toggle regexp "r" nil nil
    1570             :   (setq isearch-regexp (not isearch-regexp))
    1571             :   (if isearch-regexp (setq isearch-regexp-function nil)))
    1572             : 
    1573             : (defun isearch--momentary-message (string)
    1574             :   "Print STRING at the end of the isearch prompt for 1 second"
    1575           0 :   (let ((message-log-max nil))
    1576           0 :     (message "%s%s [%s]"
    1577           0 :              (isearch-message-prefix nil isearch-nonincremental)
    1578           0 :              isearch-message
    1579           0 :              string))
    1580           0 :   (sit-for 1))
    1581             : 
    1582             : (isearch-define-mode-toggle lax-whitespace " " nil
    1583             :   "In ordinary search, toggles the value of the variable
    1584             : `isearch-lax-whitespace'.  In regexp search, toggles the
    1585             : value of the variable `isearch-regexp-lax-whitespace'."
    1586             :   (isearch--momentary-message
    1587             :    (if (if isearch-regexp
    1588             :            (setq isearch-regexp-lax-whitespace (not isearch-regexp-lax-whitespace))
    1589             :          (setq isearch-lax-whitespace (not isearch-lax-whitespace)))
    1590             :        "match spaces loosely"
    1591             :      "match spaces literally")))
    1592             : 
    1593             : (isearch-define-mode-toggle case-fold "c" nil
    1594             :   "Toggles the value of the variable `isearch-case-fold-search'."
    1595             :   (isearch--momentary-message
    1596             :    (if (setq isearch-case-fold-search
    1597             :              (if isearch-case-fold-search nil 'yes))
    1598             :        "case insensitive"
    1599             :      "case sensitive")))
    1600             : 
    1601             : (isearch-define-mode-toggle invisible "i" nil
    1602             :   "This determines whether to search inside invisible text or not.
    1603             : Toggles the variable `isearch-invisible' between values
    1604             : nil and a non-nil value of the option `search-invisible'
    1605             : \(or `open' if `search-invisible' is nil)."
    1606             :   "match %svisible text"
    1607             :   (isearch--momentary-message
    1608             :    (if (setq isearch-invisible
    1609             :              (if isearch-invisible
    1610             :                  nil (or search-invisible 'open)))
    1611             :        "match invisible text"
    1612             :      "match visible text")))
    1613             : 
    1614             : 
    1615             : ;; Word search
    1616             : 
    1617             : (defun word-search-regexp (string &optional lax)
    1618             :   "Return a regexp which matches words, ignoring punctuation.
    1619             : Given STRING, a string of words separated by word delimiters,
    1620             : compute a regexp that matches those exact words separated by
    1621             : arbitrary punctuation.  If the string begins or ends in whitespace,
    1622             : the beginning or the end of the string matches arbitrary whitespace.
    1623             : Otherwise if LAX is non-nil, the beginning or the end of the string
    1624             : need not match a word boundary.
    1625             : 
    1626             : Used in `word-search-forward', `word-search-backward',
    1627             : `word-search-forward-lax', `word-search-backward-lax'."
    1628           0 :   (cond
    1629           0 :    ((equal string "") "")
    1630           0 :    ((string-match-p "\\`\\W+\\'" string) "\\W+")
    1631           0 :    (t (concat
    1632           0 :        (if (string-match-p "\\`\\W" string) "\\W+"
    1633           0 :          "\\<")
    1634           0 :        (mapconcat 'regexp-quote (split-string string "\\W+" t) "\\W+")
    1635           0 :        (if (string-match-p "\\W\\'" string) "\\W+"
    1636           0 :          (unless lax "\\>"))))))
    1637             : 
    1638             : (defun word-search-backward (string &optional bound noerror count)
    1639             :   "Search backward from point for STRING, ignoring differences in punctuation.
    1640             : Set point to the beginning of the occurrence found, and return point.
    1641             : An optional second argument bounds the search; it is a buffer position.
    1642             :   The match found must not begin before that position.  A value of nil
    1643             :   means search to the beginning of the accessible portion of the buffer.
    1644             : Optional third argument, if t, means if fail just return nil (no error).
    1645             :   If not nil and not t, position at limit of search and return nil.
    1646             : Optional fourth argument COUNT, if a positive number, means to search
    1647             :   for COUNT successive occurrences.  If COUNT is negative, search
    1648             :   forward, instead of backward, for -COUNT occurrences.  A value of
    1649             :   nil means the same as 1.
    1650             : With COUNT positive, the match found is the COUNTth to last one (or
    1651             :   last, if COUNT is 1 or nil) in the buffer located entirely before
    1652             :   the origin of the search; correspondingly with COUNT negative.
    1653             : 
    1654             : Relies on the function `word-search-regexp' to convert a sequence
    1655             : of words in STRING to a regexp used to search words without regard
    1656             : to punctuation.
    1657             : This command does not support character folding, and lax space matching
    1658             : has no effect on it."
    1659             :   (interactive "sWord search backward: ")
    1660           0 :   (re-search-backward (word-search-regexp string nil) bound noerror count))
    1661             : 
    1662             : (defun word-search-forward (string &optional bound noerror count)
    1663             :   "Search forward from point for STRING, ignoring differences in punctuation.
    1664             : Set point to the end of the occurrence found, and return point.
    1665             : An optional second argument bounds the search; it is a buffer position.
    1666             :   The match found must not end after that position.  A value of nil
    1667             :   means search to the end of the accessible portion of the buffer.
    1668             : Optional third argument, if t, means if fail just return nil (no error).
    1669             :   If not nil and not t, move to limit of search and return nil.
    1670             : Optional fourth argument COUNT, if a positive number, means to search
    1671             :   for COUNT successive occurrences.  If COUNT is negative, search
    1672             :   backward, instead of forward, for -COUNT occurrences.  A value of
    1673             :   nil means the same as 1.
    1674             : With COUNT positive, the match found is the COUNTth one (or first,
    1675             :   if COUNT is 1 or nil) in the buffer located entirely after the
    1676             :   origin of the search; correspondingly with COUNT negative.
    1677             : 
    1678             : Relies on the function `word-search-regexp' to convert a sequence
    1679             : of words in STRING to a regexp used to search words without regard
    1680             : to punctuation.
    1681             : This command does not support character folding, and lax space matching
    1682             : has no effect on it."
    1683             :   (interactive "sWord search: ")
    1684           0 :   (re-search-forward (word-search-regexp string nil) bound noerror count))
    1685             : 
    1686             : (defun word-search-backward-lax (string &optional bound noerror count)
    1687             :   "Search backward from point for STRING, ignoring differences in punctuation.
    1688             : Set point to the beginning of the occurrence found, and return point.
    1689             : 
    1690             : Unlike `word-search-backward', the end of STRING need not match a word
    1691             : boundary, unless STRING ends in whitespace.
    1692             : 
    1693             : An optional second argument bounds the search; it is a buffer position.
    1694             :   The match found must not begin before that position.  A value of nil
    1695             :   means search to the beginning of the accessible portion of the buffer.
    1696             : Optional third argument, if t, means if fail just return nil (no error).
    1697             :   If not nil and not t, position at limit of search and return nil.
    1698             : Optional fourth argument COUNT, if a positive number, means to search
    1699             :   for COUNT successive occurrences.  If COUNT is negative, search
    1700             :   forward, instead of backward, for -COUNT occurrences.  A value of
    1701             :   nil means the same as 1.
    1702             : With COUNT positive, the match found is the COUNTth to last one (or
    1703             :   last, if COUNT is 1 or nil) in the buffer located entirely before
    1704             :   the origin of the search; correspondingly with COUNT negative.
    1705             : 
    1706             : Relies on the function `word-search-regexp' to convert a sequence
    1707             : of words in STRING to a regexp used to search words without regard
    1708             : to punctuation.
    1709             : This command does not support character folding, and lax space matching
    1710             : has no effect on it."
    1711             :   (interactive "sWord search backward: ")
    1712           0 :   (re-search-backward (word-search-regexp string t) bound noerror count))
    1713             : 
    1714             : (defun word-search-forward-lax (string &optional bound noerror count)
    1715             :   "Search forward from point for STRING, ignoring differences in punctuation.
    1716             : Set point to the end of the occurrence found, and return point.
    1717             : 
    1718             : Unlike `word-search-forward', the end of STRING need not match a word
    1719             : boundary, unless STRING ends in whitespace.
    1720             : 
    1721             : An optional second argument bounds the search; it is a buffer position.
    1722             :   The match found must not end after that position.  A value of nil
    1723             :   means search to the end of the accessible portion of the buffer.
    1724             : Optional third argument, if t, means if fail just return nil (no error).
    1725             :   If not nil and not t, move to limit of search and return nil.
    1726             : Optional fourth argument COUNT, if a positive number, means to search
    1727             :   for COUNT successive occurrences.  If COUNT is negative, search
    1728             :   backward, instead of forward, for -COUNT occurrences.  A value of
    1729             :   nil means the same as 1.
    1730             : With COUNT positive, the match found is the COUNTth one (or first,
    1731             :   if COUNT is 1 or nil) in the buffer located entirely after the
    1732             :   origin of the search; correspondingly with COUNT negative.
    1733             : 
    1734             : Relies on the function `word-search-regexp' to convert a sequence
    1735             : of words in STRING to a regexp used to search words without regard
    1736             : to punctuation.
    1737             : This command does not support character folding, and lax space matching
    1738             : has no effect on it."
    1739             :   (interactive "sWord search: ")
    1740           0 :   (re-search-forward (word-search-regexp string t) bound noerror count))
    1741             : 
    1742             : ;; Symbol search
    1743             : 
    1744             : (defun isearch-symbol-regexp (string &optional lax)
    1745             :   "Return a regexp which matches STRING as a symbol.
    1746             : Creates a regexp where STRING is surrounded by symbol delimiters \\_< and \\_>.
    1747             : If there are more than one symbol, then compute a regexp that matches
    1748             : those exact symbols separated by non-symbol characters.  If the string
    1749             : begins or ends in whitespace, the beginning or the end of the string
    1750             : matches arbitrary non-symbol whitespace.  Otherwise if LAX is non-nil,
    1751             : the beginning or the end of the string need not match a symbol boundary."
    1752           0 :   (let ((not-word-symbol-re
    1753             :          ;; This regexp matches all syntaxes except word and symbol syntax.
    1754             :          ;; FIXME: Replace it with something shorter if possible (bug#14602).
    1755             :          "\\(?:\\s-\\|\\s.\\|\\s(\\|\\s)\\|\\s\"\\|\\s\\\\|\\s/\\|\\s$\\|\\s'\\|\\s<\\|\\s>\\|\\s@\\|\\s!\\|\\s|\\)+"))
    1756           0 :     (cond
    1757           0 :      ((equal string "") "")
    1758           0 :      ((string-match-p (format "\\`%s\\'" not-word-symbol-re) string) not-word-symbol-re)
    1759           0 :      (t (concat
    1760           0 :          (if (string-match-p (format "\\`%s" not-word-symbol-re) string) not-word-symbol-re
    1761           0 :            "\\_<")
    1762           0 :          (mapconcat 'regexp-quote (split-string string not-word-symbol-re t) not-word-symbol-re)
    1763           0 :          (if (string-match-p (format "%s\\'" not-word-symbol-re) string) not-word-symbol-re
    1764           0 :            (unless lax "\\_>")))))))
    1765             : 
    1766             : (put 'isearch-symbol-regexp 'isearch-message-prefix "symbol ")
    1767             : 
    1768             : ;; Search with lax whitespace
    1769             : 
    1770             : (defun search-forward-lax-whitespace (string &optional bound noerror count)
    1771             :   "Search forward for STRING, matching a sequence of whitespace chars."
    1772           0 :   (let ((search-spaces-regexp search-whitespace-regexp))
    1773           0 :     (re-search-forward (regexp-quote string) bound noerror count)))
    1774             : 
    1775             : (defun search-backward-lax-whitespace (string &optional bound noerror count)
    1776             :   "Search backward for STRING, matching a sequence of whitespace chars."
    1777           0 :   (let ((search-spaces-regexp search-whitespace-regexp))
    1778           0 :     (re-search-backward (regexp-quote string) bound noerror count)))
    1779             : 
    1780             : (defun re-search-forward-lax-whitespace (regexp &optional bound noerror count)
    1781             :   "Search forward for REGEXP, matching a sequence of whitespace chars."
    1782           0 :   (let ((search-spaces-regexp search-whitespace-regexp))
    1783           0 :     (re-search-forward regexp bound noerror count)))
    1784             : 
    1785             : (defun re-search-backward-lax-whitespace (regexp &optional bound noerror count)
    1786             :   "Search backward for REGEXP, matching a sequence of whitespace chars."
    1787           0 :   (let ((search-spaces-regexp search-whitespace-regexp))
    1788           0 :     (re-search-backward regexp bound noerror count)))
    1789             : 
    1790             : (dolist (old '(re-search-forward-lax-whitespace search-backward-lax-whitespace
    1791             :                search-forward-lax-whitespace re-search-backward-lax-whitespace))
    1792             :   (make-obsolete old
    1793             :                  "instead, use (let ((search-spaces-regexp search-whitespace-regexp))
    1794             :                (re-search-... ...))"
    1795             :                  "25.1"))
    1796             : 
    1797             : 
    1798             : (defun isearch-query-replace (&optional arg regexp-flag)
    1799             :   "Start `query-replace' with string to replace from last search string.
    1800             : The ARG (prefix arg if interactive), if non-nil, means replace
    1801             : only matches surrounded by word boundaries.  A negative prefix
    1802             : arg means replace backward.  Note that using the prefix arg
    1803             : is possible only when `isearch-allow-scroll' is non-nil or
    1804             : `isearch-allow-prefix' is non-nil, and it doesn't always provide the
    1805             : correct matches for `query-replace', so the preferred way to run word
    1806             : replacements from Isearch is `M-s w ... M-%'."
    1807             :   (interactive
    1808           0 :    (list current-prefix-arg))
    1809           0 :   (barf-if-buffer-read-only)
    1810           0 :   (if regexp-flag (setq isearch-regexp t))
    1811           0 :   (let ((case-fold-search isearch-case-fold-search)
    1812             :         ;; set `search-upper-case' to nil to not call
    1813             :         ;; `isearch-no-upper-case-p' in `perform-replace'
    1814             :         (search-upper-case nil)
    1815           0 :         (search-invisible isearch-invisible)
    1816             :         (replace-lax-whitespace
    1817           0 :          isearch-lax-whitespace)
    1818             :         (replace-regexp-lax-whitespace
    1819           0 :          isearch-regexp-lax-whitespace)
    1820           0 :         (delimited (and arg (not (eq arg '-))))
    1821           0 :         (backward (and arg (eq arg '-)))
    1822             :         ;; Set `isearch-recursive-edit' to nil to prevent calling
    1823             :         ;; `exit-recursive-edit' in `isearch-done' that terminates
    1824             :         ;; the execution of this command when it is non-nil.
    1825             :         ;; We call `exit-recursive-edit' explicitly at the end below.
    1826             :         (isearch-recursive-edit nil))
    1827           0 :     (isearch-done nil t)
    1828           0 :     (isearch-clean-overlays)
    1829           0 :     (if (and isearch-other-end
    1830           0 :              (if backward
    1831           0 :                  (> isearch-other-end (point))
    1832           0 :                (< isearch-other-end (point)))
    1833           0 :              (not (and transient-mark-mode mark-active
    1834           0 :                        (if backward
    1835           0 :                            (> (mark) (point))
    1836           0 :                          (< (mark) (point))))))
    1837           0 :         (goto-char isearch-other-end))
    1838           0 :     (set query-replace-from-history-variable
    1839           0 :          (cons isearch-string
    1840           0 :                (symbol-value query-replace-from-history-variable)))
    1841           0 :     (perform-replace
    1842           0 :      isearch-string
    1843           0 :      (query-replace-read-to
    1844           0 :       isearch-string
    1845           0 :       (concat "Query replace"
    1846           0 :               (isearch--describe-regexp-mode (or delimited isearch-regexp-function) t)
    1847           0 :               (if backward " backward" "")
    1848           0 :               (if (and transient-mark-mode mark-active) " in region" ""))
    1849           0 :       isearch-regexp)
    1850           0 :      t isearch-regexp (or delimited isearch-regexp-function) nil nil
    1851           0 :      (if (and transient-mark-mode mark-active) (region-beginning))
    1852           0 :      (if (and transient-mark-mode mark-active) (region-end))
    1853           0 :      backward))
    1854           0 :   (and isearch-recursive-edit (exit-recursive-edit)))
    1855             : 
    1856             : (defun isearch-query-replace-regexp (&optional arg)
    1857             :   "Start `query-replace-regexp' with string to replace from last search string.
    1858             : See `isearch-query-replace' for more information."
    1859             :   (interactive
    1860           0 :    (list current-prefix-arg))
    1861           0 :   (isearch-query-replace arg t))
    1862             : 
    1863             : (defun isearch-occur (regexp &optional nlines)
    1864             :   "Run `occur' using the last search string as the regexp.
    1865             : Interactively, REGEXP is constructed using the search string from the
    1866             : last search command.  NLINES has the same meaning as in `occur'.
    1867             : 
    1868             : If the last search command was a word search, REGEXP is computed from
    1869             : the search words, ignoring punctuation.  If the last search
    1870             : command was a regular expression search, REGEXP is the regular
    1871             : expression used in that search.  If the last search command searched
    1872             : for a literal string, REGEXP is constructed by quoting all the special
    1873             : characters in that string."
    1874             :   (interactive
    1875           0 :    (let* ((perform-collect (consp current-prefix-arg))
    1876           0 :           (regexp (cond
    1877           0 :                    ((functionp isearch-regexp-function)
    1878           0 :                     (funcall isearch-regexp-function isearch-string))
    1879           0 :                    (isearch-regexp-function (word-search-regexp isearch-string))
    1880           0 :                    (isearch-regexp isearch-string)
    1881           0 :                    (t (regexp-quote isearch-string)))))
    1882           0 :      (list regexp
    1883           0 :            (if perform-collect
    1884             :                ;; Perform collect operation
    1885           0 :                (if (zerop (regexp-opt-depth regexp))
    1886             :                    ;; No subexpression so collect the entire match.
    1887             :                    "\\&"
    1888             :                  ;; Get the regexp for collection pattern.
    1889           0 :                  (let ((default (car occur-collect-regexp-history))
    1890             :                        regexp-collect)
    1891           0 :                    (with-isearch-suspended
    1892             :                     (setq regexp-collect
    1893             :                           (read-regexp
    1894             :                            (format "Regexp to collect (default %s): " default)
    1895           0 :                            default 'occur-collect-regexp-history)))
    1896           0 :                    regexp-collect))
    1897             :              ;; Otherwise normal occur takes numerical prefix argument.
    1898           0 :              (when current-prefix-arg
    1899           0 :                (prefix-numeric-value current-prefix-arg))))))
    1900           0 :   (let ((case-fold-search isearch-case-fold-search)
    1901             :         ;; Set `search-upper-case' to nil to not call
    1902             :         ;; `isearch-no-upper-case-p' in `occur-1'.
    1903             :         (search-upper-case nil)
    1904             :         (search-spaces-regexp
    1905           0 :          (if (if isearch-regexp
    1906           0 :                  isearch-regexp-lax-whitespace
    1907           0 :                isearch-lax-whitespace)
    1908           0 :              search-whitespace-regexp)))
    1909           0 :     (occur (if isearch-regexp-function
    1910           0 :                (propertize regexp
    1911           0 :                            'isearch-string isearch-string
    1912             :                            'isearch-regexp-function-descr
    1913           0 :                            (isearch--describe-regexp-mode isearch-regexp-function))
    1914           0 :              regexp)
    1915           0 :            nlines)))
    1916             : 
    1917             : (declare-function hi-lock-read-face-name "hi-lock" ())
    1918             : 
    1919             : (defun isearch-highlight-regexp ()
    1920             :   "Run `highlight-regexp' with regexp from the current search string.
    1921             : It exits Isearch mode and calls `hi-lock-face-buffer' with its regexp
    1922             : argument from the last search regexp or a quoted search string,
    1923             : and reads its face argument using `hi-lock-read-face-name'."
    1924             :   (interactive)
    1925           0 :   (let (
    1926             :         ;; Set `isearch-recursive-edit' to nil to prevent calling
    1927             :         ;; `exit-recursive-edit' in `isearch-done' that terminates
    1928             :         ;; the execution of this command when it is non-nil.
    1929             :         ;; We call `exit-recursive-edit' explicitly at the end below.
    1930             :         (isearch-recursive-edit nil))
    1931           0 :     (isearch-done nil t)
    1932           0 :     (isearch-clean-overlays))
    1933           0 :   (require 'hi-lock nil t)
    1934           0 :   (let ((regexp (cond ((functionp isearch-regexp-function)
    1935           0 :                        (funcall isearch-regexp-function isearch-string))
    1936           0 :                       (isearch-regexp-function (word-search-regexp isearch-string))
    1937           0 :                       (isearch-regexp isearch-string)
    1938           0 :                       ((if (and (eq isearch-case-fold-search t)
    1939           0 :                                 search-upper-case)
    1940           0 :                            (isearch-no-upper-case-p
    1941           0 :                             isearch-string isearch-regexp)
    1942           0 :                          isearch-case-fold-search)
    1943             :                        ;; Turn isearch-string into a case-insensitive
    1944             :                        ;; regexp.
    1945           0 :                        (mapconcat
    1946             :                         (lambda (c)
    1947           0 :                           (let ((s (string c)))
    1948           0 :                             (if (string-match "[[:alpha:]]" s)
    1949           0 :                                 (format "[%s%s]" (upcase s) (downcase s))
    1950           0 :                               (regexp-quote s))))
    1951           0 :                         isearch-string ""))
    1952           0 :                       (t (regexp-quote isearch-string)))))
    1953           0 :     (hi-lock-face-buffer regexp (hi-lock-read-face-name)))
    1954           0 :   (and isearch-recursive-edit (exit-recursive-edit)))
    1955             : 
    1956             : 
    1957             : (defun isearch-delete-char ()
    1958             :   "Discard last input item and move point back.
    1959             : Last input means the last character or the last isearch command
    1960             : that added or deleted characters from the search string,
    1961             : moved point, toggled regexp mode or case-sensitivity, etc.
    1962             : If no previous match was done, just beep."
    1963             :   (interactive)
    1964           0 :   (if (null (cdr isearch-cmds))
    1965           0 :       (ding)
    1966           0 :     (isearch-pop-state))
    1967           0 :   (isearch-update))
    1968             : 
    1969             : (defun isearch-del-char (&optional arg)
    1970             :   "Delete character from end of search string and search again.
    1971             : Unlike `isearch-delete-char', it only deletes the last character,
    1972             : but doesn't cancel the effect of other isearch command.
    1973             : If search string is empty, just beep."
    1974             :   (interactive "p")
    1975           0 :   (if (= 0 (length isearch-string))
    1976           0 :       (ding)
    1977           0 :     (setq isearch-string (substring isearch-string 0
    1978           0 :                                     (- (min (or arg 1)
    1979           0 :                                             (length isearch-string))))
    1980           0 :           isearch-message (mapconcat 'isearch-text-char-description
    1981           0 :                                      isearch-string "")))
    1982             :   ;; Do the following before moving point.
    1983           0 :   (funcall (or isearch-message-function #'isearch-message) nil t)
    1984             :   ;; Use the isearch-other-end as new starting point to be able
    1985             :   ;; to find the remaining part of the search string again.
    1986             :   ;; This is like what `isearch-search-and-update' does,
    1987             :   ;; but currently it doesn't support deletion of characters
    1988             :   ;; for the case where unsuccessful search may become successful
    1989             :   ;; by deletion of characters.
    1990           0 :   (if isearch-other-end (goto-char isearch-other-end))
    1991           0 :   (isearch-search)
    1992           0 :   (isearch-push-state)
    1993           0 :   (isearch-update))
    1994             : 
    1995             : (defun isearch-yank-string (string)
    1996             :   "Pull STRING into search string."
    1997             :   ;; Downcase the string if not supposed to case-fold yanked strings.
    1998           0 :   (if (and isearch-case-fold-search
    1999           0 :            (eq 'not-yanks search-upper-case))
    2000           0 :       (setq string (downcase string)))
    2001           0 :   (if isearch-regexp (setq string (regexp-quote string)))
    2002             :   ;; Don't move cursor in reverse search.
    2003           0 :   (setq isearch-yank-flag t)
    2004           0 :   (isearch-process-search-string
    2005           0 :    string (mapconcat 'isearch-text-char-description string "")))
    2006             : 
    2007             : (defun isearch-yank-kill ()
    2008             :   "Pull string from kill ring into search string."
    2009             :   (interactive)
    2010           0 :   (isearch-yank-string (current-kill 0)))
    2011             : 
    2012             : (defun isearch-yank-pop ()
    2013             :   "Replace just-yanked search string with previously killed string."
    2014             :   (interactive)
    2015           0 :   (if (not (memq last-command '(isearch-yank-kill isearch-yank-pop)))
    2016             :       ;; Fall back on `isearch-yank-kill' for the benefits of people
    2017             :       ;; who are used to the old behavior of `M-y' in isearch mode. In
    2018             :       ;; future, this fallback may be changed if we ever change
    2019             :       ;; `yank-pop' to do something like the kill-ring-browser.
    2020           0 :       (isearch-yank-kill)
    2021           0 :     (isearch-pop-state)
    2022           0 :     (isearch-yank-string (current-kill 1))))
    2023             : 
    2024             : (defun isearch-yank-x-selection ()
    2025             :   "Pull current X selection into search string."
    2026             :   (interactive)
    2027           0 :   (isearch-yank-string (gui-get-selection))
    2028             :   ;; If `gui-get-selection' returned the text from the active region,
    2029             :   ;; then it "used" the mark which we should hence deactivate.
    2030           0 :   (when select-active-regions (deactivate-mark)))
    2031             : 
    2032             : 
    2033             : (defun isearch-mouse-2 (click)
    2034             :   "Handle mouse-2 in Isearch mode.
    2035             : For a click in the echo area, invoke `isearch-yank-x-selection'.
    2036             : Otherwise invoke whatever the calling mouse-2 command sequence
    2037             : is bound to outside of Isearch."
    2038             :   (interactive "e")
    2039           0 :   (let ((w (posn-window (event-start click)))
    2040           0 :         (binding (let ((overriding-terminal-local-map nil))
    2041           0 :                    (key-binding (this-command-keys-vector) t))))
    2042           0 :     (if (and (window-minibuffer-p w)
    2043           0 :              (not (minibuffer-window-active-p w))) ; in echo area
    2044           0 :         (isearch-yank-x-selection)
    2045           0 :       (when (functionp binding)
    2046           0 :         (call-interactively binding)))))
    2047             : 
    2048             : (declare-function xterm--pasted-text "term/xterm" ())
    2049             : 
    2050             : (defun isearch-xterm-paste ()
    2051             :   "Pull terminal paste into search string."
    2052             :   (interactive)
    2053           0 :   (isearch-yank-string (xterm--pasted-text)))
    2054             : 
    2055             : (defun isearch-yank-internal (jumpform)
    2056             :   "Pull the text from point to the point reached by JUMPFORM.
    2057             : JUMPFORM is a lambda expression that takes no arguments and returns
    2058             : a buffer position, possibly having moved point to that position.
    2059             : For example, it might move point forward by a word and return point,
    2060             : or it might return the position of the end of the line."
    2061           0 :   (isearch-yank-string
    2062           0 :    (save-excursion
    2063           0 :      (and (not isearch-forward) isearch-other-end
    2064           0 :           (goto-char isearch-other-end))
    2065           0 :      (buffer-substring-no-properties (point) (funcall jumpform)))))
    2066             : 
    2067             : (defun isearch-yank-char-in-minibuffer (&optional arg)
    2068             :   "Pull next character from buffer into end of search string in minibuffer."
    2069             :   (interactive "p")
    2070           0 :   (if (eobp)
    2071           0 :       (insert
    2072           0 :        (with-current-buffer (cadr (buffer-list))
    2073           0 :          (buffer-substring-no-properties
    2074           0 :           (point) (progn (forward-char arg) (point)))))
    2075           0 :     (forward-char arg)))
    2076             : 
    2077             : (defun isearch-yank-char (&optional arg)
    2078             :   "Pull next character from buffer into search string.
    2079             : If optional ARG is non-nil, pull in the next ARG characters."
    2080             :   (interactive "p")
    2081           0 :   (isearch-yank-internal (lambda () (forward-char arg) (point))))
    2082             : 
    2083             : (declare-function subword-forward "subword" (&optional arg))
    2084             : (defun isearch-yank-word-or-char ()
    2085             :   "Pull next character, subword or word from buffer into search string.
    2086             : Subword is used when `subword-mode' is activated. "
    2087             :   (interactive)
    2088           0 :   (isearch-yank-internal
    2089             :    (lambda ()
    2090           0 :      (if (or (= (char-syntax (or (char-after) 0)) ?w)
    2091           0 :              (= (char-syntax (or (char-after (1+ (point))) 0)) ?w))
    2092           0 :          (if (or (and (boundp 'subword-mode) subword-mode)
    2093           0 :                  (and (boundp 'superword-mode) superword-mode))
    2094           0 :              (subword-forward 1)
    2095           0 :            (forward-word 1))
    2096           0 :        (forward-char 1))
    2097           0 :      (point))))
    2098             : 
    2099             : (defun isearch-yank-word (&optional arg)
    2100             :   "Pull next word from buffer into search string.
    2101             : If optional ARG is non-nil, pull in the next ARG words."
    2102             :   (interactive "p")
    2103           0 :   (isearch-yank-internal (lambda () (forward-word arg) (point))))
    2104             : 
    2105             : (defun isearch-yank-line (&optional arg)
    2106             :   "Pull rest of line from buffer into search string.
    2107             : If optional ARG is non-nil, yank the next ARG lines."
    2108             :   (interactive "p")
    2109           0 :   (isearch-yank-internal
    2110           0 :    (lambda () (let ((inhibit-field-text-motion t))
    2111           0 :                 (line-end-position (if (eolp) (1+ arg) arg))))))
    2112             : 
    2113             : (defun isearch-char-by-name (&optional count)
    2114             :   "Read a character by its Unicode name and add it to the search string.
    2115             : Completion is available like in `read-char-by-name' used by `insert-char'.
    2116             : With argument, add COUNT copies of the character."
    2117             :   (interactive "p")
    2118           0 :   (with-isearch-suspended
    2119             :    (let ((char (read-char-by-name "Add character to search (Unicode name or hex): ")))
    2120             :      (when char
    2121             :        (let ((string (if (and (integerp count) (> count 1))
    2122             :                          (make-string count char)
    2123             :                        (char-to-string char))))
    2124             :          (setq isearch-new-string (concat isearch-string string)
    2125             :                isearch-new-message (concat isearch-message
    2126             :                                            (mapconcat 'isearch-text-char-description
    2127           0 :                                                       string ""))))))))
    2128             : 
    2129             : (defun isearch-search-and-update ()
    2130             :   ;; Do the search and update the display.
    2131           0 :   (when (or isearch-success
    2132             :             ;; Unsuccessful regexp search may become successful by
    2133             :             ;; addition of characters which make isearch-string valid
    2134           0 :             isearch-regexp
    2135             :             ;; If the string was found but was completely invisible,
    2136             :             ;; it might now be partly visible, so try again.
    2137           0 :             (prog1 isearch-hidden (setq isearch-hidden nil)))
    2138             :     ;; In reverse search, adding stuff at
    2139             :     ;; the end may cause zero or many more chars to be
    2140             :     ;; matched, in the string following point.
    2141             :     ;; Allow all those possibilities without moving point as
    2142             :     ;; long as the match does not extend past search origin.
    2143           0 :     (if (and (not isearch-forward) (not isearch-adjusted)
    2144           0 :              (condition-case ()
    2145           0 :                  (let ((case-fold-search isearch-case-fold-search))
    2146           0 :                    (if (and (eq case-fold-search t) search-upper-case)
    2147           0 :                        (setq case-fold-search
    2148           0 :                              (isearch-no-upper-case-p isearch-string isearch-regexp)))
    2149           0 :                    (looking-at (cond
    2150           0 :                                 ((functionp isearch-regexp-function)
    2151           0 :                                  (funcall isearch-regexp-function isearch-string t))
    2152           0 :                                 (isearch-regexp-function (word-search-regexp isearch-string t))
    2153           0 :                                 (isearch-regexp isearch-string)
    2154           0 :                                 (t (regexp-quote isearch-string)))))
    2155           0 :                (error nil))
    2156           0 :              (or isearch-yank-flag
    2157           0 :                  (<= (match-end 0)
    2158           0 :                      (min isearch-opoint isearch-barrier))))
    2159           0 :         (progn
    2160           0 :           (setq isearch-success t
    2161             :                 isearch-error nil
    2162           0 :                 isearch-other-end (match-end 0))
    2163           0 :           (if (and (eq isearch-case-fold-search t) search-upper-case)
    2164           0 :               (setq isearch-case-fold-search
    2165           0 :                     (isearch-no-upper-case-p isearch-string isearch-regexp))))
    2166             :       ;; Not regexp, not reverse, or no match at point.
    2167             :       ;; Do the following before moving point.
    2168           0 :       (funcall (or isearch-message-function #'isearch-message) nil t)
    2169           0 :       (if (and isearch-other-end (not isearch-adjusted))
    2170           0 :           (goto-char (if isearch-forward isearch-other-end
    2171           0 :                        (min isearch-opoint
    2172           0 :                             isearch-barrier
    2173           0 :                             (1+ isearch-other-end)))))
    2174           0 :       (isearch-search)
    2175           0 :       ))
    2176           0 :   (isearch-push-state)
    2177           0 :   (if isearch-op-fun (funcall isearch-op-fun))
    2178           0 :   (isearch-update))
    2179             : 
    2180             : 
    2181             : ;; *, ?, }, and | chars can make a regexp more liberal.
    2182             : ;; They can make a regexp match sooner or make it succeed instead of failing.
    2183             : ;; So go back to place last successful search started
    2184             : ;; or to the last ^S/^R (barrier), whichever is nearer.
    2185             : ;; + needs no special handling because the string must match at least once.
    2186             : 
    2187             : (defun isearch-backslash (str)
    2188             :   "Return t if STR ends in an odd number of backslashes."
    2189           0 :   (= (mod (- (length str) (string-match "\\\\*\\'" str)) 2) 1))
    2190             : 
    2191             : (defun isearch-fallback (want-backslash &optional allow-invalid to-barrier)
    2192             :   "Return point to previous successful match to allow regexp liberalization.
    2193             : \\<isearch-mode-map>
    2194             : Respects \\[isearch-repeat-forward] and \\[isearch-repeat-backward] by \
    2195             : stopping at `isearch-barrier' as needed.
    2196             : 
    2197             : Do nothing if a backslash is escaping the liberalizing character.
    2198             : If WANT-BACKSLASH is non-nil, invert this behavior (for \\} and \\|).
    2199             : 
    2200             : Do nothing if regexp has recently been invalid unless optional
    2201             : ALLOW-INVALID non-nil.
    2202             : 
    2203             : If optional TO-BARRIER non-nil, ignore previous matches and go exactly
    2204             : to the barrier."
    2205             :   ;; (eq (not a) (not b)) makes all non-nil values equivalent
    2206           0 :   (when (and isearch-regexp (eq (not (isearch-backslash isearch-string))
    2207           0 :                                 (not want-backslash))
    2208             :              ;; We have to check 2 stack frames because the last might be
    2209             :              ;; invalid just because of a backslash.
    2210           0 :              (or (not isearch-error)
    2211           0 :                  (not (isearch--state-error (cadr isearch-cmds)))
    2212           0 :                  allow-invalid))
    2213           0 :     (if to-barrier
    2214           0 :         (progn (goto-char isearch-barrier)
    2215           0 :                (setq isearch-adjusted t))
    2216           0 :       (let* ((stack isearch-cmds)
    2217           0 :              (previous (cdr stack))     ; lookbelow in the stack
    2218           0 :              (frame (car stack)))
    2219             :         ;; Walk down the stack looking for a valid regexp (as of course only
    2220             :         ;; they can be the previous successful match); this conveniently
    2221             :         ;; removes all bracket-sets and groups that might be in the way, as
    2222             :         ;; well as partial \{\} constructs that the code below leaves behind.
    2223             :         ;; Also skip over postfix operators -- though horrid,
    2224             :         ;; 'ab?\{5,6\}+\{1,2\}*' is perfectly valid.
    2225           0 :         (while (and previous
    2226           0 :                     (or (isearch--state-error frame)
    2227           0 :                         (let* ((string (isearch--state-string frame))
    2228           0 :                                (lchar (aref string (1- (length string)))))
    2229             :                           ;; The operators aren't always operators; check
    2230             :                           ;; backslashes.  This doesn't handle the case of
    2231             :                           ;; operators at the beginning of the regexp not
    2232             :                           ;; being special, but then we should fall back to
    2233             :                           ;; the barrier anyway because it's all optional.
    2234           0 :                           (if (isearch-backslash
    2235           0 :                                (isearch--state-string (car previous)))
    2236           0 :                               (eq lchar ?\})
    2237           0 :                             (memq lchar '(?* ?? ?+))))))
    2238           0 :           (setq stack previous previous (cdr previous) frame (car stack)))
    2239           0 :         (when stack
    2240             :           ;; `stack' now refers the most recent valid regexp that is not at
    2241             :           ;; all optional in its last term.  Now dig one level deeper and find
    2242             :           ;; what matched before that.
    2243           0 :           (let ((last-other-end
    2244           0 :                  (or (and (car previous)
    2245           0 :                           (isearch--state-other-end (car previous)))
    2246           0 :                      isearch-barrier)))
    2247           0 :             (goto-char (if isearch-forward
    2248           0 :                            (max last-other-end isearch-barrier)
    2249           0 :                          (min last-other-end isearch-barrier)))
    2250           0 :             (setq isearch-adjusted t)))))))
    2251             : 
    2252             : ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    2253             : ;; scrolling within Isearch mode.  Alan Mackenzie (acm@muc.de), 2003/2/24
    2254             : ;;
    2255             : ;; The idea here is that certain vertical scrolling commands (like C-l
    2256             : ;; `recenter') should be usable WITHIN Isearch mode.  For a command to be
    2257             : ;; suitable, it must NOT alter the buffer, swap to another buffer or frame,
    2258             : ;; tamper with isearch's state, or move point.  It is unacceptable for the
    2259             : ;; search string to be scrolled out of the current window.  If a command
    2260             : ;; attempts this, we scroll the text back again.
    2261             : ;;
    2262             : ;; We implement this feature with a property called `isearch-scroll'.
    2263             : ;; If a command's symbol has the value t for this property or for the
    2264             : ;; `scroll-command' property, it is a scrolling command.  The feature
    2265             : ;; needs to be enabled by setting the customizable variable
    2266             : ;; `isearch-allow-scroll' to a non-nil value.
    2267             : ;;
    2268             : ;; The universal argument commands (e.g. C-u) in simple.el are marked
    2269             : ;; as scrolling commands, and isearch.el has been amended to allow
    2270             : ;; prefix arguments to be passed through to scrolling commands.  Thus
    2271             : ;; M-0 C-l will scroll point to the top of the window.
    2272             : ;;
    2273             : ;; Horizontal scrolling commands are currently not catered for.
    2274             : ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    2275             : 
    2276             : ;; Set the isearch-scroll property on some standard functions:
    2277             : ;; Scroll-bar functions:
    2278             : (if (fboundp 'scroll-bar-toolkit-scroll)
    2279             :     (put 'scroll-bar-toolkit-scroll 'isearch-scroll t))
    2280             : (if (fboundp 'w32-handle-scroll-bar-event)
    2281             :     (put 'w32-handle-scroll-bar-event 'isearch-scroll t))
    2282             : 
    2283             : ;; Commands which scroll the window (some scroll commands
    2284             : ;; already have the `scroll-command' property on them):
    2285             : (put 'recenter 'isearch-scroll t)
    2286             : (put 'recenter-top-bottom 'isearch-scroll t)
    2287             : (put 'reposition-window 'isearch-scroll t)
    2288             : 
    2289             : ;; Commands which act on the other window
    2290             : (put 'list-buffers 'isearch-scroll t)
    2291             : (put 'scroll-other-window 'isearch-scroll t)
    2292             : (put 'scroll-other-window-down 'isearch-scroll t)
    2293             : (put 'beginning-of-buffer-other-window 'isearch-scroll t)
    2294             : (put 'end-of-buffer-other-window 'isearch-scroll t)
    2295             : 
    2296             : ;; Commands which change the window layout
    2297             : (put 'delete-other-windows 'isearch-scroll t)
    2298             : (put 'balance-windows 'isearch-scroll t)
    2299             : (put 'split-window-right 'isearch-scroll t)
    2300             : (put 'split-window-below 'isearch-scroll t)
    2301             : (put 'enlarge-window 'isearch-scroll t)
    2302             : 
    2303             : ;; Aliases for split-window-*
    2304             : (put 'split-window-vertically 'isearch-scroll t)
    2305             : (put 'split-window-horizontally 'isearch-scroll t)
    2306             : 
    2307             : ;; Universal argument commands
    2308             : (put 'universal-argument 'isearch-scroll t)
    2309             : (put 'universal-argument-more 'isearch-scroll t)
    2310             : (put 'negative-argument 'isearch-scroll t)
    2311             : (put 'digit-argument 'isearch-scroll t)
    2312             : 
    2313             : (defcustom isearch-allow-scroll nil
    2314             :   "Whether scrolling is allowed during incremental search.
    2315             : If non-nil, scrolling commands can be used in Isearch mode.
    2316             : However, the current match will never scroll offscreen.
    2317             : If nil, scrolling commands will first cancel Isearch mode."
    2318             :   :type 'boolean
    2319             :   :group 'isearch)
    2320             : 
    2321             : (defcustom isearch-allow-prefix t
    2322             :   "Whether prefix arguments are allowed during incremental search.
    2323             : If non-nil, entering a prefix argument will not terminate the
    2324             : search.  This option is ignored \(presumed t) when
    2325             : `isearch-allow-scroll' is set."
    2326             :   :version "24.4"
    2327             :   :type 'boolean
    2328             :   :group 'isearch)
    2329             : 
    2330             : (defun isearch-string-out-of-window (isearch-point)
    2331             :   "Test whether the search string is currently outside of the window.
    2332             : Return nil if it's completely visible, or if point is visible,
    2333             : together with as much of the search string as will fit; the symbol
    2334             : `above' if we need to scroll the text downwards; the symbol `below',
    2335             : if upwards."
    2336           0 :   (let ((w-start (window-group-start))
    2337           0 :         (w-end (window-group-end nil t))
    2338           0 :         (w-L1 (save-excursion
    2339           0 :                 (save-selected-window (move-to-window-group-line 1) (point))))
    2340           0 :         (w-L-1 (save-excursion
    2341           0 :                  (save-selected-window (move-to-window-group-line -1) (point))))
    2342             :         start end)                  ; start and end of search string in buffer
    2343           0 :     (if isearch-forward
    2344           0 :         (setq end isearch-point  start (or isearch-other-end isearch-point))
    2345           0 :       (setq start isearch-point  end (or isearch-other-end isearch-point)))
    2346           0 :     (cond ((or (and (>= start w-start) (<= end w-end))
    2347           0 :                (if isearch-forward
    2348           0 :                    (and (>= isearch-point w-L-1) (< isearch-point w-end)) ; point on Line -1
    2349           0 :                  (and (>= isearch-point w-start) (< isearch-point w-L1)))) ; point on Line 0
    2350             :            nil)
    2351           0 :           ((and (< start w-start)
    2352           0 :                 (< isearch-point w-L-1))
    2353             :            'above)
    2354           0 :           (t 'below))))
    2355             : 
    2356             : (defun isearch-back-into-window (above isearch-point)
    2357             :   "Scroll the window to bring the search string back into view.
    2358             : Restore point to ISEARCH-POINT in the process.  ABOVE is t when the
    2359             : search string is above the top of the window, nil when it is beneath
    2360             : the bottom."
    2361           0 :   (let (start end)
    2362           0 :     (if isearch-forward
    2363           0 :         (setq end isearch-point  start (or isearch-other-end isearch-point))
    2364           0 :       (setq start isearch-point  end (or isearch-other-end isearch-point)))
    2365           0 :     (if above
    2366           0 :         (progn
    2367           0 :           (goto-char start)
    2368           0 :           (recenter-window-group 0)
    2369           0 :           (when (>= isearch-point (window-group-end nil t))
    2370           0 :             (goto-char isearch-point)
    2371           0 :             (recenter-window-group -1)))
    2372           0 :       (goto-char end)
    2373           0 :       (recenter-window-group -1)
    2374           0 :       (when (< isearch-point (window-group-start))
    2375           0 :         (goto-char isearch-point)
    2376           0 :         (recenter-window-group 0))))
    2377           0 :   (goto-char isearch-point))
    2378             : 
    2379             : (defvar isearch-pre-scroll-point nil)
    2380             : 
    2381             : (defun isearch-pre-command-hook ()
    2382             :   "Decide whether to exit Isearch mode before executing the command.
    2383             : Don't exit Isearch if the key sequence that invoked this command
    2384             : is bound in `isearch-mode-map', or if the invoked command is
    2385             : a prefix argument command (when `isearch-allow-prefix' is non-nil),
    2386             : or it is a scrolling command (when `isearch-allow-scroll' is non-nil).
    2387             : Otherwise, exit Isearch (when `search-exit-option' is non-nil)
    2388             : before the command is executed globally with terminated Isearch."
    2389           0 :   (let* ((key (this-single-command-keys))
    2390           0 :          (main-event (aref key 0)))
    2391           0 :     (cond
    2392             :      ;; Don't exit Isearch if we're in the middle of some
    2393             :      ;; `set-transient-map' thingy like `universal-argument--mode'.
    2394           0 :      ((not (eq overriding-terminal-local-map isearch--saved-overriding-local-map)))
    2395             :      ;; Don't exit Isearch for isearch key bindings.
    2396           0 :      ((commandp (lookup-key isearch-mode-map key nil)))
    2397             :      ;; Optionally edit the search string instead of exiting.
    2398           0 :      ((eq search-exit-option 'edit)
    2399           0 :       (setq this-command 'isearch-edit-string))
    2400             :      ;; Handle a scrolling function or prefix argument.
    2401           0 :      ((or (and isearch-allow-prefix
    2402           0 :                (memq this-command '(universal-argument universal-argument-more
    2403           0 :                                     digit-argument negative-argument)))
    2404           0 :           (and isearch-allow-scroll
    2405           0 :                (symbolp this-command)
    2406           0 :                (or (eq (get this-command 'isearch-scroll) t)
    2407           0 :                    (eq (get this-command 'scroll-command) t))))
    2408           0 :       (when isearch-allow-scroll
    2409           0 :         (setq isearch-pre-scroll-point (point))))
    2410             :      ;; A mouse click on the isearch message starts editing the search string.
    2411           0 :      ((and (eq (car-safe main-event) 'down-mouse-1)
    2412           0 :            (window-minibuffer-p (posn-window (event-start main-event))))
    2413             :       ;; Swallow the up-event.
    2414           0 :       (read-event)
    2415           0 :       (setq this-command 'isearch-edit-string))
    2416             :      ;; Other characters terminate the search and are then executed normally.
    2417           0 :      (search-exit-option
    2418           0 :       (isearch-done)
    2419           0 :       (isearch-clean-overlays))
    2420             :      ;; If search-exit-option is nil, run the command without exiting Isearch.
    2421             :      (t
    2422           0 :       (isearch-process-search-string key key)))))
    2423             : 
    2424             : (defun isearch-post-command-hook ()
    2425           0 :   (when isearch-pre-scroll-point
    2426           0 :     (let ((ab-bel (isearch-string-out-of-window isearch-pre-scroll-point)))
    2427           0 :       (if ab-bel
    2428           0 :           (isearch-back-into-window (eq ab-bel 'above) isearch-pre-scroll-point)
    2429           0 :         (goto-char isearch-pre-scroll-point)))
    2430           0 :     (setq isearch-pre-scroll-point nil)
    2431           0 :     (isearch-update)))
    2432             : 
    2433             : (defun isearch-quote-char (&optional count)
    2434             :   "Quote special characters for incremental search.
    2435             : With argument, add COUNT copies of the character."
    2436             :   (interactive "p")
    2437           0 :   (let ((char (read-quoted-char (isearch-message t))))
    2438           0 :     (unless (characterp char)
    2439           0 :       (user-error "%s is not a valid character"
    2440           0 :                   (key-description (vector char))))
    2441             :     ;; Assume character codes 0200 - 0377 stand for characters in some
    2442             :     ;; single-byte character set, and convert them to Emacs
    2443             :     ;; characters.
    2444           0 :     (if (and isearch-regexp isearch-regexp-lax-whitespace (= char ?\s))
    2445           0 :         (if (subregexp-context-p isearch-string (length isearch-string))
    2446           0 :             (isearch-process-search-string "[ ]" " ")
    2447           0 :           (isearch-process-search-char char count))
    2448             :       ;; This used to assume character codes 0240 - 0377 stand for
    2449             :       ;; characters in some single-byte character set, and converted them
    2450             :       ;; to Emacs characters.  But in 23.1 this feature is deprecated
    2451             :       ;; in favor of inserting the corresponding Unicode characters.
    2452             :       ;; (and enable-multibyte-characters
    2453             :       ;;      (>= char ?\200)
    2454             :       ;;      (<= char ?\377)
    2455             :       ;;      (setq char (unibyte-char-to-multibyte char)))
    2456           0 :       (isearch-process-search-char char count))))
    2457             : 
    2458             : (defun isearch-printing-char (&optional char count)
    2459             :   "Add this ordinary printing CHAR to the search string and search.
    2460             : With argument, add COUNT copies of the character."
    2461           0 :   (interactive (list last-command-event
    2462           0 :                      (prefix-numeric-value current-prefix-arg)))
    2463           0 :   (let ((char (or char last-command-event)))
    2464           0 :     (if (= char ?\S-\ )
    2465           0 :         (setq char ?\s))
    2466           0 :     (if current-input-method
    2467           0 :         (isearch-process-search-multibyte-characters char count)
    2468           0 :       (isearch-process-search-char char count))))
    2469             : 
    2470             : (defun isearch-process-search-char (char &optional count)
    2471             :   "Add CHAR to the search string, COUNT times.
    2472             : Search is updated accordingly."
    2473             :   ;; * and ? are special in regexps when not preceded by \.
    2474             :   ;; } and | are special in regexps when preceded by \.
    2475             :   ;; Nothing special for + because it matches at least once.
    2476           0 :   (cond
    2477           0 :    ((memq char '(?* ??)) (isearch-fallback nil))
    2478           0 :    ((eq   char ?\})      (isearch-fallback t t))
    2479           0 :    ((eq   char ?|)       (isearch-fallback t nil t)))
    2480             : 
    2481             :   ;; Append the char(s) to the search string,
    2482             :   ;; update the message and re-search.
    2483           0 :   (let* ((string (if (and (integerp count) (> count 1))
    2484           0 :                      (make-string count char)
    2485           0 :                    (char-to-string char)))
    2486           0 :          (message (if (>= char ?\200)
    2487           0 :                       string
    2488           0 :                     (mapconcat 'isearch-text-char-description string ""))))
    2489           0 :     (isearch-process-search-string string message)))
    2490             : 
    2491             : (defun isearch-process-search-string (string message)
    2492           0 :   (setq isearch-string (concat isearch-string string)
    2493           0 :         isearch-message (concat isearch-message message))
    2494           0 :   (isearch-search-and-update))
    2495             : 
    2496             : 
    2497             : ;; Search Ring
    2498             : 
    2499             : (defun isearch-ring-adjust1 (advance)
    2500             :   ;; Helper for isearch-ring-adjust
    2501           0 :   (let* ((ring (if isearch-regexp regexp-search-ring search-ring))
    2502           0 :          (length (length ring))
    2503           0 :          (yank-pointer-name (if isearch-regexp
    2504             :                                 'regexp-search-ring-yank-pointer
    2505           0 :                               'search-ring-yank-pointer))
    2506           0 :          (yank-pointer (eval yank-pointer-name)))
    2507           0 :     (if (zerop length)
    2508             :         ()
    2509           0 :       (set yank-pointer-name
    2510           0 :            (setq yank-pointer
    2511           0 :                  (mod (+ (or yank-pointer (if advance 0 -1))
    2512           0 :                          (if advance -1 1))
    2513           0 :                       length)))
    2514           0 :       (setq isearch-string (nth yank-pointer ring)
    2515           0 :             isearch-message (mapconcat 'isearch-text-char-description
    2516           0 :                                        isearch-string "")))))
    2517             : 
    2518             : (defun isearch-ring-adjust (advance)
    2519             :   ;; Helper for isearch-ring-advance and isearch-ring-retreat
    2520           0 :   (isearch-ring-adjust1 advance)
    2521           0 :   (if search-ring-update
    2522           0 :       (progn
    2523           0 :         (funcall (or isearch-message-function #'isearch-message) nil t)
    2524           0 :         (isearch-search)
    2525           0 :         (isearch-push-state)
    2526           0 :         (isearch-update))
    2527             :     ;; Otherwise, edit the search string instead.  Note that there is
    2528             :     ;; no need to push the search state after isearch-edit-string here
    2529             :     ;; since isearch-edit-string already pushes its state
    2530           0 :     (isearch-edit-string)))
    2531             : 
    2532             : (defun isearch-ring-advance ()
    2533             :   "Advance to the next search string in the ring."
    2534             :   ;; This could be more general to handle a prefix arg, but who would use it.
    2535             :   (interactive)
    2536           0 :   (isearch-ring-adjust 'advance))
    2537             : 
    2538             : (defun isearch-ring-retreat ()
    2539             :   "Retreat to the previous search string in the ring."
    2540             :   (interactive)
    2541           0 :   (isearch-ring-adjust nil))
    2542             : 
    2543             : (defun isearch-complete1 ()
    2544             :   ;; Helper for isearch-complete and isearch-complete-edit
    2545             :   ;; Return t if completion OK, nil if no completion exists.
    2546           0 :   (let* ((ring (if isearch-regexp regexp-search-ring search-ring))
    2547           0 :          (completion-ignore-case case-fold-search)
    2548           0 :          (completion (try-completion isearch-string ring)))
    2549           0 :     (cond
    2550           0 :      ((eq completion t)
    2551             :       ;; isearch-string stays the same
    2552             :       t)
    2553           0 :      ((or completion ; not nil, must be a string
    2554           0 :           (= 0 (length isearch-string))) ; shouldn't have to say this
    2555           0 :       (if (equal completion isearch-string)  ;; no extension?
    2556           0 :           (progn
    2557           0 :             (if completion-auto-help
    2558           0 :                 (with-output-to-temp-buffer "*Isearch completions*"
    2559           0 :                   (display-completion-list
    2560           0 :                    (all-completions isearch-string ring))))
    2561           0 :             t)
    2562           0 :         (and completion
    2563           0 :              (setq isearch-string completion))))
    2564             :      (t
    2565           0 :       (message "No completion") ; waits a second if in minibuffer
    2566           0 :       nil))))
    2567             : 
    2568             : (defun isearch-complete ()
    2569             :   "Complete the search string from the strings on the search ring.
    2570             : The completed string is then editable in the minibuffer.
    2571             : If there is no completion possible, say so and continue searching."
    2572             :   (interactive)
    2573           0 :   (if (isearch-complete1)
    2574           0 :       (progn (setq isearch-message
    2575           0 :                    (mapconcat 'isearch-text-char-description
    2576           0 :                               isearch-string ""))
    2577           0 :              (isearch-edit-string))
    2578             :     ;; else
    2579           0 :     (sit-for 1)
    2580           0 :     (isearch-update)))
    2581             : 
    2582             : (defun isearch-complete-edit ()
    2583             :   "Same as `isearch-complete' except in the minibuffer."
    2584             :   (interactive)
    2585           0 :   (setq isearch-string (field-string))
    2586           0 :   (if (isearch-complete1)
    2587           0 :       (progn
    2588           0 :         (delete-field)
    2589           0 :         (insert isearch-string))))
    2590             : 
    2591             : 
    2592             : ;; Message string
    2593             : 
    2594             : (defun isearch-message (&optional c-q-hack ellipsis)
    2595             :   ;; Generate and print the message string.
    2596             : 
    2597             :   ;; N.B.: This function should always be called with point at the
    2598             :   ;; search point, because in certain (rare) circumstances, undesired
    2599             :   ;; scrolling can happen when point is elsewhere.  These
    2600             :   ;; circumstances are when follow-mode is active, the search string
    2601             :   ;; spans two (or several) windows, and the message about to be
    2602             :   ;; displayed will cause the echo area to expand.
    2603           0 :   (let ((cursor-in-echo-area ellipsis)
    2604           0 :         (m isearch-message)
    2605           0 :         (fail-pos (isearch-fail-pos t)))
    2606             :     ;; Highlight failed part
    2607           0 :     (when fail-pos
    2608           0 :       (setq m (copy-sequence m))
    2609           0 :       (add-text-properties fail-pos (length m) '(face isearch-fail) m)
    2610             :       ;; Highlight failed trailing whitespace
    2611           0 :       (when (string-match " +$" m)
    2612           0 :         (add-text-properties (match-beginning 0) (match-end 0)
    2613           0 :                              '(face trailing-whitespace) m)))
    2614           0 :     (setq m (concat
    2615           0 :              (isearch-message-prefix ellipsis isearch-nonincremental)
    2616           0 :              m
    2617           0 :              (isearch-message-suffix c-q-hack)))
    2618           0 :     (if c-q-hack m (let ((message-log-max nil)) (message "%s" m)))))
    2619             : 
    2620             : (defun isearch--describe-regexp-mode (regexp-function &optional space-before)
    2621             :   "Make a string for describing REGEXP-FUNCTION.
    2622             : If SPACE-BEFORE is non-nil, put a space before, instead of after,
    2623             : the word mode."
    2624           0 :   (when (eq regexp-function t)
    2625           0 :     (setq regexp-function #'word-search-regexp))
    2626           0 :   (let ((description
    2627           0 :          (cond
    2628             :           ;; 1. Do not use a description on the default search mode,
    2629             :           ;;    but only if the default search mode is non-nil.
    2630           0 :           ((or (and search-default-mode
    2631           0 :                     (equal search-default-mode regexp-function))
    2632             :                ;; Special case where `search-default-mode' is t
    2633             :                ;; (defaults to regexp searches).
    2634           0 :                (and (eq search-default-mode t)
    2635           0 :                     (eq search-default-mode isearch-regexp))) "")
    2636             :           ;; 2. Use the `isearch-message-prefix' set for
    2637             :           ;;    `regexp-function' if available.
    2638           0 :           (regexp-function
    2639           0 :            (and (symbolp regexp-function)
    2640           0 :                 (or (get regexp-function 'isearch-message-prefix)
    2641           0 :                     "")))
    2642             :           ;; 3. Else if `isearch-regexp' is non-nil, set description
    2643             :           ;;    to "regexp ".
    2644           0 :           (isearch-regexp "regexp ")
    2645             :           ;; 4. Else if we're in literal mode (and if the default
    2646             :           ;;    mode is also not literal), describe it.
    2647           0 :           ((functionp search-default-mode) "literal ")
    2648             :           ;; 5. And finally, if none of the above is true, set the
    2649             :           ;;    description to an empty string.
    2650           0 :           (t ""))))
    2651           0 :     (if space-before
    2652             :         ;; Move space from the end to the beginning.
    2653           0 :         (replace-regexp-in-string "\\(.*\\) \\'" " \\1" description)
    2654           0 :       description)))
    2655             : (define-obsolete-function-alias 'isearch--describe-word-mode
    2656             :   'isearch--describe-regexp-mode "25.1")
    2657             : 
    2658             : (defun isearch-message-prefix (&optional ellipsis nonincremental)
    2659             :   ;; If about to search, and previous search regexp was invalid,
    2660             :   ;; check that it still is.  If it is valid now,
    2661             :   ;; let the message we display while searching say that it is valid.
    2662           0 :   (and isearch-error ellipsis
    2663           0 :        (condition-case ()
    2664           0 :            (progn (re-search-forward isearch-string (point) t)
    2665           0 :                   (setq isearch-error nil))
    2666           0 :          (error nil)))
    2667             :   ;; If currently failing, display no ellipsis.
    2668           0 :   (or isearch-success (setq ellipsis nil))
    2669           0 :   (let ((m (concat (if isearch-success "" "failing ")
    2670           0 :                    (if isearch-adjusted "pending " "")
    2671           0 :                    (if (and isearch-wrapped
    2672           0 :                             (not isearch-wrap-function)
    2673           0 :                             (if isearch-forward
    2674           0 :                                 (> (point) isearch-opoint)
    2675           0 :                               (< (point) isearch-opoint)))
    2676           0 :                        "over")
    2677           0 :                    (if isearch-wrapped "wrapped ")
    2678           0 :                    (let ((prefix ""))
    2679           0 :                      (advice-function-mapc
    2680             :                       (lambda (_ props)
    2681           0 :                         (let ((np (cdr (assq 'isearch-message-prefix props))))
    2682           0 :                           (if np (setq prefix (concat np prefix)))))
    2683           0 :                       isearch-filter-predicate)
    2684           0 :                      prefix)
    2685           0 :                    (isearch--describe-regexp-mode isearch-regexp-function)
    2686           0 :                    (cond
    2687           0 :                     (multi-isearch-file-list "multi-file ")
    2688           0 :                     (multi-isearch-buffer-list "multi-buffer ")
    2689           0 :                     (t ""))
    2690           0 :                    (or isearch-message-prefix-add "")
    2691           0 :                    (if nonincremental "search" "I-search")
    2692           0 :                    (if isearch-forward "" " backward")
    2693           0 :                    (if current-input-method
    2694             :                        ;; Input methods for RTL languages use RTL
    2695             :                        ;; characters for their title, and that messes
    2696             :                        ;; up the display of search text after the prompt.
    2697           0 :                        (bidi-string-mark-left-to-right
    2698           0 :                         (concat " [" current-input-method-title "]: "))
    2699           0 :                      ": ")
    2700           0 :                    )))
    2701           0 :     (propertize (concat (upcase (substring m 0 1)) (substring m 1))
    2702           0 :                 'face 'minibuffer-prompt)))
    2703             : 
    2704             : (defun isearch-message-suffix (&optional c-q-hack)
    2705           0 :   (concat (if c-q-hack "^Q" "")
    2706           0 :           (if isearch-error
    2707           0 :               (concat " [" isearch-error "]")
    2708           0 :             "")
    2709           0 :           (or isearch-message-suffix-add "")))
    2710             : 
    2711             : 
    2712             : ;; Searching
    2713             : 
    2714             : (defvar isearch-search-fun-function 'isearch-search-fun-default
    2715             :   "Non-default value overrides the behavior of `isearch-search-fun-default'.
    2716             : This variable's value should be a function, which will be called
    2717             : with no arguments, and should return a function that takes three
    2718             : arguments: STRING, BOUND, and NOERROR.  STRING is the string to
    2719             : be searched for.  See `re-search-forward' for the meaning of
    2720             : BOUND and NOERROR arguments.
    2721             : 
    2722             : This returned function will be used by `isearch-search-string' to
    2723             : search for the first occurrence of STRING.")
    2724             : 
    2725             : (defun isearch-search-fun ()
    2726             :   "Return the function to use for the search.
    2727             : Can be changed via `isearch-search-fun-function' for special needs."
    2728           0 :   (funcall (or isearch-search-fun-function 'isearch-search-fun-default)))
    2729             : 
    2730             : (defun isearch--lax-regexp-function-p ()
    2731             :   "Non-nil if next regexp-function call should be lax."
    2732           0 :   (not (or isearch-nonincremental
    2733           0 :            (null (car isearch-cmds))
    2734           0 :            (eq (length isearch-string)
    2735           0 :                (length (isearch--state-string
    2736           0 :                         (car isearch-cmds)))))))
    2737             : 
    2738             : (defun isearch-search-fun-default ()
    2739             :   "Return default functions to use for the search."
    2740             :   (lambda (string &optional bound noerror count)
    2741             :     ;; Use lax versions to not fail at the end of the word while
    2742             :     ;; the user adds and removes characters in the search string
    2743             :     ;; (or when using nonincremental word isearch)
    2744           0 :     (let ((search-spaces-regexp (when (cond
    2745           0 :                                        (isearch-regexp isearch-regexp-lax-whitespace)
    2746           0 :                                        (t isearch-lax-whitespace))
    2747           0 :                                   search-whitespace-regexp)))
    2748           0 :       (condition-case er
    2749           0 :           (funcall
    2750           0 :            (if isearch-forward #'re-search-forward #'re-search-backward)
    2751           0 :            (cond (isearch-regexp-function
    2752           0 :                   (let ((lax (and (not bound) (isearch--lax-regexp-function-p))))
    2753           0 :                     (when lax
    2754           0 :                       (setq isearch-adjusted t))
    2755           0 :                     (if (functionp isearch-regexp-function)
    2756           0 :                         (funcall isearch-regexp-function string lax)
    2757           0 :                       (word-search-regexp string lax))))
    2758           0 :                  (isearch-regexp string)
    2759           0 :                  (t (regexp-quote string)))
    2760           0 :            bound noerror count)
    2761             :         (search-failed
    2762           0 :          (signal (car er)
    2763           0 :                  (let ((prefix (get isearch-regexp-function 'isearch-message-prefix)))
    2764           0 :                    (if (and isearch-regexp-function (stringp prefix))
    2765           0 :                        (list (format "%s   [using %ssearch]" string prefix))
    2766           0 :                      (cdr er)))))))))
    2767             : 
    2768             : (defun isearch-search-string (string bound noerror)
    2769             :   "Search for the first occurrence of STRING or its translation.
    2770             : STRING's characters are translated using `translation-table-for-input'
    2771             : if that is non-nil.
    2772             : If found, move point to the end of the occurrence,
    2773             : update the match data, and return point.
    2774             : An optional second argument bounds the search; it is a buffer position.
    2775             : The match found must not extend after that position.
    2776             : Optional third argument, if t, means if fail just return nil (no error).
    2777             :   If not nil and not t, move to limit of search and return nil."
    2778           0 :   (let* ((func (isearch-search-fun))
    2779           0 :          (pos1 (save-excursion (funcall func string bound noerror)))
    2780             :          pos2)
    2781           0 :     (when (and
    2782             :            ;; Avoid "obsolete" warnings for translation-table-for-input.
    2783           0 :            (with-no-warnings
    2784           0 :              (char-table-p translation-table-for-input))
    2785           0 :            (multibyte-string-p string)
    2786             :            ;; Minor optimization.
    2787           0 :            (string-match-p "[^[:ascii:]]" string))
    2788           0 :       (let ((translated
    2789           0 :              (apply 'string
    2790           0 :                     (mapcar (lambda (c)
    2791           0 :                               (or
    2792             :                                ;; Avoid "obsolete" warnings for
    2793             :                                ;; translation-table-for-input.
    2794           0 :                                (with-no-warnings
    2795           0 :                                  (aref translation-table-for-input c))
    2796           0 :                                c))
    2797           0 :                             string)))
    2798             :             match-data)
    2799           0 :         (when translated
    2800           0 :           (save-match-data
    2801           0 :             (save-excursion
    2802           0 :               (if (setq pos2 (funcall func translated bound noerror))
    2803           0 :                   (setq match-data (match-data t)))))
    2804           0 :           (when (and pos2
    2805           0 :                      (or (not pos1)
    2806           0 :                          (if isearch-forward (< pos2 pos1) (> pos2 pos1))))
    2807           0 :             (setq pos1 pos2)
    2808           0 :             (set-match-data match-data)))))
    2809           0 :     (when pos1
    2810             :       ;; When using multiple buffers isearch, switch to the new buffer here,
    2811             :       ;; because `save-excursion' above doesn't allow doing it inside funcall.
    2812           0 :       (if (and multi-isearch-next-buffer-current-function
    2813           0 :                (buffer-live-p multi-isearch-current-buffer))
    2814           0 :           (switch-to-buffer multi-isearch-current-buffer))
    2815           0 :       (goto-char pos1)
    2816           0 :       pos1)))
    2817             : 
    2818             : (defun isearch-search ()
    2819             :   ;; Do the search with the current search string.
    2820           0 :   (if (and (eq isearch-case-fold-search t) search-upper-case)
    2821           0 :       (setq isearch-case-fold-search
    2822           0 :             (isearch-no-upper-case-p isearch-string isearch-regexp)))
    2823           0 :   (condition-case lossage
    2824           0 :       (let ((inhibit-point-motion-hooks isearch-invisible)
    2825             :             (inhibit-quit nil)
    2826           0 :             (case-fold-search isearch-case-fold-search)
    2827           0 :             (search-invisible isearch-invisible)
    2828             :             (retry t))
    2829           0 :         (setq isearch-error nil)
    2830           0 :         (while retry
    2831           0 :           (setq isearch-success
    2832           0 :                 (isearch-search-string isearch-string nil t))
    2833             :           ;; Clear RETRY unless the search predicate says
    2834             :           ;; to skip this search hit.
    2835           0 :           (if (or (not isearch-success)
    2836           0 :                   (bobp) (eobp)
    2837           0 :                   (= (match-beginning 0) (match-end 0))
    2838           0 :                   (funcall isearch-filter-predicate
    2839           0 :                            (match-beginning 0) (match-end 0)))
    2840           0 :               (setq retry nil)))
    2841           0 :         (setq isearch-just-started nil)
    2842           0 :         (if isearch-success
    2843           0 :             (setq isearch-other-end
    2844           0 :                   (if isearch-forward (match-beginning 0) (match-end 0)))))
    2845             : 
    2846           0 :     (quit (isearch-unread ?\C-g)
    2847           0 :           (setq isearch-success nil))
    2848             : 
    2849             :     (invalid-regexp
    2850           0 :      (setq isearch-error (car (cdr lossage)))
    2851           0 :      (cond
    2852           0 :       ((string-match
    2853             :         "\\`Premature \\|\\`Unmatched \\|\\`Invalid "
    2854           0 :         isearch-error)
    2855           0 :        (setq isearch-error "incomplete input"))
    2856           0 :       ((and (not isearch-regexp)
    2857           0 :             (string-match "\\`Regular expression too big" isearch-error))
    2858           0 :        (cond
    2859           0 :         (isearch-regexp-function
    2860           0 :          (setq isearch-error "Too many words"))
    2861           0 :         ((and isearch-lax-whitespace search-whitespace-regexp)
    2862           0 :          (setq isearch-error "Too many spaces for whitespace matching"))))))
    2863             : 
    2864             :     (search-failed
    2865           0 :      (setq isearch-success nil)
    2866           0 :      (setq isearch-error (nth 2 lossage)))
    2867             : 
    2868             :     (error
    2869             :      ;; stack overflow in regexp search.
    2870           0 :      (setq isearch-error (format "%s" lossage))))
    2871             : 
    2872           0 :   (if isearch-success
    2873             :       nil
    2874             :     ;; Ding if failed this time after succeeding last time.
    2875           0 :     (and (isearch--state-success (car isearch-cmds))
    2876           0 :          (ding))
    2877           0 :     (if (functionp (isearch--state-pop-fun (car isearch-cmds)))
    2878           0 :         (funcall (isearch--state-pop-fun (car isearch-cmds))
    2879           0 :                  (car isearch-cmds)))
    2880           0 :     (goto-char (isearch--state-point (car isearch-cmds)))))
    2881             : 
    2882             : 
    2883             : ;; Called when opening an overlay, and we are still in isearch.
    2884             : (defun isearch-open-overlay-temporary (ov)
    2885           0 :   (if (not (null (overlay-get ov 'isearch-open-invisible-temporary)))
    2886             :       ;; Some modes would want to open the overlays temporary during
    2887             :       ;; isearch in their own way, they should set the
    2888             :       ;; `isearch-open-invisible-temporary' to a function doing this.
    2889           0 :       (funcall  (overlay-get ov 'isearch-open-invisible-temporary)  ov nil)
    2890             :     ;; Store the values for the `invisible' property, and then set it to nil.
    2891             :     ;; This way the text hidden by this overlay becomes visible.
    2892             : 
    2893             :     ;; In 19.34 this does not exist so I cannot test it.
    2894           0 :     (overlay-put ov 'isearch-invisible (overlay-get ov 'invisible))
    2895           0 :     (overlay-put ov 'invisible nil)))
    2896             : 
    2897             : 
    2898             : ;; This is called at the end of isearch.  It will open the overlays
    2899             : ;; that contain the latest match.  Obviously in case of a C-g the
    2900             : ;; point returns to the original location which surely is not contain
    2901             : ;; in any of these overlays, se we are safe in this case too.
    2902             : (defun isearch-open-necessary-overlays (ov)
    2903           0 :   (let ((inside-overlay (and  (> (point) (overlay-start ov))
    2904           0 :                               (<= (point) (overlay-end ov))))
    2905             :         ;; If this exists it means that the overlay was opened using
    2906             :         ;; this function, not by us tweaking the overlay properties.
    2907           0 :         (fct-temp (overlay-get ov 'isearch-open-invisible-temporary)))
    2908           0 :     (when (or inside-overlay (not fct-temp))
    2909             :       ;; restore the values for the `invisible' properties.
    2910           0 :       (overlay-put ov 'invisible (overlay-get ov 'isearch-invisible))
    2911           0 :       (overlay-put ov 'isearch-invisible nil))
    2912           0 :     (if inside-overlay
    2913           0 :         (funcall (overlay-get ov 'isearch-open-invisible)  ov)
    2914           0 :       (if fct-temp
    2915           0 :           (funcall fct-temp ov t)))))
    2916             : 
    2917             : ;; This is called when exiting isearch. It closes the temporary
    2918             : ;; opened overlays, except the ones that contain the latest match.
    2919             : (defun isearch-clean-overlays ()
    2920           0 :   (when isearch-opened-overlays
    2921           0 :     (mapc 'isearch-open-necessary-overlays isearch-opened-overlays)
    2922           0 :     (setq isearch-opened-overlays nil)))
    2923             : 
    2924             : 
    2925             : (defun isearch-intersects-p (start0 end0 start1 end1)
    2926             :   "Return t if regions START0..END0 and START1..END1 intersect."
    2927           0 :   (or (and (>= start0 start1) (<  start0 end1))
    2928           0 :       (and (>  end0 start1)   (<= end0 end1))
    2929           0 :       (and (>= start1 start0) (<  start1 end0))
    2930           0 :       (and (>  end1 start0)   (<= end1 end0))))
    2931             : 
    2932             : 
    2933             : ;; Verify if the current match is outside of each element of
    2934             : ;; `isearch-opened-overlays', if so close that overlay.
    2935             : 
    2936             : (defun isearch-close-unnecessary-overlays (begin end)
    2937           0 :   (let ((overlays isearch-opened-overlays))
    2938           0 :     (setq isearch-opened-overlays nil)
    2939           0 :     (dolist (ov overlays)
    2940           0 :       (if (isearch-intersects-p begin end (overlay-start ov) (overlay-end ov))
    2941           0 :           (push ov isearch-opened-overlays)
    2942           0 :         (let ((fct-temp (overlay-get ov 'isearch-open-invisible-temporary)))
    2943           0 :           (if fct-temp
    2944             :               ;; If this exists it means that the overlay was opened
    2945             :               ;; using this function, not by us tweaking the overlay
    2946             :               ;; properties.
    2947           0 :               (funcall fct-temp ov t)
    2948           0 :             (overlay-put ov 'invisible (overlay-get ov 'isearch-invisible))
    2949           0 :             (overlay-put ov 'isearch-invisible nil)))))))
    2950             : 
    2951             : 
    2952             : (defun isearch-range-invisible (beg end)
    2953             :   "Return t if all the text from BEG to END is invisible."
    2954           0 :   (when (/= beg end)
    2955             :     ;; Check that invisibility runs up to END.
    2956           0 :     (save-excursion
    2957           0 :       (goto-char beg)
    2958           0 :       (let (;; can-be-opened keeps track if we can open some overlays.
    2959           0 :             (can-be-opened (eq search-invisible 'open))
    2960             :             ;; the list of overlays that could be opened
    2961             :             (crt-overlays nil))
    2962           0 :         (when (and can-be-opened isearch-hide-immediately)
    2963           0 :           (isearch-close-unnecessary-overlays beg end))
    2964             :         ;; If the following character is currently invisible,
    2965             :         ;; skip all characters with that same `invisible' property value.
    2966             :         ;; Do that over and over.
    2967           0 :         (while (and (< (point) end) (invisible-p (point)))
    2968           0 :           (if (invisible-p (get-text-property (point) 'invisible))
    2969           0 :               (progn
    2970           0 :                 (goto-char (next-single-property-change (point) 'invisible
    2971           0 :                                                         nil end))
    2972             :                 ;; if text is hidden by an `invisible' text property
    2973             :                 ;; we cannot open it at all.
    2974           0 :                 (setq can-be-opened nil))
    2975           0 :             (when can-be-opened
    2976           0 :               (let ((overlays (overlays-at (point)))
    2977             :                     ov-list
    2978             :                     o
    2979             :                     invis-prop)
    2980           0 :                 (while overlays
    2981           0 :                   (setq o (car overlays)
    2982           0 :                         invis-prop (overlay-get o 'invisible))
    2983           0 :                   (if (invisible-p invis-prop)
    2984           0 :                       (if (overlay-get o 'isearch-open-invisible)
    2985           0 :                           (setq ov-list (cons o ov-list))
    2986             :                         ;; We found one overlay that cannot be
    2987             :                         ;; opened, that means the whole chunk
    2988             :                         ;; cannot be opened.
    2989           0 :                         (setq can-be-opened nil)))
    2990           0 :                   (setq overlays (cdr overlays)))
    2991           0 :                 (if can-be-opened
    2992             :                     ;; It makes sense to append to the open
    2993             :                     ;; overlays list only if we know that this is
    2994             :                     ;; t.
    2995           0 :                     (setq crt-overlays (append ov-list crt-overlays)))))
    2996           0 :             (goto-char (next-overlay-change (point)))))
    2997             :         ;; See if invisibility reaches up thru END.
    2998           0 :         (if (>= (point) end)
    2999           0 :             (if (and can-be-opened (consp crt-overlays))
    3000           0 :                 (progn
    3001           0 :                   (setq isearch-opened-overlays
    3002           0 :                         (append isearch-opened-overlays crt-overlays))
    3003           0 :                   (mapc 'isearch-open-overlay-temporary crt-overlays)
    3004           0 :                   nil)
    3005           0 :               (setq isearch-hidden t)))))))
    3006             : 
    3007             : (defun isearch-filter-visible (beg end)
    3008             :   "Test whether the current search hit is visible at least partially.
    3009             : Return non-nil if the text from BEG to END is visible to Isearch as
    3010             : determined by `isearch-range-invisible' unless invisible text can be
    3011             : searched too when `search-invisible' is t."
    3012           0 :   (or (eq search-invisible t)
    3013           0 :       (not (isearch-range-invisible beg end))))
    3014             : 
    3015             : 
    3016             : ;; General utilities
    3017             : 
    3018             : (defun isearch-no-upper-case-p (string regexp-flag)
    3019             :   "Return t if there are no upper case chars in STRING.
    3020             : If REGEXP-FLAG is non-nil, disregard letters preceded by `\\' (but not `\\\\')
    3021             : since they have special meaning in a regexp."
    3022           0 :   (let (quote-flag (i 0) (len (length string)) found)
    3023           0 :     (while (and (not found) (< i len))
    3024           0 :       (let ((char (aref string i)))
    3025           0 :         (if (and regexp-flag (eq char ?\\))
    3026           0 :             (setq quote-flag (not quote-flag))
    3027           0 :           (if (and (not quote-flag) (not (eq char (downcase char))))
    3028           0 :               (setq found t))
    3029           0 :           (setq quote-flag nil)))
    3030           0 :       (setq i (1+ i)))
    3031           0 :     (not (or found
    3032             :              ;; Even if there's no uppercase char, we want to detect the use
    3033             :              ;; of [:upper:] or [:lower:] char-class, which indicates
    3034             :              ;; clearly that the user cares about case distinction.
    3035           0 :              (and regexp-flag (string-match "\\[:\\(upp\\|low\\)er:]" string)
    3036           0 :                   (condition-case err
    3037           0 :                       (progn
    3038           0 :                         (string-match (substring string 0 (match-beginning 0))
    3039           0 :                                       "")
    3040           0 :                         nil)
    3041             :                     (invalid-regexp
    3042           0 :                      (equal "Unmatched [ or [^" (cadr err)))))))))
    3043             : 
    3044             : ;; Portability functions to support various Emacs versions.
    3045             : 
    3046             : (defun isearch-text-char-description (c)
    3047           0 :   (cond
    3048           0 :    ((< c ?\s) (propertize
    3049           0 :                (char-to-string c)
    3050           0 :                'display (propertize (format "^%c" (+ c 64)) 'face 'escape-glyph)))
    3051           0 :    ((= c ?\^?) (propertize
    3052           0 :                 (char-to-string c)
    3053           0 :                 'display (propertize "^?" 'face 'escape-glyph)))
    3054           0 :    (t (char-to-string c))))
    3055             : 
    3056             : ;; General function to unread characters or events.
    3057             : ;; Also insert them in a keyboard macro being defined.
    3058             : (defun isearch-unread (&rest char-or-events)
    3059           0 :   (mapc 'store-kbd-macro-event char-or-events)
    3060           0 :   (setq unread-command-events
    3061           0 :         (append char-or-events unread-command-events)))
    3062             : 
    3063             : 
    3064             : ;; Highlighting
    3065             : 
    3066             : (defvar isearch-overlay nil)
    3067             : 
    3068             : (defun isearch-highlight (beg end)
    3069           0 :   (if search-highlight
    3070           0 :       (if isearch-overlay
    3071             :           ;; Overlay already exists, just move it.
    3072           0 :           (move-overlay isearch-overlay beg end (current-buffer))
    3073             :         ;; Overlay doesn't exist, create it.
    3074           0 :         (setq isearch-overlay (make-overlay beg end))
    3075             :         ;; 1001 is higher than lazy's 1000 and ediff's 100+
    3076           0 :         (overlay-put isearch-overlay 'priority 1001)
    3077           0 :         (overlay-put isearch-overlay 'face isearch-face))))
    3078             : 
    3079             : (defun isearch-dehighlight ()
    3080           0 :   (when isearch-overlay
    3081           0 :     (delete-overlay isearch-overlay)))
    3082             : 
    3083             : ;; isearch-lazy-highlight feature
    3084             : ;; by Bob Glickstein <http://www.zanshin.com/~bobg/>
    3085             : 
    3086             : ;; When active, *every* match for the current search string is
    3087             : ;; highlighted: the current one using the normal isearch match color
    3088             : ;; and all the others using `isearch-lazy-highlight'.  The extra
    3089             : ;; highlighting makes it easier to anticipate where the cursor will
    3090             : ;; land each time you press C-s or C-r to repeat a pending search.
    3091             : ;; Highlighting of these additional matches happens in a deferred
    3092             : ;; fashion using "idle timers," so the cycles needed do not rob
    3093             : ;; isearch of its usual snappy response.
    3094             : 
    3095             : ;; IMPLEMENTATION NOTE: This depends on some isearch internals.
    3096             : ;; Specifically:
    3097             : ;;  - `isearch-update' is expected to be called (at least) every time
    3098             : ;;    the search string or window-start changes;
    3099             : ;;  - `isearch-string' is expected to contain the current search
    3100             : ;;    string as entered by the user;
    3101             : ;;  - the type of the current search is expected to be given by
    3102             : ;;    `isearch-regexp-function' and `isearch-regexp';
    3103             : ;;  - the direction of the current search is expected to be given by
    3104             : ;;    `isearch-forward';
    3105             : ;;  - the variable `isearch-error' is expected to be true
    3106             : ;;    only if `isearch-string' is an invalid regexp.
    3107             : 
    3108             : (defvar isearch-lazy-highlight-overlays nil)
    3109             : (defvar isearch-lazy-highlight-wrapped nil)
    3110             : (defvar isearch-lazy-highlight-start-limit nil)
    3111             : (defvar isearch-lazy-highlight-end-limit nil)
    3112             : (defvar isearch-lazy-highlight-start nil)
    3113             : (defvar isearch-lazy-highlight-end nil)
    3114             : (defvar isearch-lazy-highlight-timer nil)
    3115             : (defvar isearch-lazy-highlight-last-string nil)
    3116             : (defvar isearch-lazy-highlight-window nil)
    3117             : (defvar isearch-lazy-highlight-window-group nil)
    3118             : (defvar isearch-lazy-highlight-window-start nil)
    3119             : (defvar isearch-lazy-highlight-window-end nil)
    3120             : (defvar isearch-lazy-highlight-case-fold-search nil)
    3121             : (defvar isearch-lazy-highlight-regexp nil)
    3122             : (defvar isearch-lazy-highlight-lax-whitespace nil)
    3123             : (defvar isearch-lazy-highlight-regexp-lax-whitespace nil)
    3124             : (defvar isearch-lazy-highlight-regexp-function nil)
    3125             : (define-obsolete-variable-alias 'isearch-lazy-highlight-word
    3126             :   'isearch-lazy-highlight-regexp-function "25.1")
    3127             : (defvar isearch-lazy-highlight-forward nil)
    3128             : (defvar isearch-lazy-highlight-error nil)
    3129             : 
    3130             : (defun lazy-highlight-cleanup (&optional force procrastinate)
    3131             :   "Stop lazy highlighting and remove extra highlighting from current buffer.
    3132             : FORCE non-nil means do it whether or not `lazy-highlight-cleanup' is nil.
    3133             : PROCRASTINATE non-nil means postpone cleanup to a later time.
    3134             : This function is called when exiting an incremental search if
    3135             : `lazy-highlight-cleanup' is non-nil."
    3136             :   (interactive '(t))
    3137           0 :   (when (and (or force lazy-highlight-cleanup) (not procrastinate))
    3138           0 :     (while isearch-lazy-highlight-overlays
    3139           0 :       (delete-overlay (car isearch-lazy-highlight-overlays))
    3140           0 :       (setq isearch-lazy-highlight-overlays
    3141           0 :             (cdr isearch-lazy-highlight-overlays))))
    3142           0 :   (when isearch-lazy-highlight-timer
    3143           0 :     (cancel-timer isearch-lazy-highlight-timer)
    3144           0 :     (setq isearch-lazy-highlight-timer nil)))
    3145             : 
    3146             : (define-obsolete-function-alias 'isearch-lazy-highlight-cleanup
    3147             :                                 'lazy-highlight-cleanup
    3148             :                                 "22.1")
    3149             : 
    3150             : (defun isearch-lazy-highlight-new-loop (&optional beg end)
    3151             :   "Cleanup any previous `lazy-highlight' loop and begin a new one.
    3152             : BEG and END specify the bounds within which highlighting should occur.
    3153             : This is called when `isearch-update' is invoked (which can cause the
    3154             : search string to change or the window to scroll).  It is also used
    3155             : by other Emacs features."
    3156           0 :   (when (and (null executing-kbd-macro)
    3157           0 :              (sit-for 0)         ;make sure (window-start) is credible
    3158           0 :              (or (not (equal isearch-string
    3159           0 :                              isearch-lazy-highlight-last-string))
    3160           0 :                  (not (memq (selected-window)
    3161           0 :                             isearch-lazy-highlight-window-group))
    3162           0 :                  (not (eq isearch-lazy-highlight-case-fold-search
    3163           0 :                           isearch-case-fold-search))
    3164           0 :                  (not (eq isearch-lazy-highlight-regexp
    3165           0 :                           isearch-regexp))
    3166           0 :                  (not (eq isearch-lazy-highlight-regexp-function
    3167           0 :                           isearch-regexp-function))
    3168           0 :                  (not (eq isearch-lazy-highlight-lax-whitespace
    3169           0 :                           isearch-lax-whitespace))
    3170           0 :                  (not (eq isearch-lazy-highlight-regexp-lax-whitespace
    3171           0 :                           isearch-regexp-lax-whitespace))
    3172           0 :                  (not (= (window-group-start)
    3173           0 :                          isearch-lazy-highlight-window-start))
    3174           0 :                  (not (= (window-group-end) ; Window may have been split/joined.
    3175           0 :                          isearch-lazy-highlight-window-end))
    3176           0 :                  (not (eq isearch-forward
    3177           0 :                           isearch-lazy-highlight-forward))
    3178             :                  ;; In case we are recovering from an error.
    3179           0 :                  (not (equal isearch-error
    3180           0 :                              isearch-lazy-highlight-error))))
    3181             :     ;; something important did indeed change
    3182           0 :     (lazy-highlight-cleanup t (not (equal isearch-string ""))) ;stop old timer
    3183           0 :     (setq isearch-lazy-highlight-error isearch-error)
    3184             :     ;; It used to check for `(not isearch-error)' here, but actually
    3185             :     ;; lazy-highlighting might find matches to highlight even when
    3186             :     ;; `isearch-error' is non-nil.  (Bug#9918)
    3187           0 :     (setq isearch-lazy-highlight-start-limit beg
    3188           0 :           isearch-lazy-highlight-end-limit end)
    3189           0 :     (setq isearch-lazy-highlight-window       (selected-window)
    3190           0 :           isearch-lazy-highlight-window-group (selected-window-group)
    3191           0 :           isearch-lazy-highlight-window-start (window-group-start)
    3192           0 :           isearch-lazy-highlight-window-end   (window-group-end)
    3193             :           ;; Start lazy-highlighting at the beginning of the found
    3194             :           ;; match (`isearch-other-end').  If no match, use point.
    3195             :           ;; One of the next two variables (depending on search direction)
    3196             :           ;; is used to define the starting position of lazy-highlighting
    3197             :           ;; and also to remember the current position of point between
    3198             :           ;; calls of `isearch-lazy-highlight-update', and another variable
    3199             :           ;; is used to define where the wrapped search must stop.
    3200           0 :           isearch-lazy-highlight-start        (or isearch-other-end (point))
    3201           0 :           isearch-lazy-highlight-end          (or isearch-other-end (point))
    3202             :           isearch-lazy-highlight-wrapped      nil
    3203           0 :           isearch-lazy-highlight-last-string  isearch-string
    3204           0 :           isearch-lazy-highlight-case-fold-search isearch-case-fold-search
    3205           0 :           isearch-lazy-highlight-regexp       isearch-regexp
    3206           0 :           isearch-lazy-highlight-lax-whitespace   isearch-lax-whitespace
    3207           0 :           isearch-lazy-highlight-regexp-lax-whitespace isearch-regexp-lax-whitespace
    3208           0 :           isearch-lazy-highlight-regexp-function  isearch-regexp-function
    3209           0 :           isearch-lazy-highlight-forward      isearch-forward)
    3210           0 :     (unless (equal isearch-string "")
    3211           0 :       (setq isearch-lazy-highlight-timer
    3212           0 :             (run-with-idle-timer lazy-highlight-initial-delay nil
    3213           0 :                                  'isearch-lazy-highlight-start)))))
    3214             : 
    3215             : (defun isearch-lazy-highlight-search ()
    3216             :   "Search ahead for the next or previous match, for lazy highlighting.
    3217             : Attempt to do the search exactly the way the pending Isearch would."
    3218           0 :   (condition-case nil
    3219           0 :       (let ((case-fold-search isearch-lazy-highlight-case-fold-search)
    3220           0 :             (isearch-regexp isearch-lazy-highlight-regexp)
    3221           0 :             (isearch-regexp-function isearch-lazy-highlight-regexp-function)
    3222             :             (isearch-lax-whitespace
    3223           0 :              isearch-lazy-highlight-lax-whitespace)
    3224             :             (isearch-regexp-lax-whitespace
    3225           0 :              isearch-lazy-highlight-regexp-lax-whitespace)
    3226           0 :             (isearch-forward isearch-lazy-highlight-forward)
    3227             :             (search-invisible nil)      ; don't match invisible text
    3228             :             (retry t)
    3229             :             (success nil)
    3230           0 :             (bound (if isearch-lazy-highlight-forward
    3231           0 :                        (min (or isearch-lazy-highlight-end-limit (point-max))
    3232           0 :                             (if isearch-lazy-highlight-wrapped
    3233           0 :                                 (+ isearch-lazy-highlight-start
    3234             :                                    ;; Extend bound to match whole string at point
    3235           0 :                                    (1- (length isearch-lazy-highlight-last-string)))
    3236           0 :                               (window-group-end)))
    3237           0 :                      (max (or isearch-lazy-highlight-start-limit (point-min))
    3238           0 :                           (if isearch-lazy-highlight-wrapped
    3239           0 :                               (- isearch-lazy-highlight-end
    3240             :                                  ;; Extend bound to match whole string at point
    3241           0 :                                  (1- (length isearch-lazy-highlight-last-string)))
    3242           0 :                             (window-group-start))))))
    3243             :         ;; Use a loop like in `isearch-search'.
    3244           0 :         (while retry
    3245           0 :           (setq success (isearch-search-string
    3246           0 :                          isearch-lazy-highlight-last-string bound t))
    3247             :           ;; Clear RETRY unless the search predicate says
    3248             :           ;; to skip this search hit.
    3249           0 :           (if (or (not success)
    3250           0 :                   (= (point) bound) ; like (bobp) (eobp) in `isearch-search'.
    3251           0 :                   (= (match-beginning 0) (match-end 0))
    3252           0 :                   (funcall isearch-filter-predicate
    3253           0 :                            (match-beginning 0) (match-end 0)))
    3254           0 :               (setq retry nil)))
    3255           0 :         success)
    3256           0 :     (error nil)))
    3257             : 
    3258             : (defun isearch-lazy-highlight-start ()
    3259             :   "Start a new lazy-highlight updating loop."
    3260           0 :   (lazy-highlight-cleanup t) ;remove old overlays
    3261           0 :   (isearch-lazy-highlight-update))
    3262             : 
    3263             : (defun isearch-lazy-highlight-update ()
    3264             :   "Update highlighting of other matches for current search."
    3265           0 :   (let ((max lazy-highlight-max-at-a-time)
    3266             :         (looping t)
    3267             :         nomore)
    3268           0 :     (with-local-quit
    3269           0 :       (save-selected-window
    3270           0 :         (if (and (window-live-p isearch-lazy-highlight-window)
    3271           0 :                  (not (memq (selected-window) isearch-lazy-highlight-window-group)))
    3272           0 :             (select-window isearch-lazy-highlight-window))
    3273           0 :         (save-excursion
    3274           0 :           (save-match-data
    3275           0 :             (goto-char (if isearch-lazy-highlight-forward
    3276           0 :                            isearch-lazy-highlight-end
    3277           0 :                          isearch-lazy-highlight-start))
    3278           0 :             (while looping
    3279           0 :               (let ((found (isearch-lazy-highlight-search)))
    3280           0 :                 (when max
    3281           0 :                   (setq max (1- max))
    3282           0 :                   (if (<= max 0)
    3283           0 :                       (setq looping nil)))
    3284           0 :                 (if found
    3285           0 :                     (let ((mb (match-beginning 0))
    3286           0 :                           (me (match-end 0)))
    3287           0 :                       (if (= mb me)     ;zero-length match
    3288           0 :                           (if isearch-lazy-highlight-forward
    3289           0 :                               (if (= mb (if isearch-lazy-highlight-wrapped
    3290           0 :                                             isearch-lazy-highlight-start
    3291           0 :                                           (window-group-end)))
    3292           0 :                                   (setq found nil)
    3293           0 :                                 (forward-char 1))
    3294           0 :                             (if (= mb (if isearch-lazy-highlight-wrapped
    3295           0 :                                           isearch-lazy-highlight-end
    3296           0 :                                         (window-group-start)))
    3297           0 :                                 (setq found nil)
    3298           0 :                               (forward-char -1)))
    3299             : 
    3300             :                         ;; non-zero-length match
    3301           0 :                         (let ((ov (make-overlay mb me)))
    3302           0 :                           (push ov isearch-lazy-highlight-overlays)
    3303             :                           ;; 1000 is higher than ediff's 100+,
    3304             :                           ;; but lower than isearch main overlay's 1001
    3305           0 :                           (overlay-put ov 'priority 1000)
    3306           0 :                           (overlay-put ov 'face 'lazy-highlight)
    3307           0 :                           (unless (eq isearch-lazy-highlight 'all-windows)
    3308           0 :                             (overlay-put ov 'window (selected-window)))))
    3309             :                       ;; Remember the current position of point for
    3310             :                       ;; the next call of `isearch-lazy-highlight-update'
    3311             :                       ;; when `lazy-highlight-max-at-a-time' is too small.
    3312           0 :                       (if isearch-lazy-highlight-forward
    3313           0 :                           (setq isearch-lazy-highlight-end (point))
    3314           0 :                         (setq isearch-lazy-highlight-start (point)))))
    3315             : 
    3316             :                 ;; not found or zero-length match at the search bound
    3317           0 :                 (if (not found)
    3318           0 :                     (if isearch-lazy-highlight-wrapped
    3319           0 :                         (setq looping nil
    3320           0 :                               nomore  t)
    3321           0 :                       (setq isearch-lazy-highlight-wrapped t)
    3322           0 :                       (if isearch-lazy-highlight-forward
    3323           0 :                           (progn
    3324           0 :                             (setq isearch-lazy-highlight-end (window-group-start))
    3325           0 :                             (goto-char (max (or isearch-lazy-highlight-start-limit (point-min))
    3326           0 :                                             (window-group-start))))
    3327           0 :                         (setq isearch-lazy-highlight-start (window-group-end))
    3328           0 :                         (goto-char (min (or isearch-lazy-highlight-end-limit (point-max))
    3329           0 :                                         (window-group-end))))))))
    3330           0 :             (unless nomore
    3331           0 :               (setq isearch-lazy-highlight-timer
    3332           0 :                     (run-at-time lazy-highlight-interval nil
    3333           0 :                                  'isearch-lazy-highlight-update)))))))))
    3334             : 
    3335             : (defun isearch-resume (string regexp word forward message case-fold)
    3336             :   "Resume an incremental search.
    3337             : STRING is the string or regexp searched for.
    3338             : REGEXP non-nil means the resumed search was a regexp search.
    3339             : WORD non-nil means resume a word search.
    3340             : FORWARD non-nil means resume a forward search.
    3341             : MESSAGE is the echo-area message recorded for the search resumed.
    3342             : CASE-FOLD non-nil means the search was case-insensitive."
    3343           0 :   (isearch-mode forward regexp nil nil word)
    3344           0 :   (setq isearch-string string
    3345           0 :         isearch-message message
    3346           0 :         isearch-case-fold-search case-fold)
    3347           0 :   (isearch-search)
    3348           0 :   (isearch-update))
    3349             : 
    3350             : (provide 'isearch)
    3351             : 
    3352             : ;;; isearch.el ends here

Generated by: LCOV version 1.12