isearch.el 96.9 KB
Newer Older
1
;;; isearch.el --- incremental search minor mode
2

3
;; Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000,
Glenn Morris's avatar
Glenn Morris committed
4
;;   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
Eric S. Raymond's avatar
Eric S. Raymond committed
5

6
;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
7
;; Maintainer: FSF
Dave Love's avatar
Dave Love committed
8
;; Keywords: matching
Jim Blandy's avatar
Jim Blandy committed
9

David J. MacKenzie's avatar
David J. MacKenzie committed
10
;; This file is part of GNU Emacs.
Jim Blandy's avatar
Jim Blandy committed
11

12 13
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
14
;; the Free Software Foundation; either version 3, or (at your option)
15 16
;; any later version.

Jim Blandy's avatar
Jim Blandy committed
17
;; GNU Emacs is distributed in the hope that it will be useful,
18 19 20 21 22
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
Erik Naggum's avatar
Erik Naggum committed
23
;; along with GNU Emacs; see the file COPYING.  If not, write to the
Lute Kamstra's avatar
Lute Kamstra committed
24 25
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
Jim Blandy's avatar
Jim Blandy committed
26

27 28
;;; Commentary:

Jim Blandy's avatar
Jim Blandy committed
29 30
;; Instructions

31 32
;; For programmed use of isearch-mode, e.g. calling (isearch-forward),
;; isearch-mode behaves modally and does not return until the search
Dave Love's avatar
Dave Love committed
33
;; is completed.  It uses a recursive-edit to behave this way.
34

Jim Blandy's avatar
Jim Blandy committed
35
;; The key bindings active within isearch-mode are defined below in
36 37 38 39 40 41 42
;; `isearch-mode-map' which is given bindings close to the default
;; characters of the original isearch.el.  With `isearch-mode',
;; however, you can bind multi-character keys and it should be easier
;; to add new commands.  One bug though: keys with meta-prefix cannot
;; be longer than two chars.  Also see minibuffer-local-isearch-map
;; for bindings active during `isearch-edit-string'.

Dave Love's avatar
Dave Love committed
43 44 45
;; isearch-mode should work even if you switch windows with the mouse,
;; in which case isearch-mode is terminated automatically before the
;; switch.
46 47 48 49 50 51 52 53 54 55 56 57 58 59

;; The search ring and completion commands automatically put you in
;; the minibuffer to edit the string.  This gives you a chance to
;; modify the search string before executing the search.  There are
;; three commands to terminate the editing: C-s and C-r exit the
;; minibuffer and search forward and reverse respectively, while C-m
;; exits and does a nonincremental search.

;; Exiting immediately from isearch uses isearch-edit-string instead
;; of nonincremental-search, if search-nonincremental-instead is non-nil.
;; The name of this option should probably be changed if we decide to
;; keep the behavior.  No point in forcing nonincremental search until
;; the last possible moment.

60
;;; Code:
61 62


63
;; Some additional options and constants.
64

65 66
(defgroup isearch nil
  "Incremental search minor mode."
Dave Love's avatar
Dave Love committed
67 68
  :link '(emacs-commentary-link "isearch")
  :link '(custom-manual "(emacs)Incremental Search")
69 70 71
  :prefix "isearch-"
  :prefix "search-"
  :group 'matching)
72

73 74 75 76 77 78 79

(defcustom search-exit-option t
  "*Non-nil means random control characters terminate incremental search."
  :type 'boolean
  :group 'isearch)

(defcustom search-slow-window-lines 1
80 81 82
  "*Number of lines in slow search display windows.
These are the short windows used during incremental search on slow terminals.
Negative means put the slow search window at the top (normally it's at bottom)
83 84 85
and the value is minus the number of lines."
  :type 'integer
  :group 'isearch)
86

87
(defcustom search-slow-speed 1200
88 89
  "*Highest terminal speed at which to use \"slow\" style incremental search.
This is the style where a one-line window is created to show the line
90 91 92
that the search has reached."
  :type 'integer
  :group 'isearch)
Jim Blandy's avatar
Jim Blandy committed
93

94
(defcustom search-upper-case 'not-yanks
Jim Blandy's avatar
Jim Blandy committed
95
  "*If non-nil, upper case chars disable case fold searching.
96 97
That is, upper and lower case chars must match exactly.
This applies no matter where the chars come from, but does not
98
apply to chars in regexps that are prefixed with `\\'.
Juri Linkov's avatar
Juri Linkov committed
99 100
If this value is `not-yanks', text yanked into the search string
in Isearch mode is always downcased."
101 102
  :type '(choice (const :tag "off" nil)
		 (const not-yanks)
103
		 (other :tag "on" t))
104
  :group 'isearch)
Jim Blandy's avatar
Jim Blandy committed
105

106
(defcustom search-nonincremental-instead t
Jim Blandy's avatar
Jim Blandy committed
107
  "*If non-nil, do a nonincremental search instead if exiting immediately.
108
Actually, `isearch-edit-string' is called to let you enter the search
109 110 111
string, and RET terminates editing and does a nonincremental search."
  :type 'boolean
  :group 'isearch)
Jim Blandy's avatar
Jim Blandy committed
112

113
(defcustom search-whitespace-regexp "\\s-+"
Jim Blandy's avatar
Jim Blandy committed
114
  "*If non-nil, regular expression to match a sequence of whitespace chars.
115
This applies to regular expression incremental search.
116 117 118 119
When you put a space or spaces in the incremental regexp, it stands for
this, unless it is inside of a regexp construct such as [...] or *, + or ?.
You might want to use something like \"[ \\t\\r\\n]+\" instead.
In the Customization buffer, that is `[' followed by a space,
120 121 122 123 124
a tab, a carriage return (control-M), a newline, and `]+'.

When this is nil, each space you type matches literally, against one space."
  :type '(choice (const :tag "Find Spaces Literally" nil)
		 regexp)
125
  :group 'isearch)
Jim Blandy's avatar
Jim Blandy committed
126

127 128
(defcustom search-invisible 'open
  "If t incremental search can match hidden text.
129 130
A nil value means don't match invisible text.
When the value is `open', if the text matched is made invisible by
131 132
an overlay having an `invisible' property and that overlay has a property
`isearch-open-invisible', then incremental search will show the contents.
Stefan Monnier's avatar
Stefan Monnier committed
133 134 135
\(This applies when using `outline.el' and `hideshow.el'.)
See also `reveal-mode' if you want overlays to automatically be opened
whenever point is in one of them."
136 137
  :type '(choice (const :tag "Match hidden text" t)
		 (const :tag "Open overlays" open)
138
		 (const :tag "Don't match hidden text" nil))
139 140 141
  :group 'isearch)

(defcustom isearch-hide-immediately t
142 143 144 145
  "If non-nil, re-hide an invisible match right away.
This variable makes a difference when `search-invisible' is set to `open'.
It means that after search makes some invisible text visible
to show the match, it makes the text invisible again when the match moves.
146 147
Ordinarily the text becomes invisible again at the end of the search."
  :type 'boolean
148
  :group 'isearch)
149

150 151 152 153
(defcustom isearch-resume-in-command-history nil
  "*If non-nil, `isearch-resume' commands are added to the command history.
This allows you to resume earlier isearch sessions through the
command history."
154 155 156
  :type 'boolean
  :group 'isearch)

157 158 159 160
(defvar isearch-mode-hook nil
  "Function(s) to call after starting up an incremental search.")

(defvar isearch-mode-end-hook nil
161 162
  "Function(s) to call after terminating an incremental search.
When these functions are called, `isearch-mode-end-hook-quit'
163
is non-nil if the user quits the search.")
164 165

(defvar isearch-mode-end-hook-quit nil
166
  "Non-nil while running `isearch-mode-end-hook' if the user quits the search.")
167

168 169 170 171
(defvar isearch-message-function nil
  "Function to call to display the search prompt.
If nil, use `isearch-message'.")

172 173 174 175 176 177 178 179 180
(defvar isearch-wrap-function nil
  "Function to call to wrap the search when search is failed.
If nil, move point to the beginning of the buffer for a forward search,
or to the end of the buffer for a backward search.")

(defvar isearch-push-state-function nil
  "Function to save a function restoring the mode-specific isearch state
to the search status stack.")

181
;; Search ring.
Jim Blandy's avatar
Jim Blandy committed
182 183 184

(defvar search-ring nil
  "List of search string sequences.")
185
(defvar regexp-search-ring nil
Jim Blandy's avatar
Jim Blandy committed
186 187
  "List of regular expression search string sequences.")

188 189 190 191 192 193 194 195
(defcustom search-ring-max 16
  "*Maximum length of search ring before oldest elements are thrown away."
  :type 'integer
  :group 'isearch)
(defcustom regexp-search-ring-max 16
  "*Maximum length of regexp search ring before oldest elements are thrown away."
  :type 'integer
  :group 'isearch)
Jim Blandy's avatar
Jim Blandy committed
196 197

(defvar search-ring-yank-pointer nil
198
  "Index in `search-ring' of last string reused.
199
It is nil if none yet.")
200
(defvar regexp-search-ring-yank-pointer nil
201
  "Index in `regexp-search-ring' of last string reused.
202
It is nil if none yet.")
Jim Blandy's avatar
Jim Blandy committed
203

204
(defcustom search-ring-update nil
205
  "*Non-nil if advancing or retreating in the search ring should cause search.
206 207 208
Default value, nil, means edit the string instead."
  :type 'boolean
  :group 'isearch)
209

210 211 212 213 214 215 216 217 218 219 220
;;; isearch highlight customization.

(defcustom search-highlight t
  "*Non-nil means incremental search highlights the current match."
  :type 'boolean
  :group 'isearch)

(defface isearch
  '((((class color) (min-colors 88) (background light))
     ;; The background must not be too dark, for that means
     ;; the character is hard to see when the cursor is there.
221
     (:background "magenta3" :foreground "lightskyblue1"))
222 223 224 225 226 227 228 229
    (((class color) (min-colors 88) (background dark))
     (:background "palevioletred2" :foreground "brown4"))
    (((class color) (min-colors 16))
     (:background "magenta4" :foreground "cyan1"))
    (((class color) (min-colors 8))
     (:background "magenta4" :foreground "cyan1"))
    (t (:inverse-video t)))
  "Face for highlighting Isearch matches."
230 231
  :group 'isearch
  :group 'basic-faces)
232 233
(defvar isearch 'isearch)

234 235 236 237 238 239 240 241 242 243 244 245
(defface isearch-fail
  '((((class color) (min-colors 88) (background light))
     (:background "RosyBrown1"))
    (((class color) (min-colors 88) (background dark))
     (:background "red4"))
    (((class color) (min-colors 16))
     (:background "red"))
    (((class color) (min-colors 8))
     (:background "red"))
    (((class color grayscale))
     :foreground "grey")
    (t (:inverse-video t)))
Bastien Guerry's avatar
Bastien Guerry committed
246
  "Face for highlighting failed part in Isearch echo-area message."
247
  :version "23.1"
Bastien Guerry's avatar
Bastien Guerry committed
248 249
  :group 'isearch)

250 251 252 253 254 255 256 257 258
(defcustom isearch-lazy-highlight t
  "*Controls the lazy-highlighting during incremental search.
When non-nil, all text in the buffer matching the current search
string is highlighted lazily (see `lazy-highlight-initial-delay'
and `lazy-highlight-interval')."
  :type 'boolean
  :group 'lazy-highlight
  :group 'isearch)

259
;;; Lazy highlight customization.
260

261 262 263 264 265
(defgroup lazy-highlight nil
  "Lazy highlighting feature for matching strings."
  :prefix "lazy-highlight-"
  :version "21.1"
  :group 'isearch
266
  :group 'matching)
267 268 269 270

(defcustom lazy-highlight-cleanup t
  "*Controls whether to remove extra highlighting after a search.
If this is nil, extra highlighting can be \"manually\" removed with
271
\\[lazy-highlight-cleanup]."
272 273
  :type 'boolean
  :group 'lazy-highlight)
274 275 276
(define-obsolete-variable-alias 'isearch-lazy-highlight-cleanup
                                'lazy-highlight-cleanup
                                "22.1")
277 278 279 280 281

(defcustom lazy-highlight-initial-delay 0.25
  "*Seconds to wait before beginning to lazily highlight all matches."
  :type 'number
  :group 'lazy-highlight)
282 283 284
(define-obsolete-variable-alias 'isearch-lazy-highlight-initial-delay
                                'lazy-highlight-initial-delay
                                "22.1")
285 286 287 288 289

(defcustom lazy-highlight-interval 0 ; 0.0625
  "*Seconds between lazily highlighting successive matches."
  :type 'number
  :group 'lazy-highlight)
290 291 292
(define-obsolete-variable-alias 'isearch-lazy-highlight-interval
                                'lazy-highlight-interval
                                "22.1")
293 294 295 296 297 298 299 300 301

(defcustom lazy-highlight-max-at-a-time 20
  "*Maximum matches to highlight at a time (for `lazy-highlight').
Larger values may reduce isearch's responsiveness to user input;
smaller values make matches highlight slowly.
A value of nil means highlight all matches."
  :type '(choice (const :tag "All" nil)
		 (integer :tag "Some"))
  :group 'lazy-highlight)
302 303 304
(define-obsolete-variable-alias 'isearch-lazy-highlight-max-at-a-time
                                'lazy-highlight-max-at-a-time
                                "22.1")
305

306
(defface lazy-highlight
307 308 309 310 311 312 313 314 315 316
  '((((class color) (min-colors 88) (background light))
     (:background "paleturquoise"))
    (((class color) (min-colors 88) (background dark))
     (:background "paleturquoise4"))
    (((class color) (min-colors 16))
     (:background "turquoise3"))
    (((class color) (min-colors 8))
     (:background "turquoise3"))
    (t (:underline t)))
  "Face for lazy highlighting of matches other than the current one."
317 318
  :group 'lazy-highlight
  :group 'basic-faces)
319 320
(put 'isearch-lazy-highlight-face 'face-alias 'lazy-highlight)
(defvar lazy-highlight-face 'lazy-highlight)
321 322 323
(define-obsolete-variable-alias 'isearch-lazy-highlight-face
                                'lazy-highlight-face
                                "22.1")
324

325
;; Define isearch-mode keymap.
Jim Blandy's avatar
Jim Blandy committed
326

327 328 329
(defvar isearch-mode-map
  (let* ((i 0)
	 (map (make-keymap)))
Kenichi Handa's avatar
Kenichi Handa committed
330
    (or (char-table-p (nth 1 map))
331 332
	(error "The initialization of isearch-mode-map must be updated"))
    ;; Make all multibyte characters search for themselves.
Kenichi Handa's avatar
Kenichi Handa committed
333
    (set-char-table-range (nth 1 map) (cons #x100 (max-char))
334
			  'isearch-printing-char)
Kenichi Handa's avatar
Kenichi Handa committed
335 336
    ;; Make function keys, etc, which aren't bound to a scrolling-function
    ;; exit the search.
337 338
    (define-key map [t] 'isearch-other-control-char)
    ;; Control chars, by default, end isearch mode transparently.
339
    ;; We need these explicit definitions because, in a dense keymap,
340 341
    ;; the binding for t does not affect characters.
    ;; We use a dense keymap to save space.
342
    (while (< i ?\s)
343 344 345 346
      (define-key map (make-string 1 i) 'isearch-other-control-char)
      (setq i (1+ i)))

    ;; Single-byte printing chars extend the search string by default.
347
    (setq i ?\s)
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
    (while (< i 256)
      (define-key map (vector i) 'isearch-printing-char)
      (setq i (1+ i)))

    ;; To handle local bindings with meta char prefix keys, define
    ;; another full keymap.  This must be done for any other prefix
    ;; keys as well, one full keymap per char of the prefix key.  It
    ;; would be simpler to disable the global keymap, and/or have a
    ;; default local key binding for any key not otherwise bound.
    (let ((meta-map (make-sparse-keymap)))
      (define-key map (char-to-string meta-prefix-char) meta-map)
      (define-key map [escape] meta-map))
    (define-key map (vector meta-prefix-char t) 'isearch-other-meta-char)

    ;; Several non-printing chars change the searching behavior.
    (define-key map "\C-s" 'isearch-repeat-forward)
    (define-key map "\C-r" 'isearch-repeat-backward)
    ;; Define M-C-s and M-C-r like C-s and C-r so that the same key
    ;; combinations can be used to repeat regexp isearches that can
    ;; be used to start these searches.
    (define-key map "\M-\C-s" 'isearch-repeat-forward)
    (define-key map "\M-\C-r" 'isearch-repeat-backward)
    (define-key map "\177" 'isearch-delete-char)
    (define-key map "\C-g" 'isearch-abort)
372

373 374 375 376 377
    ;; This assumes \e is the meta-prefix-char.
    (or (= ?\e meta-prefix-char)
	(error "Inconsistency in isearch.el"))
    (define-key map "\e\e\e" 'isearch-cancel)
    (define-key map  [escape escape escape] 'isearch-cancel)
378

379
    (define-key map "\C-q" 'isearch-quote-char)
380

381 382 383
    (define-key map "\r" 'isearch-exit)
    (define-key map "\C-j" 'isearch-printing-char)
    (define-key map "\t" 'isearch-printing-char)
384
    (define-key map [?\S-\ ] 'isearch-printing-char)
385

386 387 388 389
    (define-key map    "\C-w" 'isearch-yank-word-or-char)
    (define-key map "\M-\C-w" 'isearch-del-char)
    (define-key map "\M-\C-y" 'isearch-yank-char)
    (define-key map    "\C-y" 'isearch-yank-line)
390

391 392 393
    ;; Turned off because I find I expect to get the global definition--rms.
    ;; ;; Instead bind C-h to special help command for isearch-mode.
    ;; (define-key map "\C-h" 'isearch-mode-help)
394

395 396 397 398 399 400 401 402 403 404 405 406 407
    (define-key map "\M-n" 'isearch-ring-advance)
    (define-key map "\M-p" 'isearch-ring-retreat)
    (define-key map "\M-y" 'isearch-yank-kill)

    (define-key map "\M-\t" 'isearch-complete)

    ;; Pass frame events transparently so they won't exit the search.
    ;; In particular, if we have more than one display open, then a
    ;; switch-frame might be generated by someone typing at another keyboard.
    (define-key map [switch-frame] nil)
    (define-key map [delete-frame] nil)
    (define-key map [iconify-frame] nil)
    (define-key map [make-frame-visible] nil)
408
    (define-key map [mouse-movement] nil)
409 410
    (define-key map [language-change] nil)

411 412 413 414 415
    ;; For searching multilingual text.
    (define-key map "\C-\\" 'isearch-toggle-input-method)
    (define-key map "\C-^" 'isearch-toggle-specified-input-method)

    ;; People expect to be able to paste with the mouse.
416
    (define-key map [mouse-2] #'isearch-mouse-2)
417 418 419 420 421 422 423 424
    (define-key map [down-mouse-2] nil)

    ;; Some bindings you may want to put in your isearch-mode-hook.
    ;; Suggest some alternates...
    (define-key map "\M-c" 'isearch-toggle-case-fold)
    (define-key map "\M-r" 'isearch-toggle-regexp)
    (define-key map "\M-e" 'isearch-edit-string)

425 426
    (define-key map [?\M-%] 'isearch-query-replace)
    (define-key map [?\C-\M-%] 'isearch-query-replace-regexp)
Juri Linkov's avatar
Juri Linkov committed
427
    (define-key map "\M-so" 'isearch-occur)
428

429 430 431 432 433 434
    map)
  "Keymap for `isearch-mode'.")

(defvar minibuffer-local-isearch-map
  (let ((map (make-sparse-keymap)))
    (set-keymap-parent map minibuffer-local-map)
435
    (define-key map "\r"    'isearch-nonincremental-exit-minibuffer)
436
    (define-key map "\M-\t" 'isearch-complete-edit)
437 438 439 440
    (define-key map "\C-s"  'isearch-forward-exit-minibuffer)
    (define-key map "\C-r"  'isearch-reverse-exit-minibuffer)
    (define-key map "\C-f"  'isearch-yank-char-in-minibuffer)
    (define-key map [right] 'isearch-yank-char-in-minibuffer)
441
    map)
442
  "Keymap for editing isearch strings in the minibuffer.")
Jim Blandy's avatar
Jim Blandy committed
443 444

;; Internal variables declared globally for byte-compiler.
445 446 447 448 449 450
;; These are all set with setq while isearching
;; and bound locally while editing the search string.

(defvar isearch-forward nil)	; Searching in the forward direction.
(defvar isearch-regexp nil)	; Searching for a regexp.
(defvar isearch-word nil)	; Searching for words.
Stefan Monnier's avatar
Stefan Monnier committed
451
(defvar isearch-hidden nil) ; Non-nil if the string exists but is invisible.
452

453 454
(defvar isearch-cmds nil
  "Stack of search status sets.
455 456 457
Each set is a vector of the form:
 [STRING MESSAGE POINT SUCCESS FORWARD OTHER-END WORD
  INVALID-REGEXP WRAPPED BARRIER WITHIN-BRACKETS CASE-FOLD-SEARCH]")
458

459 460 461
(defvar isearch-string "")  ; The current search string.
(defvar isearch-message "") ; text-char-description version of isearch-string

Juri Linkov's avatar
Juri Linkov committed
462 463
(defvar isearch-success t)	; Searching is currently successful.
(defvar isearch-error nil)	; Error message for failed search.
464 465
(defvar isearch-other-end nil)	; Start (end) of match if forward (backward).
(defvar isearch-wrapped nil)	; Searching restarted from the top (bottom).
Jim Blandy's avatar
Jim Blandy committed
466
(defvar isearch-barrier 0)
467
(defvar isearch-just-started nil)
468
(defvar isearch-start-hscroll 0)	; hscroll when starting the search.
Jim Blandy's avatar
Jim Blandy committed
469

470 471 472 473
; case-fold-search while searching.
;   either nil, t, or 'yes.  'yes means the same as t except that mixed
;   case in the search string is ignored.
(defvar isearch-case-fold-search nil)
Jim Blandy's avatar
Jim Blandy committed
474

475 476
(defvar isearch-last-case-fold-search nil)

477 478 479
;; Used to save default value while isearch is active
(defvar isearch-original-minibuffer-message-timeout nil)

Jim Blandy's avatar
Jim Blandy committed
480 481
(defvar isearch-adjusted nil)
(defvar isearch-slow-terminal-mode nil)
482
;; If t, using a small window.
483
(defvar isearch-small-window nil)
Jim Blandy's avatar
Jim Blandy committed
484
(defvar isearch-opoint 0)
485
;; The window configuration active at the beginning of the search.
486
(defvar isearch-window-configuration nil)
Jim Blandy's avatar
Jim Blandy committed
487

488 489
;; Flag to indicate a yank occurred, so don't move the cursor.
(defvar isearch-yank-flag nil)
Jim Blandy's avatar
Jim Blandy committed
490

491 492 493
;; A function to be called after each input character is processed.
;; (It is not called after characters that exit the search.)
;; It is only set from an optional argument to `isearch-mode'.
494
(defvar isearch-op-fun nil)
Jim Blandy's avatar
Jim Blandy committed
495

496
;;  Is isearch-mode in a recursive edit for modal searching.
497
(defvar isearch-recursive-edit nil)
Jim Blandy's avatar
Jim Blandy committed
498

499
;; Should isearch be terminated after doing one search?
500 501 502 503
(defvar isearch-nonincremental nil)

;; New value of isearch-forward after isearch-edit-string.
(defvar isearch-new-forward nil)
Jim Blandy's avatar
Jim Blandy committed
504

505 506
;; Accumulate here the overlays opened during searching.
(defvar isearch-opened-overlays nil)
Jim Blandy's avatar
Jim Blandy committed
507

508 509 510 511 512 513 514
;; The value of input-method-function when isearch is invoked.
(defvar isearch-input-method-function nil)

;; A flag to tell if input-method-function is locally bound when
;; isearch is invoked.
(defvar isearch-input-method-local-p nil)

Jim Blandy's avatar
Jim Blandy committed
515 516 517 518 519 520 521
;; Minor-mode-alist changes - kind of redundant with the
;; echo area, but if isearching in multiple windows, it can be useful.

(or (assq 'isearch-mode minor-mode-alist)
    (nconc minor-mode-alist
	   (list '(isearch-mode isearch-mode))))

522
(defvar isearch-mode nil) ;; Name of the minor mode, if non-nil.
Jim Blandy's avatar
Jim Blandy committed
523 524
(make-variable-buffer-local 'isearch-mode)

525 526 527 528 529
(define-key global-map "\C-s" 'isearch-forward)
(define-key esc-map "\C-s" 'isearch-forward-regexp)
(define-key global-map "\C-r" 'isearch-backward)
(define-key esc-map "\C-r" 'isearch-backward-regexp)

530
;; Entry points to isearch-mode.
Jim Blandy's avatar
Jim Blandy committed
531

532
(defun isearch-forward (&optional regexp-p no-recursive-edit)
Jim Blandy's avatar
Jim Blandy committed
533 534
  "\
Do incremental search forward.
535 536
With a prefix argument, do an incremental regular expression search instead.
\\<isearch-mode-map>
Jim Blandy's avatar
Jim Blandy committed
537
As you type characters, they add to the search string and are found.
538
The following non-printing keys are bound in `isearch-mode-map'.
Jim Blandy's avatar
Jim Blandy committed
539

540
Type \\[isearch-delete-char] to cancel last input item from end of search string.
Jim Blandy's avatar
Jim Blandy committed
541
Type \\[isearch-exit] to exit, leaving point at location found.
542 543 544
Type LFD (C-j) to match end of line.
Type \\[isearch-repeat-forward] to search again forward,\
 \\[isearch-repeat-backward] to search again backward.
545 546
Type \\[isearch-yank-word-or-char] to yank next word or character in buffer
  onto the end of the search string, and search for it.
547 548
Type \\[isearch-del-char] to delete character from end of search string.
Type \\[isearch-yank-char] to yank char from buffer onto end of search\
549 550 551
 string and search for it.
Type \\[isearch-yank-line] to yank rest of line onto end of search string\
 and search for it.
552
Type \\[isearch-yank-kill] to yank the last string of killed text.
Jim Blandy's avatar
Jim Blandy committed
553
Type \\[isearch-quote-char] to quote control character to search for it.
554 555 556 557 558
\\[isearch-abort] while searching or when search has failed cancels input\
 back to what has
 been found successfully.
\\[isearch-abort] when search is successful aborts and moves point to\
 starting point.
Jim Blandy's avatar
Jim Blandy committed
559

560 561 562
If you try to exit with the search string still empty, it invokes
 nonincremental search.

563
Type \\[isearch-query-replace] to start `query-replace' with string to\
Andreas Schwab's avatar
Andreas Schwab committed
564
 replace from last search string.
565
Type \\[isearch-query-replace-regexp] to start `query-replace-regexp'\
566
 with string to replace from last search string.
567

568 569 570 571
Type \\[isearch-toggle-case-fold] to toggle search case-sensitivity.
Type \\[isearch-toggle-regexp] to toggle regular-expression mode.
Type \\[isearch-edit-string] to edit the search string in the minibuffer.

Jim Blandy's avatar
Jim Blandy committed
572 573
Also supported is a search ring of the previous 16 search strings.
Type \\[isearch-ring-advance] to search for the next item in the search ring.
574 575 576
Type \\[isearch-ring-retreat] to search for the previous item in the search\
 ring.
Type \\[isearch-complete] to complete the search string using the search ring.
Jim Blandy's avatar
Jim Blandy committed
577

Eli Zaretskii's avatar
Eli Zaretskii committed
578
If an input method is turned on in the current buffer, that input
579
method is also active while you are typing characters to search.  To
580 581 582 583
toggle the input method, type \\[isearch-toggle-input-method].  It
also toggles the input method in the current buffer.

To use a different input method for searching, type
Eli Zaretskii's avatar
Eli Zaretskii committed
584
\\[isearch-toggle-specified-input-method], and specify an input method
585 586
you want to use.

587
The above keys, bound in `isearch-mode-map', are often controlled by
588
 options; do \\[apropos] on search-.* to find them.
Jim Blandy's avatar
Jim Blandy committed
589
Other control and meta characters terminate the search
590
 and are then executed normally (depending on `search-exit-option').
591
Likewise for function keys and mouse button events.
Jim Blandy's avatar
Jim Blandy committed
592

593 594
If this function is called non-interactively, it does not return to
the calling function until the search is done."
Jim Blandy's avatar
Jim Blandy committed
595

596
  (interactive "P\np")
597
  (isearch-mode t (not (null regexp-p)) nil (not no-recursive-edit)))
Jim Blandy's avatar
Jim Blandy committed
598

599
(defun isearch-forward-regexp (&optional not-regexp no-recursive-edit)
Jim Blandy's avatar
Jim Blandy committed
600 601
  "\
Do incremental search forward for regular expression.
602
With a prefix argument, do a regular string search instead.
Jim Blandy's avatar
Jim Blandy committed
603
Like ordinary incremental search except that your input
604 605 606 607 608
is treated as a regexp.  See \\[isearch-forward] for more info.

In regexp incremental searches, a space or spaces normally matches
any whitespace (the variable `search-whitespace-regexp' controls
precisely what that means).  If you want to search for a literal space
609
and nothing else, enter C-q SPC."
610
  (interactive "P\np")
611
  (isearch-mode t (null not-regexp) nil (not no-recursive-edit)))
Jim Blandy's avatar
Jim Blandy committed
612

613
(defun isearch-backward (&optional regexp-p no-recursive-edit)
Jim Blandy's avatar
Jim Blandy committed
614 615
  "\
Do incremental search backward.
616
With a prefix argument, do a regular expression search instead.
Jim Blandy's avatar
Jim Blandy committed
617
See \\[isearch-forward] for more information."
618
  (interactive "P\np")
619
  (isearch-mode nil (not (null regexp-p)) nil (not no-recursive-edit)))
Jim Blandy's avatar
Jim Blandy committed
620

621
(defun isearch-backward-regexp (&optional not-regexp no-recursive-edit)
Jim Blandy's avatar
Jim Blandy committed
622 623
  "\
Do incremental search backward for regular expression.
624
With a prefix argument, do a regular string search instead.
Jim Blandy's avatar
Jim Blandy committed
625 626
Like ordinary incremental search except that your input
is treated as a regexp.  See \\[isearch-forward] for more info."
627
  (interactive "P\np")
628
  (isearch-mode nil (null not-regexp) nil (not no-recursive-edit)))
629 630 631 632 633 634


(defun isearch-mode-help ()
  (interactive)
  (describe-function 'isearch-forward)
  (isearch-update))
Jim Blandy's avatar
Jim Blandy committed
635 636 637 638 639


;; isearch-mode only sets up incremental search for the minor mode.
;; All the work is done by the isearch-mode commands.

640
;; Not used yet:
641
;;(defvar isearch-commands '(isearch-forward isearch-backward
642 643
;;			     isearch-forward-regexp isearch-backward-regexp)
;;  "List of commands for which isearch-mode does not recursive-edit.")
644

645 646

(defun isearch-mode (forward &optional regexp op-fun recursive-edit word-p)
Richard M. Stallman's avatar
Richard M. Stallman committed
647 648 649
  "Start isearch minor mode.  Called by `isearch-forward', etc.

\\{isearch-mode-map}"
Jim Blandy's avatar
Jim Blandy committed
650 651 652 653

  ;; Initialize global vars.
  (setq isearch-forward forward
	isearch-regexp regexp
654
	isearch-word word-p
Jim Blandy's avatar
Jim Blandy committed
655
	isearch-op-fun op-fun
656
	isearch-last-case-fold-search isearch-case-fold-search
Jim Blandy's avatar
Jim Blandy committed
657 658 659 660 661 662 663 664 665
	isearch-case-fold-search case-fold-search
	isearch-string ""
	isearch-message ""
	isearch-cmds nil
	isearch-success t
	isearch-wrapped nil
	isearch-barrier (point)
	isearch-adjusted nil
	isearch-yank-flag nil
Juri Linkov's avatar
Juri Linkov committed
666
	isearch-error nil
667
	isearch-slow-terminal-mode (and (<= baud-rate search-slow-speed)
Jim Blandy's avatar
Jim Blandy committed
668
					(> (window-height)
669 670
					   (* 4
					      (abs search-slow-window-lines))))
Jim Blandy's avatar
Jim Blandy committed
671 672
	isearch-other-end nil
	isearch-small-window nil
673
	isearch-just-started t
674
	isearch-start-hscroll (window-hscroll)
Jim Blandy's avatar
Jim Blandy committed
675 676

	isearch-opoint (point)
677
	search-ring-yank-pointer nil
678
	isearch-opened-overlays nil
679 680
	isearch-input-method-function input-method-function
	isearch-input-method-local-p (local-variable-p 'input-method-function)
681 682 683 684 685 686
	regexp-search-ring-yank-pointer nil

	;; Save the original value of `minibuffer-message-timeout', and
	;; set it to nil so that isearch's messages don't get timed out.
	isearch-original-minibuffer-message-timeout minibuffer-message-timeout
	minibuffer-message-timeout nil)
687 688 689

  ;; We must bypass input method while reading key.  When a user type
  ;; printable character, appropriate input method is turned on in
690
  ;; minibuffer to read multibyte characters.
691 692 693 694
  (or isearch-input-method-local-p
      (make-local-variable 'input-method-function))
  (setq input-method-function nil)

695
  (looking-at "")
696 697
  (setq isearch-window-configuration
	(if isearch-slow-terminal-mode (current-window-configuration) nil))
698

699 700
  ;; Maybe make minibuffer frame visible and/or raise it.
  (let ((frame (window-frame (minibuffer-window))))
701 702 703 704 705
    (unless (memq (frame-live-p frame) '(nil t))
      (unless (frame-visible-p frame)
	(make-frame-visible frame))
      (if minibuffer-auto-raise
	  (raise-frame frame))))
706

Jim Blandy's avatar
Jim Blandy committed
707
  (setq	isearch-mode " Isearch")  ;; forward? regexp?
708
  (force-mode-line-update)
Jim Blandy's avatar
Jim Blandy committed
709 710 711

  (isearch-push-state)

712
  (setq overriding-terminal-local-map isearch-mode-map)
Jim Blandy's avatar
Jim Blandy committed
713 714
  (isearch-update)
  (run-hooks 'isearch-mode-hook)
715

716
  (add-hook 'mouse-leave-buffer-hook 'isearch-done)
717
  (add-hook 'kbd-macro-termination-hook 'isearch-done)
718

719 720
  ;; isearch-mode can be made modal (in the sense of not returning to
  ;; the calling function until searching is completed) by entering
721
  ;; a recursive-edit and exiting it when done isearching.
722 723 724
  (if recursive-edit
      (let ((isearch-recursive-edit t))
	(recursive-edit)))
725
  isearch-success)
Jim Blandy's avatar
Jim Blandy committed
726 727 728 729 730


;; Some high level utilities.  Others below.

(defun isearch-update ()
731
  ;; Called after each command to update the display.
732 733
  (if (and (null unread-command-events)
	   (null executing-kbd-macro))
Jim Blandy's avatar
Jim Blandy committed
734
      (progn
735
        (if (not (input-pending-p))
736 737 738
	    (if isearch-message-function
		(funcall isearch-message-function)
	      (isearch-message)))
739
        (if (and isearch-slow-terminal-mode
740
                 (not (or isearch-small-window
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
                          (pos-visible-in-window-p))))
            (let ((found-point (point)))
              (setq isearch-small-window t)
              (move-to-window-line 0)
              (let ((window-min-height 1))
                (split-window nil (if (< search-slow-window-lines 0)
                                      (1+ (- search-slow-window-lines))
                                    (- (window-height)
                                       (1+ search-slow-window-lines)))))
              (if (< search-slow-window-lines 0)
                  (progn (vertical-motion (- 1 search-slow-window-lines))
                         (set-window-start (next-window) (point))
                         (set-window-hscroll (next-window)
                                             (window-hscroll))
                         (set-window-hscroll (selected-window) 0))
                (other-window 1))
757 758 759 760 761 762 763
              (goto-char found-point))
	  ;; Keep same hscrolling as at the start of the search when possible
	  (let ((current-scroll (window-hscroll)))
	    (set-window-hscroll (selected-window) isearch-start-hscroll)
	    (unless (pos-visible-in-window-p)
	      (set-window-hscroll (selected-window) current-scroll))))
	(if isearch-other-end
764 765 766
            (if (< isearch-other-end (point)) ; isearch-forward?
                (isearch-highlight isearch-other-end (point))
              (isearch-highlight (point) isearch-other-end))
767
          (isearch-dehighlight))
768
        ))
Jim Blandy's avatar
Jim Blandy committed
769 770 771
  (setq ;; quit-flag nil  not for isearch-mode
   isearch-adjusted nil
   isearch-yank-flag nil)
772
  (when isearch-lazy-highlight
773
    (isearch-lazy-highlight-new-loop))
774 775 776
  ;; We must prevent the point moving to the end of composition when a
  ;; part of the composition has just been searched.
  (setq disable-point-adjustment t))
Jim Blandy's avatar
Jim Blandy committed
777

778
(defun isearch-done (&optional nopush edit)
779 780 781 782 783 784
  "Exit Isearch mode.
For successful search, pass no args.
For a failing search, NOPUSH is t.
For going to the minibuffer to edit the search string,
NOPUSH is t and EDIT is t."

785
  (if isearch-resume-in-command-history
786 787 788 789 790 791
      (let ((command `(isearch-resume ,isearch-string ,isearch-regexp
				      ,isearch-word ,isearch-forward
				      ,isearch-message
				      ',isearch-case-fold-search)))
	(unless (equal (car command-history) command)
	  (setq command-history (cons command command-history)))))
792

793
  (remove-hook 'mouse-leave-buffer-hook 'isearch-done)
794
  (remove-hook 'kbd-macro-termination-hook 'isearch-done)
795 796
  (setq isearch-lazy-highlight-start nil)

Jim Blandy's avatar
Jim Blandy committed
797
  ;; Called by all commands that terminate isearch-mode.
Richard M. Stallman's avatar
Richard M. Stallman committed
798
  ;; If NOPUSH is non-nil, we don't push the string on the search ring.
799
  (setq overriding-terminal-local-map nil)
800
  ;; (setq pre-command-hook isearch-old-pre-command-hook) ; for lemacs
801
  (setq minibuffer-message-timeout isearch-original-minibuffer-message-timeout)
802
  (isearch-dehighlight)
803
  (lazy-highlight-cleanup lazy-highlight-cleanup)
804 805
  (let ((found-start (window-start (selected-window)))
	(found-point (point)))
806 807 808 809 810 811 812 813 814
    (when isearch-window-configuration
      (set-window-configuration isearch-window-configuration)
      (if isearch-small-window
	  (goto-char found-point)
	;; set-window-configuration clobbers window-start; restore it.
	;; This has an annoying side effect of clearing the last_modiff
	;; field of the window, which can cause unwanted scrolling,
	;; so don't do it unless truly necessary.
	(set-window-start (selected-window) found-start t))))
815 816

  (setq isearch-mode nil)
817 818 819 820
  (if isearch-input-method-local-p
      (setq input-method-function isearch-input-method-function)
    (kill-local-variable 'input-method-function))

821
  (force-mode-line-update)
Jim Blandy's avatar
Jim Blandy committed
822

823 824 825 826 827 828 829 830 831 832 833
  ;; If we ended in the middle of some intangible text,
  ;; move to the further end of that intangible text.
  (let ((after (if (eobp) nil
		 (get-text-property (point) 'intangible)))
	(before (if (bobp) nil
		  (get-text-property (1- (point)) 'intangible))))
    (when (and before after (eq before after))
      (if isearch-forward
	  (goto-char (next-single-property-change (point) 'intangible))
	(goto-char (previous-single-property-change (point) 'intangible)))))

Richard M. Stallman's avatar
Richard M. Stallman committed
834
  (if (and (> (length isearch-string) 0) (not nopush))
Jim Blandy's avatar
Jim Blandy committed
835
      ;; Update the ring data.
836
      (isearch-update-ring isearch-string isearch-regexp))
Jim Blandy's avatar
Jim Blandy committed
837

838 839
  (let ((isearch-mode-end-hook-quit (and nopush (not edit))))
    (run-hooks 'isearch-mode-end-hook))
840 841

  ;; If there was movement, mark the starting position.
842
  ;; Maybe should test difference between and set mark only if > threshold.
843 844 845 846 847 848 849
  (if (/= (point) isearch-opoint)
      (or (and transient-mark-mode mark-active)
	  (progn
	    (push-mark isearch-opoint t)
	    (or executing-kbd-macro (> (minibuffer-depth) 0)
		(message "Mark saved where search started")))))

850
  (and (not edit) isearch-recursive-edit (exit-recursive-edit)))
851

852 853
(defun isearch-update-ring (string &optional regexp)
  "Add STRING to the beginning of the search ring.
854
REGEXP if non-nil says use the regexp search ring."
855 856 857 858
  (add-to-history
   (if regexp 'regexp-search-ring 'search-ring)
   string
   (if regexp regexp-search-ring-max search-ring-max)))
859

860 861 862 863 864 865 866 867
;; Switching buffers should first terminate isearch-mode.
;; ;; For Emacs 19, the frame switch event is handled.
;; (defun isearch-switch-frame-handler ()
;;   (interactive) ;; Is this necessary?
;;   ;; First terminate isearch-mode.
;;   (isearch-done)
;;   (isearch-clean-overlays)
;;   (handle-switch-frame (car (cdr last-command-char))))
868

869 870 871

;; The search status structure and stack.

872
(defsubst isearch-string-state (frame)
873
  "Return the search string in FRAME."
874
  (aref frame 0))
875
(defsubst isearch-message-state (frame)
876
  "Return the search string to display to the user in FRAME."
877
  (aref frame 1))
878
(defsubst isearch-point-state (frame)
879
  "Return the point in FRAME."
880
  (aref frame 2))
881
(defsubst isearch-success-state (frame)
882
  "Return the success flag in FRAME."
883
  (aref frame 3))
884
(defsubst isearch-forward-state (frame)
885
  "Return the searching-forward flag in FRAME."
886
  (aref frame 4))