Merge from emacs--rel--22
[bpt/emacs.git] / lisp / isearch.el
CommitLineData
55535639 1;;; isearch.el --- incremental search minor mode
3b1e4dd1 2
0d30b337 3;; Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000,
409cc4a3 4;; 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
3a801d0c 5
3b1e4dd1 6;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
0f09b616 7;; Maintainer: FSF
117132a6 8;; Keywords: matching
8e1cae6d 9
54d2ecd3 10;; This file is part of GNU Emacs.
8e1cae6d 11
59243403
RS
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
b4aa6026 14;; the Free Software Foundation; either version 3, or (at your option)
59243403
RS
15;; any later version.
16
8e1cae6d 17;; GNU Emacs is distributed in the hope that it will be useful,
59243403
RS
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
b578f267 23;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
24;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25;; Boston, MA 02110-1301, USA.
8e1cae6d 26
3b1e4dd1
ER
27;;; Commentary:
28
8e1cae6d
JB
29;; Instructions
30
08200510
RS
31;; For programmed use of isearch-mode, e.g. calling (isearch-forward),
32;; isearch-mode behaves modally and does not return until the search
117132a6 33;; is completed. It uses a recursive-edit to behave this way.
08200510 34
8e1cae6d 35;; The key bindings active within isearch-mode are defined below in
08200510
RS
36;; `isearch-mode-map' which is given bindings close to the default
37;; characters of the original isearch.el. With `isearch-mode',
38;; however, you can bind multi-character keys and it should be easier
39;; to add new commands. One bug though: keys with meta-prefix cannot
40;; be longer than two chars. Also see minibuffer-local-isearch-map
41;; for bindings active during `isearch-edit-string'.
42
117132a6
DL
43;; isearch-mode should work even if you switch windows with the mouse,
44;; in which case isearch-mode is terminated automatically before the
45;; switch.
08200510
RS
46
47;; The search ring and completion commands automatically put you in
48;; the minibuffer to edit the string. This gives you a chance to
49;; modify the search string before executing the search. There are
50;; three commands to terminate the editing: C-s and C-r exit the
51;; minibuffer and search forward and reverse respectively, while C-m
52;; exits and does a nonincremental search.
53
54;; Exiting immediately from isearch uses isearch-edit-string instead
55;; of nonincremental-search, if search-nonincremental-instead is non-nil.
56;; The name of this option should probably be changed if we decide to
57;; keep the behavior. No point in forcing nonincremental search until
58;; the last possible moment.
59
3b1e4dd1 60;;; Code:
08200510
RS
61
62\f
191f025a 63;; Some additional options and constants.
08200510 64
9c1db929
RS
65(defgroup isearch nil
66 "Incremental search minor mode."
117132a6
DL
67 :link '(emacs-commentary-link "isearch")
68 :link '(custom-manual "(emacs)Incremental Search")
9c1db929
RS
69 :prefix "isearch-"
70 :prefix "search-"
71 :group 'matching)
fdf5afa4 72
9c1db929
RS
73
74(defcustom search-exit-option t
75 "*Non-nil means random control characters terminate incremental search."
76 :type 'boolean
77 :group 'isearch)
78
79(defcustom search-slow-window-lines 1
fdf5afa4
RS
80 "*Number of lines in slow search display windows.
81These are the short windows used during incremental search on slow terminals.
82Negative means put the slow search window at the top (normally it's at bottom)
9c1db929
RS
83and the value is minus the number of lines."
84 :type 'integer
85 :group 'isearch)
fdf5afa4 86
9c1db929 87(defcustom search-slow-speed 1200
fdf5afa4
RS
88 "*Highest terminal speed at which to use \"slow\" style incremental search.
89This is the style where a one-line window is created to show the line
9c1db929
RS
90that the search has reached."
91 :type 'integer
92 :group 'isearch)
8e1cae6d 93
9c1db929 94(defcustom search-upper-case 'not-yanks
8e1cae6d 95 "*If non-nil, upper case chars disable case fold searching.
08200510
RS
96That is, upper and lower case chars must match exactly.
97This applies no matter where the chars come from, but does not
fdf5afa4 98apply to chars in regexps that are prefixed with `\\'.
6e3057bb
JL
99If this value is `not-yanks', text yanked into the search string
100in Isearch mode is always downcased."
9c1db929
RS
101 :type '(choice (const :tag "off" nil)
102 (const not-yanks)
5786b3ed 103 (other :tag "on" t))
9c1db929 104 :group 'isearch)
8e1cae6d 105
9c1db929 106(defcustom search-nonincremental-instead t
8e1cae6d 107 "*If non-nil, do a nonincremental search instead if exiting immediately.
08200510 108Actually, `isearch-edit-string' is called to let you enter the search
9c1db929
RS
109string, and RET terminates editing and does a nonincremental search."
110 :type 'boolean
111 :group 'isearch)
8e1cae6d 112
ab67e8b6 113(defcustom search-whitespace-regexp "\\s-+"
8e1cae6d 114 "*If non-nil, regular expression to match a sequence of whitespace chars.
e2b992cb 115This applies to regular expression incremental search.
ab67e8b6
RS
116When you put a space or spaces in the incremental regexp, it stands for
117this, unless it is inside of a regexp construct such as [...] or *, + or ?.
118You might want to use something like \"[ \\t\\r\\n]+\" instead.
119In the Customization buffer, that is `[' followed by a space,
51a77cba
RS
120a tab, a carriage return (control-M), a newline, and `]+'.
121
122When this is nil, each space you type matches literally, against one space."
123 :type '(choice (const :tag "Find Spaces Literally" nil)
124 regexp)
9c1db929 125 :group 'isearch)
8e1cae6d 126
0352b205
RS
127(defcustom search-invisible 'open
128 "If t incremental search can match hidden text.
6480c508
JB
129A nil value means don't match invisible text.
130When the value is `open', if the text matched is made invisible by
0352b205
RS
131an overlay having an `invisible' property and that overlay has a property
132`isearch-open-invisible', then incremental search will show the contents.
cd59ea72
SM
133\(This applies when using `outline.el' and `hideshow.el'.)
134See also `reveal-mode' if you want overlays to automatically be opened
135whenever point is in one of them."
0352b205
RS
136 :type '(choice (const :tag "Match hidden text" t)
137 (const :tag "Open overlays" open)
79c7a4fa 138 (const :tag "Don't match hidden text" nil))
0352b205
RS
139 :group 'isearch)
140
141(defcustom isearch-hide-immediately t
68c18d6d
RS
142 "If non-nil, re-hide an invisible match right away.
143This variable makes a difference when `search-invisible' is set to `open'.
144It means that after search makes some invisible text visible
145to show the match, it makes the text invisible again when the match moves.
b48ca14f
JB
146Ordinarily the text becomes invisible again at the end of the search."
147 :type 'boolean
0352b205 148 :group 'isearch)
86bfaffe 149
00098b01
KS
150(defcustom isearch-resume-in-command-history nil
151 "*If non-nil, `isearch-resume' commands are added to the command history.
152This allows you to resume earlier isearch sessions through the
153command history."
6848c9f1
KS
154 :type 'boolean
155 :group 'isearch)
156
08200510
RS
157(defvar isearch-mode-hook nil
158 "Function(s) to call after starting up an incremental search.")
159
160(defvar isearch-mode-end-hook nil
87e97673
RS
161 "Function(s) to call after terminating an incremental search.
162When these functions are called, `isearch-mode-end-hook-quit'
4974aba8 163is non-nil if the user quits the search.")
87e97673
RS
164
165(defvar isearch-mode-end-hook-quit nil
4974aba8 166 "Non-nil while running `isearch-mode-end-hook' if the user quits the search.")
08200510 167
ac475d3a
JL
168(defvar isearch-message-function nil
169 "Function to call to display the search prompt.
170If nil, use `isearch-message'.")
171
6a18e4e7
JL
172(defvar isearch-wrap-function nil
173 "Function to call to wrap the search when search is failed.
174If nil, move point to the beginning of the buffer for a forward search,
175or to the end of the buffer for a backward search.")
176
177(defvar isearch-push-state-function nil
178 "Function to save a function restoring the mode-specific isearch state
179to the search status stack.")
180
5e189f39
JL
181(defvar isearch-success-function 'isearch-success-function-default
182 "Function to report whether the new search match is considered successful.
183The function has two arguments: the positions of start and end of text
b92368b4 184matched by the search. If this function returns nil, continue
5e189f39
JL
185searching without stopping at this match.")
186
191f025a 187;; Search ring.
8e1cae6d
JB
188
189(defvar search-ring nil
190 "List of search string sequences.")
08200510 191(defvar regexp-search-ring nil
8e1cae6d
JB
192 "List of regular expression search string sequences.")
193
9c1db929
RS
194(defcustom search-ring-max 16
195 "*Maximum length of search ring before oldest elements are thrown away."
196 :type 'integer
197 :group 'isearch)
198(defcustom regexp-search-ring-max 16
199 "*Maximum length of regexp search ring before oldest elements are thrown away."
200 :type 'integer
201 :group 'isearch)
8e1cae6d
JB
202
203(defvar search-ring-yank-pointer nil
a5dcf63f 204 "Index in `search-ring' of last string reused.
6480c508 205It is nil if none yet.")
08200510 206(defvar regexp-search-ring-yank-pointer nil
a5dcf63f 207 "Index in `regexp-search-ring' of last string reused.
6480c508 208It is nil if none yet.")
8e1cae6d 209
9c1db929 210(defcustom search-ring-update nil
08200510 211 "*Non-nil if advancing or retreating in the search ring should cause search.
9c1db929
RS
212Default value, nil, means edit the string instead."
213 :type 'boolean
214 :group 'isearch)
08200510 215
bca92193
JL
216;;; isearch highlight customization.
217
218(defcustom search-highlight t
219 "*Non-nil means incremental search highlights the current match."
220 :type 'boolean
221 :group 'isearch)
222
223(defface isearch
224 '((((class color) (min-colors 88) (background light))
225 ;; The background must not be too dark, for that means
226 ;; the character is hard to see when the cursor is there.
a49ff341 227 (:background "magenta3" :foreground "lightskyblue1"))
bca92193
JL
228 (((class color) (min-colors 88) (background dark))
229 (:background "palevioletred2" :foreground "brown4"))
230 (((class color) (min-colors 16))
231 (:background "magenta4" :foreground "cyan1"))
232 (((class color) (min-colors 8))
233 (:background "magenta4" :foreground "cyan1"))
234 (t (:inverse-video t)))
235 "Face for highlighting Isearch matches."
92cc4a30
JL
236 :group 'isearch
237 :group 'basic-faces)
bca92193
JL
238(defvar isearch 'isearch)
239
d8891294
JL
240(defface isearch-fail
241 '((((class color) (min-colors 88) (background light))
242 (:background "RosyBrown1"))
243 (((class color) (min-colors 88) (background dark))
244 (:background "red4"))
245 (((class color) (min-colors 16))
246 (:background "red"))
247 (((class color) (min-colors 8))
248 (:background "red"))
249 (((class color grayscale))
250 :foreground "grey")
251 (t (:inverse-video t)))
723e5b84 252 "Face for highlighting failed part in Isearch echo-area message."
d8891294 253 :version "23.1"
723e5b84
BG
254 :group 'isearch)
255
bca92193
JL
256(defcustom isearch-lazy-highlight t
257 "*Controls the lazy-highlighting during incremental search.
258When non-nil, all text in the buffer matching the current search
259string is highlighted lazily (see `lazy-highlight-initial-delay'
260and `lazy-highlight-interval')."
261 :type 'boolean
262 :group 'lazy-highlight
263 :group 'isearch)
264
c1bc6bb6 265;;; Lazy highlight customization.
bca92193 266
c1bc6bb6
RS
267(defgroup lazy-highlight nil
268 "Lazy highlighting feature for matching strings."
269 :prefix "lazy-highlight-"
270 :version "21.1"
271 :group 'isearch
bca92193 272 :group 'matching)
c1bc6bb6
RS
273
274(defcustom lazy-highlight-cleanup t
275 "*Controls whether to remove extra highlighting after a search.
276If this is nil, extra highlighting can be \"manually\" removed with
46fe9018 277\\[lazy-highlight-cleanup]."
c1bc6bb6
RS
278 :type 'boolean
279 :group 'lazy-highlight)
6480c508
JB
280(define-obsolete-variable-alias 'isearch-lazy-highlight-cleanup
281 'lazy-highlight-cleanup
282 "22.1")
c1bc6bb6
RS
283
284(defcustom lazy-highlight-initial-delay 0.25
285 "*Seconds to wait before beginning to lazily highlight all matches."
286 :type 'number
287 :group 'lazy-highlight)
6480c508
JB
288(define-obsolete-variable-alias 'isearch-lazy-highlight-initial-delay
289 'lazy-highlight-initial-delay
290 "22.1")
c1bc6bb6
RS
291
292(defcustom lazy-highlight-interval 0 ; 0.0625
293 "*Seconds between lazily highlighting successive matches."
294 :type 'number
295 :group 'lazy-highlight)
6480c508
JB
296(define-obsolete-variable-alias 'isearch-lazy-highlight-interval
297 'lazy-highlight-interval
298 "22.1")
c1bc6bb6
RS
299
300(defcustom lazy-highlight-max-at-a-time 20
301 "*Maximum matches to highlight at a time (for `lazy-highlight').
302Larger values may reduce isearch's responsiveness to user input;
303smaller values make matches highlight slowly.
304A value of nil means highlight all matches."
305 :type '(choice (const :tag "All" nil)
306 (integer :tag "Some"))
307 :group 'lazy-highlight)
6480c508
JB
308(define-obsolete-variable-alias 'isearch-lazy-highlight-max-at-a-time
309 'lazy-highlight-max-at-a-time
310 "22.1")
c1bc6bb6 311
e3cde0c7 312(defface lazy-highlight
c1bc6bb6
RS
313 '((((class color) (min-colors 88) (background light))
314 (:background "paleturquoise"))
315 (((class color) (min-colors 88) (background dark))
316 (:background "paleturquoise4"))
317 (((class color) (min-colors 16))
318 (:background "turquoise3"))
319 (((class color) (min-colors 8))
320 (:background "turquoise3"))
321 (t (:underline t)))
322 "Face for lazy highlighting of matches other than the current one."
92cc4a30
JL
323 :group 'lazy-highlight
324 :group 'basic-faces)
bca92193
JL
325(put 'isearch-lazy-highlight-face 'face-alias 'lazy-highlight)
326(defvar lazy-highlight-face 'lazy-highlight)
6480c508
JB
327(define-obsolete-variable-alias 'isearch-lazy-highlight-face
328 'lazy-highlight-face
329 "22.1")
c1bc6bb6 330\f
b92368b4
JL
331;; Define isearch help map.
332
333(defvar isearch-help-map
334 (let ((i 0)
335 (map (make-sparse-keymap)))
336 (define-key map [t] 'isearch-other-control-char)
337 (define-key map (char-to-string help-char) 'isearch-help-for-help)
338 (define-key map [help] 'isearch-help-for-help)
339 (define-key map [f1] 'isearch-help-for-help)
340 (define-key map "?" 'isearch-help-for-help)
341 (define-key map "b" 'isearch-describe-bindings)
342 (define-key map "k" 'isearch-describe-key)
343 (define-key map "m" 'isearch-describe-mode)
344 (define-key map "q" 'help-quit)
345 map)
346 "Keymap for characters following the Help key for isearch mode.")
347
348(eval-when-compile (require 'help-macro))
349
350(make-help-screen isearch-help-for-help-internal
351 "Type a help option: [bkm] or ?"
352 "You have typed %THIS-KEY%, the help character. Type a Help option:
353\(Type \\<help-map>\\[help-quit] to exit the Help command.)
354
355b Display all isearch key bindings.
356k KEYS Display full documentation of isearch key sequence.
357m Display documentation of isearch mode.
358
359You can't type here other help keys available in the global help map,
360but outise of this help window when you type them in isearch mode,
361they exit isearch mode before displaying global help."
362 isearch-help-map)
363
364(defun isearch-help-for-help ()
365 "Display isearch help menu."
366 (interactive)
367 (let (same-window-buffer-names same-window-regexps)
368 (isearch-help-for-help-internal))
369 (isearch-update))
370
371(defun isearch-describe-bindings ()
372 "Show a list of all keys defined in isearch mode, and their definitions.
373This is like `describe-bindings', but displays only isearch keys."
374 (interactive)
375 (let (same-window-buffer-names same-window-regexps)
376 (with-help-window "*Help*"
377 (with-current-buffer standard-output
378 (princ "Isearch Mode Bindings:\n")
379 (princ (substitute-command-keys "\\{isearch-mode-map}"))))))
380
381(defun isearch-describe-key ()
382 "Display documentation of the function invoked by isearch key."
383 (interactive)
384 (let (same-window-buffer-names same-window-regexps)
385 (call-interactively 'describe-key))
386 (isearch-update))
387
388(defun isearch-describe-mode ()
389 "Display documentation of isearch mode."
390 (interactive)
391 (let (same-window-buffer-names same-window-regexps)
392 (describe-function 'isearch-forward))
393 (isearch-update))
394
395(defalias 'isearch-mode-help 'isearch-describe-mode)
396
397\f
191f025a 398;; Define isearch-mode keymap.
8e1cae6d 399
02b2f510
SM
400(defvar isearch-mode-map
401 (let* ((i 0)
402 (map (make-keymap)))
8f924df7 403 (or (char-table-p (nth 1 map))
02b2f510
SM
404 (error "The initialization of isearch-mode-map must be updated"))
405 ;; Make all multibyte characters search for themselves.
6b61353c 406 (set-char-table-range (nth 1 map) (cons #x100 (max-char))
5760cdc1 407 'isearch-printing-char)
6b61353c
KH
408 ;; Make function keys, etc, which aren't bound to a scrolling-function
409 ;; exit the search.
02b2f510
SM
410 (define-key map [t] 'isearch-other-control-char)
411 ;; Control chars, by default, end isearch mode transparently.
b48ca14f 412 ;; We need these explicit definitions because, in a dense keymap,
02b2f510
SM
413 ;; the binding for t does not affect characters.
414 ;; We use a dense keymap to save space.
6480c508 415 (while (< i ?\s)
02b2f510
SM
416 (define-key map (make-string 1 i) 'isearch-other-control-char)
417 (setq i (1+ i)))
418
419 ;; Single-byte printing chars extend the search string by default.
6480c508 420 (setq i ?\s)
02b2f510
SM
421 (while (< i 256)
422 (define-key map (vector i) 'isearch-printing-char)
423 (setq i (1+ i)))
424
425 ;; To handle local bindings with meta char prefix keys, define
426 ;; another full keymap. This must be done for any other prefix
427 ;; keys as well, one full keymap per char of the prefix key. It
428 ;; would be simpler to disable the global keymap, and/or have a
429 ;; default local key binding for any key not otherwise bound.
430 (let ((meta-map (make-sparse-keymap)))
431 (define-key map (char-to-string meta-prefix-char) meta-map)
432 (define-key map [escape] meta-map))
433 (define-key map (vector meta-prefix-char t) 'isearch-other-meta-char)
434
435 ;; Several non-printing chars change the searching behavior.
436 (define-key map "\C-s" 'isearch-repeat-forward)
437 (define-key map "\C-r" 'isearch-repeat-backward)
438 ;; Define M-C-s and M-C-r like C-s and C-r so that the same key
439 ;; combinations can be used to repeat regexp isearches that can
440 ;; be used to start these searches.
441 (define-key map "\M-\C-s" 'isearch-repeat-forward)
442 (define-key map "\M-\C-r" 'isearch-repeat-backward)
443 (define-key map "\177" 'isearch-delete-char)
444 (define-key map "\C-g" 'isearch-abort)
1f4139d5 445
02b2f510
SM
446 ;; This assumes \e is the meta-prefix-char.
447 (or (= ?\e meta-prefix-char)
448 (error "Inconsistency in isearch.el"))
449 (define-key map "\e\e\e" 'isearch-cancel)
450 (define-key map [escape escape escape] 'isearch-cancel)
b48ca14f 451
02b2f510 452 (define-key map "\C-q" 'isearch-quote-char)
08200510 453
02b2f510
SM
454 (define-key map "\r" 'isearch-exit)
455 (define-key map "\C-j" 'isearch-printing-char)
456 (define-key map "\t" 'isearch-printing-char)
ec06d344 457 (define-key map [?\S-\ ] 'isearch-printing-char)
b48ca14f 458
74820eb5
JL
459 (define-key map "\C-w" 'isearch-yank-word-or-char)
460 (define-key map "\M-\C-w" 'isearch-del-char)
461 (define-key map "\M-\C-y" 'isearch-yank-char)
462 (define-key map "\C-y" 'isearch-yank-line)
08200510 463
b92368b4 464 (define-key map "\C-h" isearch-help-map)
08200510 465
02b2f510
SM
466 (define-key map "\M-n" 'isearch-ring-advance)
467 (define-key map "\M-p" 'isearch-ring-retreat)
468 (define-key map "\M-y" 'isearch-yank-kill)
469
470 (define-key map "\M-\t" 'isearch-complete)
471
472 ;; Pass frame events transparently so they won't exit the search.
473 ;; In particular, if we have more than one display open, then a
474 ;; switch-frame might be generated by someone typing at another keyboard.
475 (define-key map [switch-frame] nil)
476 (define-key map [delete-frame] nil)
477 (define-key map [iconify-frame] nil)
478 (define-key map [make-frame-visible] nil)
3f482bc0 479 (define-key map [mouse-movement] nil)
76197e28
JR
480 (define-key map [language-change] nil)
481
02b2f510
SM
482 ;; For searching multilingual text.
483 (define-key map "\C-\\" 'isearch-toggle-input-method)
484 (define-key map "\C-^" 'isearch-toggle-specified-input-method)
485
486 ;; People expect to be able to paste with the mouse.
e4af1426 487 (define-key map [mouse-2] #'isearch-mouse-2)
02b2f510
SM
488 (define-key map [down-mouse-2] nil)
489
490 ;; Some bindings you may want to put in your isearch-mode-hook.
491 ;; Suggest some alternates...
492 (define-key map "\M-c" 'isearch-toggle-case-fold)
493 (define-key map "\M-r" 'isearch-toggle-regexp)
494 (define-key map "\M-e" 'isearch-edit-string)
495
81e898ea
SM
496 (define-key map [?\M-%] 'isearch-query-replace)
497 (define-key map [?\C-\M-%] 'isearch-query-replace-regexp)
6e3057bb 498 (define-key map "\M-so" 'isearch-occur)
74820eb5 499
02b2f510
SM
500 map)
501 "Keymap for `isearch-mode'.")
502
503(defvar minibuffer-local-isearch-map
504 (let ((map (make-sparse-keymap)))
505 (set-keymap-parent map minibuffer-local-map)
74820eb5 506 (define-key map "\r" 'isearch-nonincremental-exit-minibuffer)
02b2f510 507 (define-key map "\M-\t" 'isearch-complete-edit)
74820eb5
JL
508 (define-key map "\C-s" 'isearch-forward-exit-minibuffer)
509 (define-key map "\C-r" 'isearch-reverse-exit-minibuffer)
510 (define-key map "\C-f" 'isearch-yank-char-in-minibuffer)
511 (define-key map [right] 'isearch-yank-char-in-minibuffer)
02b2f510 512 map)
08200510 513 "Keymap for editing isearch strings in the minibuffer.")
8e1cae6d 514
8e1cae6d 515;; Internal variables declared globally for byte-compiler.
08200510
RS
516;; These are all set with setq while isearching
517;; and bound locally while editing the search string.
518
519(defvar isearch-forward nil) ; Searching in the forward direction.
520(defvar isearch-regexp nil) ; Searching for a regexp.
521(defvar isearch-word nil) ; Searching for words.
cd59ea72 522(defvar isearch-hidden nil) ; Non-nil if the string exists but is invisible.
08200510 523
191f025a
SM
524(defvar isearch-cmds nil
525 "Stack of search status sets.
08e3de69
EZ
526Each set is a vector of the form:
527 [STRING MESSAGE POINT SUCCESS FORWARD OTHER-END WORD
528 INVALID-REGEXP WRAPPED BARRIER WITHIN-BRACKETS CASE-FOLD-SEARCH]")
191f025a 529
08200510
RS
530(defvar isearch-string "") ; The current search string.
531(defvar isearch-message "") ; text-char-description version of isearch-string
532
ba653a53
JL
533(defvar isearch-success t) ; Searching is currently successful.
534(defvar isearch-error nil) ; Error message for failed search.
08200510
RS
535(defvar isearch-other-end nil) ; Start (end) of match if forward (backward).
536(defvar isearch-wrapped nil) ; Searching restarted from the top (bottom).
8e1cae6d 537(defvar isearch-barrier 0)
99ae9e9f 538(defvar isearch-just-started nil)
ddbe3d5f 539(defvar isearch-start-hscroll 0) ; hscroll when starting the search.
8e1cae6d 540
4453091d
RS
541; case-fold-search while searching.
542; either nil, t, or 'yes. 'yes means the same as t except that mixed
543; case in the search string is ignored.
544(defvar isearch-case-fold-search nil)
8e1cae6d 545
67085aba
GM
546(defvar isearch-last-case-fold-search nil)
547
ae1a21c6
MB
548;; Used to save default value while isearch is active
549(defvar isearch-original-minibuffer-message-timeout nil)
550
8e1cae6d
JB
551(defvar isearch-adjusted nil)
552(defvar isearch-slow-terminal-mode nil)
191f025a 553;; If t, using a small window.
08200510 554(defvar isearch-small-window nil)
8e1cae6d 555(defvar isearch-opoint 0)
191f025a 556;; The window configuration active at the beginning of the search.
08200510 557(defvar isearch-window-configuration nil)
8e1cae6d 558
08200510
RS
559;; Flag to indicate a yank occurred, so don't move the cursor.
560(defvar isearch-yank-flag nil)
8e1cae6d 561
191f025a
SM
562;; A function to be called after each input character is processed.
563;; (It is not called after characters that exit the search.)
564;; It is only set from an optional argument to `isearch-mode'.
08200510 565(defvar isearch-op-fun nil)
8e1cae6d 566
191f025a 567;; Is isearch-mode in a recursive edit for modal searching.
08200510 568(defvar isearch-recursive-edit nil)
8e1cae6d 569
191f025a 570;; Should isearch be terminated after doing one search?
08200510
RS
571(defvar isearch-nonincremental nil)
572
573;; New value of isearch-forward after isearch-edit-string.
574(defvar isearch-new-forward nil)
8e1cae6d 575
0352b205
RS
576;; Accumulate here the overlays opened during searching.
577(defvar isearch-opened-overlays nil)
8e1cae6d 578
99848db0
KH
579;; The value of input-method-function when isearch is invoked.
580(defvar isearch-input-method-function nil)
581
582;; A flag to tell if input-method-function is locally bound when
583;; isearch is invoked.
584(defvar isearch-input-method-local-p nil)
585
8e1cae6d
JB
586;; Minor-mode-alist changes - kind of redundant with the
587;; echo area, but if isearching in multiple windows, it can be useful.
588
589(or (assq 'isearch-mode minor-mode-alist)
590 (nconc minor-mode-alist
591 (list '(isearch-mode isearch-mode))))
592
08200510 593(defvar isearch-mode nil) ;; Name of the minor mode, if non-nil.
8e1cae6d
JB
594(make-variable-buffer-local 'isearch-mode)
595
fdf5afa4
RS
596(define-key global-map "\C-s" 'isearch-forward)
597(define-key esc-map "\C-s" 'isearch-forward-regexp)
598(define-key global-map "\C-r" 'isearch-backward)
599(define-key esc-map "\C-r" 'isearch-backward-regexp)
600
191f025a 601;; Entry points to isearch-mode.
8e1cae6d 602
eceee2c0 603(defun isearch-forward (&optional regexp-p no-recursive-edit)
8e1cae6d
JB
604 "\
605Do incremental search forward.
08200510
RS
606With a prefix argument, do an incremental regular expression search instead.
607\\<isearch-mode-map>
8e1cae6d 608As you type characters, they add to the search string and are found.
b48ca14f 609The following non-printing keys are bound in `isearch-mode-map'.
8e1cae6d 610
35904fd3 611Type \\[isearch-delete-char] to cancel last input item from end of search string.
8e1cae6d 612Type \\[isearch-exit] to exit, leaving point at location found.
08200510
RS
613Type LFD (C-j) to match end of line.
614Type \\[isearch-repeat-forward] to search again forward,\
615 \\[isearch-repeat-backward] to search again backward.
0ae85960
RS
616Type \\[isearch-yank-word-or-char] to yank next word or character in buffer
617 onto the end of the search string, and search for it.
74820eb5
JL
618Type \\[isearch-del-char] to delete character from end of search string.
619Type \\[isearch-yank-char] to yank char from buffer onto end of search\
08200510
RS
620 string and search for it.
621Type \\[isearch-yank-line] to yank rest of line onto end of search string\
622 and search for it.
75a07f2c 623Type \\[isearch-yank-kill] to yank the last string of killed text.
8e1cae6d 624Type \\[isearch-quote-char] to quote control character to search for it.
08200510
RS
625\\[isearch-abort] while searching or when search has failed cancels input\
626 back to what has
627 been found successfully.
628\\[isearch-abort] when search is successful aborts and moves point to\
629 starting point.
8e1cae6d 630
b3612973
RS
631If you try to exit with the search string still empty, it invokes
632 nonincremental search.
633
ac010fca 634Type \\[isearch-query-replace] to start `query-replace' with string to\
8bdf62a7 635 replace from last search string.
ac010fca 636Type \\[isearch-query-replace-regexp] to start `query-replace-regexp'\
6480c508 637 with string to replace from last search string.
ac010fca 638
6c551d4e
EZ
639Type \\[isearch-toggle-case-fold] to toggle search case-sensitivity.
640Type \\[isearch-toggle-regexp] to toggle regular-expression mode.
641Type \\[isearch-edit-string] to edit the search string in the minibuffer.
642
8e1cae6d
JB
643Also supported is a search ring of the previous 16 search strings.
644Type \\[isearch-ring-advance] to search for the next item in the search ring.
08200510
RS
645Type \\[isearch-ring-retreat] to search for the previous item in the search\
646 ring.
647Type \\[isearch-complete] to complete the search string using the search ring.
8e1cae6d 648
b92368b4
JL
649Type \\[isearch-describe-bindings] to display all isearch key bindings.
650Type \\[isearch-describe-key] to display documentation of isearch key.
651Type \\[isearch-describe-mode] to display documentation of isearch mode.
652
1e14b095 653If an input method is turned on in the current buffer, that input
b48ca14f 654method is also active while you are typing characters to search. To
37b20c9b
KH
655toggle the input method, type \\[isearch-toggle-input-method]. It
656also toggles the input method in the current buffer.
657
658To use a different input method for searching, type
1e14b095 659\\[isearch-toggle-specified-input-method], and specify an input method
37b20c9b
KH
660you want to use.
661
b48ca14f 662The above keys, bound in `isearch-mode-map', are often controlled by
35904fd3 663 options; do \\[apropos] on search-.* to find them.
8e1cae6d 664Other control and meta characters terminate the search
08200510 665 and are then executed normally (depending on `search-exit-option').
fd49e05c 666Likewise for function keys and mouse button events.
8e1cae6d 667
08200510
RS
668If this function is called non-interactively, it does not return to
669the calling function until the search is done."
8e1cae6d 670
eceee2c0 671 (interactive "P\np")
4ae7d00a 672 (isearch-mode t (not (null regexp-p)) nil (not no-recursive-edit)))
8e1cae6d 673
eceee2c0 674(defun isearch-forward-regexp (&optional not-regexp no-recursive-edit)
8e1cae6d
JB
675 "\
676Do incremental search forward for regular expression.
08200510 677With a prefix argument, do a regular string search instead.
8e1cae6d 678Like ordinary incremental search except that your input
ab67e8b6
RS
679is treated as a regexp. See \\[isearch-forward] for more info.
680
681In regexp incremental searches, a space or spaces normally matches
682any whitespace (the variable `search-whitespace-regexp' controls
683precisely what that means). If you want to search for a literal space
1b1fb2ef 684and nothing else, enter C-q SPC."
eceee2c0 685 (interactive "P\np")
4ae7d00a 686 (isearch-mode t (null not-regexp) nil (not no-recursive-edit)))
8e1cae6d 687
eceee2c0 688(defun isearch-backward (&optional regexp-p no-recursive-edit)
8e1cae6d
JB
689 "\
690Do incremental search backward.
08200510 691With a prefix argument, do a regular expression search instead.
8e1cae6d 692See \\[isearch-forward] for more information."
eceee2c0 693 (interactive "P\np")
4ae7d00a 694 (isearch-mode nil (not (null regexp-p)) nil (not no-recursive-edit)))
8e1cae6d 695
eceee2c0 696(defun isearch-backward-regexp (&optional not-regexp no-recursive-edit)
8e1cae6d
JB
697 "\
698Do incremental search backward for regular expression.
08200510 699With a prefix argument, do a regular string search instead.
8e1cae6d
JB
700Like ordinary incremental search except that your input
701is treated as a regexp. See \\[isearch-forward] for more info."
eceee2c0 702 (interactive "P\np")
4ae7d00a 703 (isearch-mode nil (null not-regexp) nil (not no-recursive-edit)))
08200510 704
8e1cae6d 705\f
8e1cae6d
JB
706;; isearch-mode only sets up incremental search for the minor mode.
707;; All the work is done by the isearch-mode commands.
708
08200510 709;; Not used yet:
d7fa5aa2 710;;(defvar isearch-commands '(isearch-forward isearch-backward
08200510
RS
711;; isearch-forward-regexp isearch-backward-regexp)
712;; "List of commands for which isearch-mode does not recursive-edit.")
b48ca14f 713
08200510
RS
714
715(defun isearch-mode (forward &optional regexp op-fun recursive-edit word-p)
b92368b4
JL
716 "Start isearch minor mode.
717It is called by the function `isearch-forward' and other related functions."
8e1cae6d
JB
718
719 ;; Initialize global vars.
720 (setq isearch-forward forward
721 isearch-regexp regexp
08200510 722 isearch-word word-p
8e1cae6d 723 isearch-op-fun op-fun
67085aba 724 isearch-last-case-fold-search isearch-case-fold-search
8e1cae6d
JB
725 isearch-case-fold-search case-fold-search
726 isearch-string ""
727 isearch-message ""
728 isearch-cmds nil
729 isearch-success t
730 isearch-wrapped nil
731 isearch-barrier (point)
732 isearch-adjusted nil
733 isearch-yank-flag nil
ba653a53 734 isearch-error nil
0cabad13 735 isearch-slow-terminal-mode (and (<= baud-rate search-slow-speed)
8e1cae6d 736 (> (window-height)
fad241d3
RS
737 (* 4
738 (abs search-slow-window-lines))))
8e1cae6d
JB
739 isearch-other-end nil
740 isearch-small-window nil
99ae9e9f 741 isearch-just-started t
ddbe3d5f 742 isearch-start-hscroll (window-hscroll)
8e1cae6d 743
8e1cae6d 744 isearch-opoint (point)
a5dcf63f 745 search-ring-yank-pointer nil
0352b205 746 isearch-opened-overlays nil
99848db0
KH
747 isearch-input-method-function input-method-function
748 isearch-input-method-local-p (local-variable-p 'input-method-function)
ae1a21c6
MB
749 regexp-search-ring-yank-pointer nil
750
751 ;; Save the original value of `minibuffer-message-timeout', and
752 ;; set it to nil so that isearch's messages don't get timed out.
753 isearch-original-minibuffer-message-timeout minibuffer-message-timeout
754 minibuffer-message-timeout nil)
99848db0
KH
755
756 ;; We must bypass input method while reading key. When a user type
757 ;; printable character, appropriate input method is turned on in
380866a2 758 ;; minibuffer to read multibyte characters.
99848db0
KH
759 (or isearch-input-method-local-p
760 (make-local-variable 'input-method-function))
761 (setq input-method-function nil)
762
99ae9e9f 763 (looking-at "")
292a8dff
RS
764 (setq isearch-window-configuration
765 (if isearch-slow-terminal-mode (current-window-configuration) nil))
70418205 766
18ce7555
RS
767 ;; Maybe make minibuffer frame visible and/or raise it.
768 (let ((frame (window-frame (minibuffer-window))))
360e0dd5
RS
769 (unless (memq (frame-live-p frame) '(nil t))
770 (unless (frame-visible-p frame)
771 (make-frame-visible frame))
772 (if minibuffer-auto-raise
773 (raise-frame frame))))
18ce7555 774
8e1cae6d 775 (setq isearch-mode " Isearch") ;; forward? regexp?
1cd3732c 776 (force-mode-line-update)
8e1cae6d
JB
777
778 (isearch-push-state)
779
c7955222 780 (setq overriding-terminal-local-map isearch-mode-map)
8e1cae6d
JB
781 (isearch-update)
782 (run-hooks 'isearch-mode-hook)
08200510 783
bfe2d334 784 (add-hook 'mouse-leave-buffer-hook 'isearch-done)
7e56ea04 785 (add-hook 'kbd-macro-termination-hook 'isearch-done)
6e5cd0ae 786
b48ca14f
JB
787 ;; isearch-mode can be made modal (in the sense of not returning to
788 ;; the calling function until searching is completed) by entering
08200510 789 ;; a recursive-edit and exiting it when done isearching.
130bf67c
RS
790 (if recursive-edit
791 (let ((isearch-recursive-edit t))
792 (recursive-edit)))
0daa17f3 793 isearch-success)
8e1cae6d
JB
794
795
8e1cae6d
JB
796;; Some high level utilities. Others below.
797
798(defun isearch-update ()
191f025a 799 ;; Called after each command to update the display.
4c01d4bd
RS
800 (if (and (null unread-command-events)
801 (null executing-kbd-macro))
8e1cae6d 802 (progn
c982ab21 803 (if (not (input-pending-p))
ac475d3a
JL
804 (if isearch-message-function
805 (funcall isearch-message-function)
806 (isearch-message)))
c982ab21 807 (if (and isearch-slow-terminal-mode
b48ca14f 808 (not (or isearch-small-window
c982ab21
GM
809 (pos-visible-in-window-p))))
810 (let ((found-point (point)))
811 (setq isearch-small-window t)
812 (move-to-window-line 0)
813 (let ((window-min-height 1))
814 (split-window nil (if (< search-slow-window-lines 0)
815 (1+ (- search-slow-window-lines))
816 (- (window-height)
817 (1+ search-slow-window-lines)))))
818 (if (< search-slow-window-lines 0)
819 (progn (vertical-motion (- 1 search-slow-window-lines))
820 (set-window-start (next-window) (point))
821 (set-window-hscroll (next-window)
822 (window-hscroll))
823 (set-window-hscroll (selected-window) 0))
824 (other-window 1))
ddbe3d5f
RS
825 (goto-char found-point))
826 ;; Keep same hscrolling as at the start of the search when possible
827 (let ((current-scroll (window-hscroll)))
828 (set-window-hscroll (selected-window) isearch-start-hscroll)
829 (unless (pos-visible-in-window-p)
830 (set-window-hscroll (selected-window) current-scroll))))
831 (if isearch-other-end
c982ab21
GM
832 (if (< isearch-other-end (point)) ; isearch-forward?
833 (isearch-highlight isearch-other-end (point))
834 (isearch-highlight (point) isearch-other-end))
4dbbcb46 835 (isearch-dehighlight))
c982ab21 836 ))
8e1cae6d
JB
837 (setq ;; quit-flag nil not for isearch-mode
838 isearch-adjusted nil
839 isearch-yank-flag nil)
f9114cec 840 (when isearch-lazy-highlight
d9dd1f33 841 (isearch-lazy-highlight-new-loop))
a5cc922e
KH
842 ;; We must prevent the point moving to the end of composition when a
843 ;; part of the composition has just been searched.
844 (setq disable-point-adjustment t))
8e1cae6d 845
0daa17f3 846(defun isearch-done (&optional nopush edit)
87e97673
RS
847 "Exit Isearch mode.
848For successful search, pass no args.
849For a failing search, NOPUSH is t.
850For going to the minibuffer to edit the search string,
851NOPUSH is t and EDIT is t."
852
00098b01 853 (if isearch-resume-in-command-history
6848c9f1
KS
854 (let ((command `(isearch-resume ,isearch-string ,isearch-regexp
855 ,isearch-word ,isearch-forward
856 ,isearch-message
857 ',isearch-case-fold-search)))
858 (unless (equal (car command-history) command)
859 (setq command-history (cons command command-history)))))
c40a4de1 860
bfe2d334 861 (remove-hook 'mouse-leave-buffer-hook 'isearch-done)
7e56ea04 862 (remove-hook 'kbd-macro-termination-hook 'isearch-done)
d196f58d
GM
863 (setq isearch-lazy-highlight-start nil)
864
8e1cae6d 865 ;; Called by all commands that terminate isearch-mode.
35a4d143 866 ;; If NOPUSH is non-nil, we don't push the string on the search ring.
c7955222 867 (setq overriding-terminal-local-map nil)
08200510 868 ;; (setq pre-command-hook isearch-old-pre-command-hook) ; for lemacs
ae1a21c6 869 (setq minibuffer-message-timeout isearch-original-minibuffer-message-timeout)
4dbbcb46 870 (isearch-dehighlight)
46fe9018 871 (lazy-highlight-cleanup lazy-highlight-cleanup)
08200510
RS
872 (let ((found-start (window-start (selected-window)))
873 (found-point (point)))
d8a4fc44
RS
874 (when isearch-window-configuration
875 (set-window-configuration isearch-window-configuration)
876 (if isearch-small-window
877 (goto-char found-point)
878 ;; set-window-configuration clobbers window-start; restore it.
879 ;; This has an annoying side effect of clearing the last_modiff
880 ;; field of the window, which can cause unwanted scrolling,
881 ;; so don't do it unless truly necessary.
882 (set-window-start (selected-window) found-start t))))
08200510
RS
883
884 (setq isearch-mode nil)
99848db0
KH
885 (if isearch-input-method-local-p
886 (setq input-method-function isearch-input-method-function)
887 (kill-local-variable 'input-method-function))
888
1cd3732c 889 (force-mode-line-update)
8e1cae6d 890
df01192b
RS
891 ;; If we ended in the middle of some intangible text,
892 ;; move to the further end of that intangible text.
893 (let ((after (if (eobp) nil
894 (get-text-property (point) 'intangible)))
895 (before (if (bobp) nil
896 (get-text-property (1- (point)) 'intangible))))
897 (when (and before after (eq before after))
898 (if isearch-forward
899 (goto-char (next-single-property-change (point) 'intangible))
900 (goto-char (previous-single-property-change (point) 'intangible)))))
901
35a4d143 902 (if (and (> (length isearch-string) 0) (not nopush))
8e1cae6d 903 ;; Update the ring data.
73d2bf95 904 (isearch-update-ring isearch-string isearch-regexp))
8e1cae6d 905
87e97673
RS
906 (let ((isearch-mode-end-hook-quit (and nopush (not edit))))
907 (run-hooks 'isearch-mode-end-hook))
071fdd66
JL
908
909 ;; If there was movement, mark the starting position.
4837b516 910 ;; Maybe should test difference between and set mark only if > threshold.
071fdd66
JL
911 (if (/= (point) isearch-opoint)
912 (or (and transient-mark-mode mark-active)
913 (progn
914 (push-mark isearch-opoint t)
915 (or executing-kbd-macro (> (minibuffer-depth) 0)
916 (message "Mark saved where search started")))))
917
0daa17f3 918 (and (not edit) isearch-recursive-edit (exit-recursive-edit)))
08200510 919
73d2bf95
RS
920(defun isearch-update-ring (string &optional regexp)
921 "Add STRING to the beginning of the search ring.
a2b7dcc7 922REGEXP if non-nil says use the regexp search ring."
77e5aef9
KS
923 (add-to-history
924 (if regexp 'regexp-search-ring 'search-ring)
925 string
926 (if regexp regexp-search-ring-max search-ring-max)))
73d2bf95 927
191f025a
SM
928;; Switching buffers should first terminate isearch-mode.
929;; ;; For Emacs 19, the frame switch event is handled.
930;; (defun isearch-switch-frame-handler ()
931;; (interactive) ;; Is this necessary?
932;; ;; First terminate isearch-mode.
933;; (isearch-done)
934;; (isearch-clean-overlays)
935;; (handle-switch-frame (car (cdr last-command-char))))
08200510 936
8e1cae6d 937\f
08e3de69
EZ
938;; The search status structure and stack.
939
1a699acf 940(defsubst isearch-string-state (frame)
08e3de69 941 "Return the search string in FRAME."
3eec7894 942 (aref frame 0))
1a699acf 943(defsubst isearch-message-state (frame)
08e3de69 944 "Return the search string to display to the user in FRAME."
3eec7894 945 (aref frame 1))
1a699acf 946(defsubst isearch-point-state (frame)
08e3de69 947 "Return the point in FRAME."
3eec7894 948 (aref frame 2))
1a699acf 949(defsubst isearch-success-state (frame)
08e3de69 950 "Return the success flag in FRAME."
3eec7894 951 (aref frame 3))
1a699acf 952(defsubst isearch-forward-state (frame)
08e3de69 953 "Return the searching-forward flag in FRAME."
3eec7894 954 (aref frame 4))
1a699acf 955(defsubst isearch-other-end-state (frame)
08e3de69 956 "Return the other end of the match in FRAME."
3eec7894 957 (aref frame 5))
1a699acf 958(defsubst isearch-word-state (frame)
08e3de69 959 "Return the search-by-word flag in FRAME."
3eec7894 960 (aref frame 6))
ba653a53 961(defsubst isearch-error-state (frame)
08e3de69 962 "Return the regexp error message in FRAME, or nil if its regexp is valid."
3eec7894 963 (aref frame 7))
1a699acf 964(defsubst isearch-wrapped-state (frame)
08e3de69 965 "Return the search-wrapped flag in FRAME."
3eec7894 966 (aref frame 8))
1a699acf 967(defsubst isearch-barrier-state (frame)
08e3de69 968 "Return the barrier value in FRAME."
3eec7894 969 (aref frame 9))
1a699acf 970(defsubst isearch-case-fold-search-state (frame)
08e3de69 971 "Return the case-folding flag in FRAME."
ba653a53 972 (aref frame 10))
6a18e4e7
JL
973(defsubst isearch-pop-fun-state (frame)
974 "Return the function restoring the mode-specific isearch state in FRAME."
ba653a53 975 (aref frame 11))
08e3de69
EZ
976
977(defun isearch-top-state ()
978 (let ((cmd (car isearch-cmds)))
1a699acf
JL
979 (setq isearch-string (isearch-string-state cmd)
980 isearch-message (isearch-message-state cmd)
981 isearch-success (isearch-success-state cmd)
982 isearch-forward (isearch-forward-state cmd)
983 isearch-other-end (isearch-other-end-state cmd)
984 isearch-word (isearch-word-state cmd)
ba653a53 985 isearch-error (isearch-error-state cmd)
1a699acf
JL
986 isearch-wrapped (isearch-wrapped-state cmd)
987 isearch-barrier (isearch-barrier-state cmd)
1a699acf 988 isearch-case-fold-search (isearch-case-fold-search-state cmd))
6a18e4e7
JL
989 (if (functionp (isearch-pop-fun-state cmd))
990 (funcall (isearch-pop-fun-state cmd) cmd))
1a699acf 991 (goto-char (isearch-point-state cmd))))
08e3de69
EZ
992
993(defun isearch-pop-state ()
994 (setq isearch-cmds (cdr isearch-cmds))
995 (isearch-top-state))
996
997(defun isearch-push-state ()
998 (setq isearch-cmds
999 (cons (vector isearch-string isearch-message (point)
1000 isearch-success isearch-forward isearch-other-end
1001 isearch-word
ba653a53
JL
1002 isearch-error isearch-wrapped isearch-barrier
1003 isearch-case-fold-search
6a18e4e7
JL
1004 (if isearch-push-state-function
1005 (funcall isearch-push-state-function)))
08e3de69
EZ
1006 isearch-cmds)))
1007
1008\f
8e1cae6d
JB
1009;; Commands active while inside of the isearch minor mode.
1010
1011(defun isearch-exit ()
1012 "Exit search normally.
1013However, if this is the first command after starting incremental
1014search and `search-nonincremental-instead' is non-nil, do a
08200510 1015nonincremental search instead via `isearch-edit-string'."
8e1cae6d 1016 (interactive)
b48ca14f 1017 (if (and search-nonincremental-instead
8e1cae6d 1018 (= 0 (length isearch-string)))
08200510
RS
1019 (let ((isearch-nonincremental t))
1020 (isearch-edit-string)))
0352b205
RS
1021 (isearch-done)
1022 (isearch-clean-overlays))
8e1cae6d
JB
1023
1024
1025(defun isearch-edit-string ()
08200510
RS
1026 "Edit the search string in the minibuffer.
1027The following additional command keys are active while editing.
1028\\<minibuffer-local-isearch-map>
1029\\[exit-minibuffer] to resume incremental searching with the edited string.
1030\\[isearch-nonincremental-exit-minibuffer] to do one nonincremental search.
1031\\[isearch-forward-exit-minibuffer] to resume isearching forward.
8eb40e74 1032\\[isearch-reverse-exit-minibuffer] to resume isearching backward.
08200510 1033\\[isearch-complete-edit] to complete the search string using the search ring.
8eb40e74 1034\\<isearch-mode-map>
74820eb5 1035If first char entered is \\[isearch-yank-word-or-char], then do word search instead."
08200510
RS
1036
1037 ;; This code is very hairy for several reasons, explained in the code.
1038 ;; Mainly, isearch-mode must be terminated while editing and then restarted.
1039 ;; If there were a way to catch any change of buffer from the minibuffer,
1040 ;; this could be simplified greatly.
eb8c3be9 1041 ;; Editing doesn't back up the search point. Should it?
8e1cae6d 1042 (interactive)
08200510 1043 (condition-case err
e900ced4
RS
1044 (progn
1045 (let ((isearch-nonincremental isearch-nonincremental)
1046
1047 ;; Locally bind all isearch global variables to protect them
1048 ;; from recursive isearching.
1049 ;; isearch-string -message and -forward are not bound
1050 ;; so they may be changed. Instead, save the values.
1051 (isearch-new-string isearch-string)
1052 (isearch-new-message isearch-message)
1053 (isearch-new-forward isearch-forward)
1054 (isearch-new-word isearch-word)
1055
1056 (isearch-regexp isearch-regexp)
1057 (isearch-op-fun isearch-op-fun)
1058 (isearch-cmds isearch-cmds)
1059 (isearch-success isearch-success)
1060 (isearch-wrapped isearch-wrapped)
1061 (isearch-barrier isearch-barrier)
1062 (isearch-adjusted isearch-adjusted)
1063 (isearch-yank-flag isearch-yank-flag)
ba653a53 1064 (isearch-error isearch-error)
e900ced4
RS
1065 ;;; Don't bind this. We want isearch-search, below, to set it.
1066 ;;; And the old value won't matter after that.
1067 ;;; (isearch-other-end isearch-other-end)
1068 ;;; Perhaps some of these other variables should be bound for a
1069 ;;; shorter period, ending before the next isearch-search.
1070 ;;; But there doesn't seem to be a real bug, so let's not risk it now.
1071 (isearch-opoint isearch-opoint)
1072 (isearch-slow-terminal-mode isearch-slow-terminal-mode)
1073 (isearch-small-window isearch-small-window)
1074 (isearch-recursive-edit isearch-recursive-edit)
1075 ;; Save current configuration so we can restore it here.
1076 (isearch-window-configuration (current-window-configuration))
ae1a21c6
MB
1077
1078 ;; Temporarily restore `minibuffer-message-timeout'.
1079 (minibuffer-message-timeout
1080 isearch-original-minibuffer-message-timeout)
1081 (isearch-original-minibuffer-message-timeout
1082 isearch-original-minibuffer-message-timeout)
02b99a17 1083 old-point old-other-end)
e900ced4
RS
1084
1085 ;; Actually terminate isearching until editing is done.
b48ca14f 1086 ;; This is so that the user can do anything without failure,
e900ced4
RS
1087 ;; like switch buffers and start another isearch, and return.
1088 (condition-case err
1089 (isearch-done t t)
1090 (exit nil)) ; was recursive editing
1091
02b99a17
JL
1092 ;; Save old point and isearch-other-end before reading from minibuffer
1093 ;; that can change their values.
1094 (setq old-point (point) old-other-end isearch-other-end)
1095
e900ced4
RS
1096 (isearch-message) ;; for read-char
1097 (unwind-protect
b48ca14f 1098 (let* (;; Why does following read-char echo?
e900ced4
RS
1099 ;;(echo-keystrokes 0) ;; not needed with above message
1100 (e (let ((cursor-in-echo-area t))
1101 (read-event)))
1102 ;; Binding minibuffer-history-symbol to nil is a work-around
1103 ;; for some incompatibility with gmhist.
1104 (minibuffer-history-symbol)
1105 (message-log-max nil))
1106 ;; If the first character the user types when we prompt them
1107 ;; for a string is the yank-word character, then go into
1108 ;; word-search mode. Otherwise unread that character and
1109 ;; read a key the normal way.
1110 ;; Word search does not apply (yet) to regexp searches,
1111 ;; no check is made here.
8a26c165 1112 (message "%s" (isearch-message-prefix nil nil t))
88715f05
RS
1113 (if (memq (lookup-key isearch-mode-map (vector e))
1114 '(isearch-yank-word
1115 isearch-yank-word-or-char))
e900ced4
RS
1116 (setq isearch-word t;; so message-prefix is right
1117 isearch-new-word t)
1118 (cancel-kbd-macro-events)
1119 (isearch-unread e))
1120 (setq cursor-in-echo-area nil)
1121 (setq isearch-new-string
e5feeb31
SM
1122 (read-from-minibuffer
1123 (isearch-message-prefix nil nil isearch-nonincremental)
1124 isearch-string
1125 minibuffer-local-isearch-map nil
363de02e
JL
1126 (if isearch-regexp
1127 (cons 'regexp-search-ring
1128 (1+ (or regexp-search-ring-yank-pointer -1)))
1129 (cons 'search-ring
1130 (1+ (or search-ring-yank-pointer -1))))
e5feeb31 1131 nil t)
e900ced4
RS
1132 isearch-new-message
1133 (mapconcat 'isearch-text-char-description
1134 isearch-new-string "")))
02b99a17
JL
1135
1136 ;; Set point at the start (end) of old match if forward (backward),
1137 ;; so after exiting minibuffer isearch resumes at the start (end)
1138 ;; of this match and can find it again.
1139 (if (and old-other-end (eq old-point (point))
1140 (eq isearch-forward isearch-new-forward))
1141 (goto-char old-other-end))
1142
e900ced4 1143 ;; Always resume isearching by restarting it.
b48ca14f
JB
1144 (isearch-mode isearch-forward
1145 isearch-regexp
1146 isearch-op-fun
e900ced4
RS
1147 nil
1148 isearch-word)
1149
1150 ;; Copy new local values to isearch globals
1151 (setq isearch-string isearch-new-string
1152 isearch-message isearch-new-message
1153 isearch-forward isearch-new-forward
1154 isearch-word isearch-new-word))
1155
1156 ;; Empty isearch-string means use default.
1157 (if (= 0 (length isearch-string))
1158 (setq isearch-string (or (car (if isearch-regexp
1159 regexp-search-ring
1160 search-ring))
8cc3c821
RS
1161 "")
1162
1163 isearch-message
1164 (mapconcat 'isearch-text-char-description
1165 isearch-string ""))
e900ced4
RS
1166 ;; This used to set the last search string,
1167 ;; but I think it is not right to do that here.
1168 ;; Only the string actually used should be saved.
1169 ))
1170
a71a98cf
JL
1171 ;; This used to push the state as of before this C-s, but it adds
1172 ;; an inconsistent state where part of variables are from the
1173 ;; previous search (e.g. `isearch-success'), and part of variables
1174 ;; are just entered from the minibuffer (e.g. `isearch-string').
1175 ;; (isearch-push-state)
08200510
RS
1176
1177 ;; Reinvoke the pending search.
08200510 1178 (isearch-search)
a71a98cf 1179 (isearch-push-state) ; this pushes the correct state
08200510 1180 (isearch-update)
b48ca14f 1181 (if isearch-nonincremental
08200510
RS
1182 (progn
1183 ;; (sit-for 1) ;; needed if isearch-done does: (message "")
40c7f256
RS
1184 (isearch-done)
1185 ;; The search done message is confusing when the string
1186 ;; is empty, so erase it.
1187 (if (equal isearch-string "")
1188 (message "")))))
8e1cae6d 1189
08200510
RS
1190 (quit ; handle abort-recursive-edit
1191 (isearch-abort) ;; outside of let to restore outside global values
1192 )))
1193
1194(defun isearch-nonincremental-exit-minibuffer ()
1195 (interactive)
1196 (setq isearch-nonincremental t)
1197 (exit-minibuffer))
1198
1199(defun isearch-forward-exit-minibuffer ()
1200 (interactive)
1201 (setq isearch-new-forward t)
1202 (exit-minibuffer))
8e1cae6d 1203
08200510 1204(defun isearch-reverse-exit-minibuffer ()
8e1cae6d 1205 (interactive)
08200510
RS
1206 (setq isearch-new-forward nil)
1207 (exit-minibuffer))
1208
19993c54
RS
1209(defun isearch-cancel ()
1210 "Terminate the search and go back to the starting point."
1211 (interactive)
6a18e4e7
JL
1212 (if (functionp (isearch-pop-fun-state (car (last isearch-cmds))))
1213 (funcall (isearch-pop-fun-state (car (last isearch-cmds)))
1214 (car (last isearch-cmds))))
19993c54 1215 (goto-char isearch-opoint)
6a18e4e7 1216 (isearch-done t) ; exit isearch
0352b205 1217 (isearch-clean-overlays)
6a18e4e7 1218 (signal 'quit nil)) ; and pass on quit signal
08200510
RS
1219
1220(defun isearch-abort ()
b7852303 1221 "Abort incremental search mode if searching is successful, signaling quit.
08200510 1222Otherwise, revert to previous successful search and continue searching.
b7852303 1223Use `isearch-exit' to quit without signaling."
08200510 1224 (interactive)
eb8c3be9 1225;; (ding) signal instead below, if quitting
8e1cae6d
JB
1226 (discard-input)
1227 (if isearch-success
1228 ;; If search is successful, move back to starting point
1229 ;; and really do quit.
6a18e4e7
JL
1230 (progn
1231 (setq isearch-success nil)
1232 (isearch-cancel))
925a67ca
RS
1233 ;; If search is failing, or has an incomplete regexp,
1234 ;; rub out until it is once more successful.
ba653a53 1235 (while (or (not isearch-success) isearch-error)
925a67ca 1236 (isearch-pop-state))
8e1cae6d
JB
1237 (isearch-update)))
1238
8e1cae6d
JB
1239(defun isearch-repeat (direction)
1240 ;; Utility for isearch-repeat-forward and -backward.
1241 (if (eq isearch-forward (eq direction 'forward))
1242 ;; C-s in forward or C-r in reverse.
1243 (if (equal isearch-string "")
1244 ;; If search string is empty, use last one.
ece75c05
JL
1245 (if (null (if isearch-regexp regexp-search-ring search-ring))
1246 (setq isearch-error "No previous search string")
1247 (setq isearch-string
1248 (if isearch-regexp
1249 (car regexp-search-ring)
1250 (car search-ring))
1251 isearch-message
1252 (mapconcat 'isearch-text-char-description
1253 isearch-string "")
1254 isearch-case-fold-search isearch-last-case-fold-search))
8e1cae6d
JB
1255 ;; If already have what to search for, repeat it.
1256 (or isearch-success
02b2f510 1257 (progn
ba653a53
JL
1258 ;; Set isearch-wrapped before calling isearch-wrap-function
1259 (setq isearch-wrapped t)
6a18e4e7
JL
1260 (if isearch-wrap-function
1261 (funcall isearch-wrap-function)
ba653a53 1262 (goto-char (if isearch-forward (point-min) (point-max)))))))
8e1cae6d 1263 ;; C-s in reverse or C-r in forward, change direction.
f4c49513
RS
1264 (setq isearch-forward (not isearch-forward)
1265 isearch-success t))
8e1cae6d
JB
1266
1267 (setq isearch-barrier (point)) ; For subsequent \| if regexp.
6fefdc4b
RS
1268
1269 (if (equal isearch-string "")
1270 (setq isearch-success t)
512bfd85
RS
1271 (if (and isearch-success
1272 (equal (point) isearch-other-end)
99ae9e9f 1273 (not isearch-just-started))
8e1cae6d
JB
1274 ;; If repeating a search that found
1275 ;; an empty string, ensure we advance.
6fefdc4b
RS
1276 (if (if isearch-forward (eobp) (bobp))
1277 ;; If there's nowhere to advance to, fail (and wrap next time).
1278 (progn
1279 (setq isearch-success nil)
1280 (ding))
1281 (forward-char (if isearch-forward 1 -1))
1282 (isearch-search))
1283 (isearch-search)))
1284
8e1cae6d
JB
1285 (isearch-push-state)
1286 (isearch-update))
1287
1288(defun isearch-repeat-forward ()
1289 "Repeat incremental search forwards."
1290 (interactive)
1291 (isearch-repeat 'forward))
1292
1293(defun isearch-repeat-backward ()
1294 "Repeat incremental search backwards."
1295 (interactive)
1296 (isearch-repeat 'backward))
1297
1298(defun isearch-toggle-regexp ()
1299 "Toggle regexp searching on or off."
1300 ;; The status stack is left unchanged.
1301 (interactive)
1302 (setq isearch-regexp (not isearch-regexp))
08200510 1303 (if isearch-regexp (setq isearch-word nil))
d85519bb 1304 (setq isearch-success t isearch-adjusted t)
8e1cae6d
JB
1305 (isearch-update))
1306
4453091d
RS
1307(defun isearch-toggle-case-fold ()
1308 "Toggle case folding in searching on or off."
1309 (interactive)
1310 (setq isearch-case-fold-search
1311 (if isearch-case-fold-search nil 'yes))
a56687f1
KH
1312 (let ((message-log-max nil))
1313 (message "%s%s [case %ssensitive]"
1314 (isearch-message-prefix nil nil isearch-nonincremental)
1315 isearch-message
1316 (if isearch-case-fold-search "in" "")))
d85519bb 1317 (setq isearch-success t isearch-adjusted t)
4453091d
RS
1318 (sit-for 1)
1319 (isearch-update))
1320
d85519bb 1321(defun isearch-query-replace (&optional regexp-flag)
6e3057bb 1322 "Start `query-replace' with string to replace from last search string."
74820eb5 1323 (interactive)
81e898ea 1324 (barf-if-buffer-read-only)
d85519bb 1325 (if regexp-flag (setq isearch-regexp t))
6e3057bb
JL
1326 (let ((case-fold-search isearch-case-fold-search)
1327 ;; set `search-upper-case' to nil to not call
1328 ;; `isearch-no-upper-case-p' in `perform-replace'
1329 (search-upper-case nil))
74820eb5
JL
1330 (isearch-done)
1331 (isearch-clean-overlays)
e7e4ea21
JL
1332 (if (and isearch-other-end
1333 (< isearch-other-end (point))
d85519bb 1334 (not (and transient-mark-mode mark-active
fa81f010 1335 (< (mark) (point)))))
d85519bb
JL
1336 (goto-char isearch-other-end))
1337 (set query-replace-from-history-variable
1338 (cons isearch-string
1339 (symbol-value query-replace-from-history-variable)))
81e898ea
SM
1340 (perform-replace
1341 isearch-string
d85519bb
JL
1342 (query-replace-read-to
1343 isearch-string
1344 (if isearch-regexp "Query replace regexp" "Query replace")
1345 isearch-regexp)
1346 t isearch-regexp isearch-word nil nil
1347 (if (and transient-mark-mode mark-active) (region-beginning))
1348 (if (and transient-mark-mode mark-active) (region-end)))))
74820eb5
JL
1349
1350(defun isearch-query-replace-regexp ()
6e3057bb 1351 "Start `query-replace-regexp' with string to replace from last search string."
74820eb5 1352 (interactive)
d85519bb 1353 (isearch-query-replace t))
74820eb5 1354
6e3057bb
JL
1355(defun isearch-occur (regexp &optional nlines)
1356 "Run `occur' with regexp to search from the current search string.
1357Interactively, REGEXP is the current search regexp or a quoted search
1358string. NLINES has the same meaning as in `occur'."
1359 (interactive
1360 (list
1361 (if isearch-regexp isearch-string (regexp-quote isearch-string))
1362 (if current-prefix-arg (prefix-numeric-value current-prefix-arg))))
1363 (let ((case-fold-search isearch-case-fold-search)
1364 ;; set `search-upper-case' to nil to not call
1365 ;; `isearch-no-upper-case-p' in `occur-1'
1366 (search-upper-case nil))
1367 (occur regexp nlines)))
1368
74820eb5 1369\f
8e1cae6d 1370(defun isearch-delete-char ()
d6b8a1c0 1371 "Discard last input item and move point back.
8e1cae6d
JB
1372If no previous match was done, just beep."
1373 (interactive)
1374 (if (null (cdr isearch-cmds))
1375 (ding)
1376 (isearch-pop-state))
1377 (isearch-update))
1378
74820eb5
JL
1379(defun isearch-del-char (&optional arg)
1380 "Delete character from end of search string and search again.
1381If search string is empty, just beep."
1382 (interactive "p")
1383 (if (= 0 (length isearch-string))
35904fd3 1384 (ding)
74820eb5 1385 (setq isearch-string (substring isearch-string 0 (- (or arg 1)))
35904fd3 1386 isearch-message (mapconcat 'isearch-text-char-description
02b99a17
JL
1387 isearch-string "")))
1388 ;; Use the isearch-other-end as new starting point to be able
1389 ;; to find the remaining part of the search string again.
1390 (if isearch-other-end (goto-char isearch-other-end))
1391 (isearch-search)
1392 (isearch-push-state)
1393 (isearch-update))
8e1cae6d 1394
9cf081fa
KH
1395(defun isearch-yank-string (string)
1396 "Pull STRING into search string."
1397 ;; Downcase the string if not supposed to case-fold yanked strings.
1398 (if (and isearch-case-fold-search
1399 (eq 'not-yanks search-upper-case))
1400 (setq string (downcase string)))
1401 (if isearch-regexp (setq string (regexp-quote string)))
1402 (setq isearch-string (concat isearch-string string)
1403 isearch-message
1404 (concat isearch-message
1405 (mapconcat 'isearch-text-char-description
1406 string ""))
1407 ;; Don't move cursor in reverse search.
1408 isearch-yank-flag t)
8e1cae6d
JB
1409 (isearch-search-and-update))
1410
30d47262
RS
1411(defun isearch-yank-kill ()
1412 "Pull string from kill ring into search string."
1413 (interactive)
9cf081fa
KH
1414 (isearch-yank-string (current-kill 0)))
1415
1416(defun isearch-yank-x-selection ()
117132a6 1417 "Pull current X selection into search string."
9cf081fa
KH
1418 (interactive)
1419 (isearch-yank-string (x-get-selection)))
8e1cae6d 1420
e4af1426 1421
191f025a 1422(defun isearch-mouse-2 (click)
e4af1426 1423 "Handle mouse-2 in Isearch mode.
117132a6 1424For a click in the echo area, invoke `isearch-yank-x-selection'.
f3b5dd74
DK
1425Otherwise invoke whatever the calling mouse-2 command sequence
1426is bound to outside of Isearch."
191f025a 1427 (interactive "e")
e4af1426
GM
1428 (let* ((w (posn-window (event-start click)))
1429 (overriding-terminal-local-map nil)
f3b5dd74 1430 (binding (key-binding (this-command-keys-vector) t)))
117132a6
DL
1431 (if (and (window-minibuffer-p w)
1432 (not (minibuffer-window-active-p w))) ; in echo area
1433 (isearch-yank-x-selection)
cd59ea72 1434 (when (functionp binding)
191f025a 1435 (call-interactively binding)))))
e4af1426 1436
29e53a0a
KF
1437(defun isearch-yank-internal (jumpform)
1438 "Pull the text from point to the point reached by JUMPFORM.
1439JUMPFORM is a lambda expression that takes no arguments and returns a
1440buffer position, possibly having moved point to that position. For
1441example, it might move point forward by a word and return point, or it
1442might return the position of the end of the line."
9cf081fa
KH
1443 (isearch-yank-string
1444 (save-excursion
1445 (and (not isearch-forward) isearch-other-end
1446 (goto-char isearch-other-end))
29e53a0a
KF
1447 (buffer-substring-no-properties (point) (funcall jumpform)))))
1448
74820eb5
JL
1449(defun isearch-yank-char-in-minibuffer (&optional arg)
1450 "Pull next character from buffer into end of search string in minibuffer."
1451 (interactive "p")
1452 (if (eobp)
1453 (insert
1454 (save-excursion
1455 (set-buffer (cadr (buffer-list)))
1456 (buffer-substring-no-properties
1457 (point) (progn (forward-char arg) (point)))))
1458 (forward-char arg)))
1459
1460(defun isearch-yank-char (&optional arg)
35904fd3 1461 "Pull next character from buffer into search string."
74820eb5
JL
1462 (interactive "p")
1463 (isearch-yank-internal (lambda () (forward-char arg) (point))))
29e53a0a 1464
868bf43a
RS
1465(defun isearch-yank-word-or-char ()
1466 "Pull next character or word from buffer into search string."
1467 (interactive)
21d90805 1468 (isearch-yank-internal
b48ca14f 1469 (lambda ()
21d90805
KF
1470 (if (or (= (char-syntax (or (char-after) 0)) ?w)
1471 (= (char-syntax (or (char-after (1+ (point))) 0)) ?w))
1472 (forward-word 1)
1473 (forward-char 1)) (point))))
868bf43a 1474
29e53a0a
KF
1475(defun isearch-yank-word ()
1476 "Pull next word from buffer into search string."
1477 (interactive)
1478 (isearch-yank-internal (lambda () (forward-word 1) (point))))
8e1cae6d
JB
1479
1480(defun isearch-yank-line ()
1481 "Pull rest of line from buffer into search string."
1482 (interactive)
a1883913 1483 (isearch-yank-internal
933f8467
RF
1484 (lambda () (let ((inhibit-field-text-motion t))
1485 (line-end-position (if (eolp) 2 1))))))
8e1cae6d
JB
1486
1487(defun isearch-search-and-update ()
1488 ;; Do the search and update the display.
191f025a 1489 (when (or isearch-success
35904fd3
JL
1490 ;; Unsuccessful regexp search may become successful by
1491 ;; addition of characters which make isearch-string valid
cd59ea72
SM
1492 isearch-regexp
1493 ;; If the string was found but was completely invisible,
1494 ;; it might now be partly visible, so try again.
1495 (prog1 isearch-hidden (setq isearch-hidden nil)))
8e1cae6d
JB
1496 ;; In reverse search, adding stuff at
1497 ;; the end may cause zero or many more chars to be
1498 ;; matched, in the string following point.
1499 ;; Allow all those possibilities without moving point as
1500 ;; long as the match does not extend past search origin.
1501 (if (and (not isearch-forward) (not isearch-adjusted)
1502 (condition-case ()
99ae9e9f 1503 (let ((case-fold-search isearch-case-fold-search))
ec0a2f45
KH
1504 (if (and (eq case-fold-search t) search-upper-case)
1505 (setq case-fold-search
1506 (isearch-no-upper-case-p isearch-string isearch-regexp)))
99ae9e9f
KH
1507 (looking-at (if isearch-regexp isearch-string
1508 (regexp-quote isearch-string))))
8e1cae6d 1509 (error nil))
bd6a8414 1510 (or isearch-yank-flag
191f025a 1511 (<= (match-end 0)
bd6a8414 1512 (min isearch-opoint isearch-barrier))))
d64b1d96 1513 (progn
191f025a 1514 (setq isearch-success t
ba653a53 1515 isearch-error nil
d64b1d96
RS
1516 isearch-other-end (match-end 0))
1517 (if (and (eq isearch-case-fold-search t) search-upper-case)
1518 (setq isearch-case-fold-search
1519 (isearch-no-upper-case-p isearch-string isearch-regexp))))
8e1cae6d
JB
1520 ;; Not regexp, not reverse, or no match at point.
1521 (if (and isearch-other-end (not isearch-adjusted))
1522 (goto-char (if isearch-forward isearch-other-end
191f025a
SM
1523 (min isearch-opoint
1524 isearch-barrier
8e1cae6d
JB
1525 (1+ isearch-other-end)))))
1526 (isearch-search)
1527 ))
1528 (isearch-push-state)
1529 (if isearch-op-fun (funcall isearch-op-fun))
1530 (isearch-update))
1531
1532
08e3de69 1533;; *, ?, }, and | chars can make a regexp more liberal.
08200510 1534;; They can make a regexp match sooner or make it succeed instead of failing.
8e1cae6d
JB
1535;; So go back to place last successful search started
1536;; or to the last ^S/^R (barrier), whichever is nearer.
08200510 1537;; + needs no special handling because the string must match at least once.
8e1cae6d 1538
08e3de69
EZ
1539(defun isearch-backslash (str)
1540 "Return t if STR ends in an odd number of backslashes."
1541 (= (mod (- (length str) (string-match "\\\\*\\'" str)) 2) 1))
1542
1543(defun isearch-fallback (want-backslash &optional allow-invalid to-barrier)
1544 "Return point to previous successful match to allow regexp liberalization.
1545\\<isearch-mode-map>
1546Respects \\[isearch-repeat-forward] and \\[isearch-repeat-backward] by
1547stopping at `isearch-barrier' as needed.
1548
6f2df0f4
JL
1549Do nothing if a backslash is escaping the liberalizing character.
1550If WANT-BACKSLASH is non-nil, invert this behavior (for \\} and \\|).
08e3de69 1551
6f2df0f4
JL
1552Do nothing if regexp has recently been invalid unless optional
1553ALLOW-INVALID non-nil.
08e3de69 1554
6f2df0f4
JL
1555If optional TO-BARRIER non-nil, ignore previous matches and go exactly
1556to the barrier."
08e3de69
EZ
1557 ;; (eq (not a) (not b)) makes all non-nil values equivalent
1558 (when (and isearch-regexp (eq (not (isearch-backslash isearch-string))
1559 (not want-backslash))
1560 ;; We have to check 2 stack frames because the last might be
1561 ;; invalid just because of a backslash.
ba653a53
JL
1562 (or (not isearch-error)
1563 (not (isearch-error-state (cadr isearch-cmds)))
08e3de69
EZ
1564 allow-invalid))
1565 (if to-barrier
1566 (progn (goto-char isearch-barrier)
1567 (setq isearch-adjusted t))
1568 (let* ((stack isearch-cmds)
1569 (previous (cdr stack)) ; lookbelow in the stack
1570 (frame (car stack)))
1571 ;; Walk down the stack looking for a valid regexp (as of course only
1572 ;; they can be the previous successful match); this conveniently
1573 ;; removes all bracket-sets and groups that might be in the way, as
1574 ;; well as partial \{\} constructs that the code below leaves behind.
1575 ;; Also skip over postfix operators -- though horrid,
9b9a4122 1576 ;; 'ab?\{5,6\}+\{1,2\}*' is perfectly valid.
08e3de69 1577 (while (and previous
ba653a53 1578 (or (isearch-error-state frame)
1a699acf 1579 (let* ((string (isearch-string-state frame))
08e3de69
EZ
1580 (lchar (aref string (1- (length string)))))
1581 ;; The operators aren't always operators; check
1582 ;; backslashes. This doesn't handle the case of
1583 ;; operators at the beginning of the regexp not
1584 ;; being special, but then we should fall back to
1585 ;; the barrier anyway because it's all optional.
1586 (if (isearch-backslash
1a699acf 1587 (isearch-string-state (car previous)))
08e3de69
EZ
1588 (eq lchar ?\})
1589 (memq lchar '(?* ?? ?+))))))
1590 (setq stack previous previous (cdr previous) frame (car stack)))
1591 (when stack
1592 ;; `stack' now refers the most recent valid regexp that is not at
1593 ;; all optional in its last term. Now dig one level deeper and find
1594 ;; what matched before that.
5a1f9fcf
JL
1595 (let ((last-other-end
1596 (or (and (car previous)
1597 (isearch-other-end-state (car previous)))
1598 isearch-barrier)))
08e3de69
EZ
1599 (goto-char (if isearch-forward
1600 (max last-other-end isearch-barrier)
1601 (min last-other-end isearch-barrier)))
6f2df0f4 1602 (setq isearch-adjusted t)))))))
8e1cae6d 1603
6b61353c
KH
1604(defun isearch-unread-key-sequence (keylist)
1605 "Unread the given key-sequence KEYLIST.
1606Scroll-bar or mode-line events are processed appropriately."
1607 (cancel-kbd-macro-events)
1608 (apply 'isearch-unread keylist)
1609 ;; If the event was a scroll-bar or mode-line click, the event will have
1610 ;; been prefixed by a symbol such as vertical-scroll-bar. We must remove
1611 ;; it here, because this symbol will be attached to the event again next
1612 ;; time it gets read by read-key-sequence.
1613 ;;
1614 ;; (Old comment from isearch-other-meta-char: "Note that we don't have to
1615 ;; modify the event anymore in 21 because read_key_sequence no longer
1616 ;; modifies events to produce fake prefix keys.")
1617 (if (and (> (length keylist) 1)
1618 (symbolp (car keylist))
1619 (listp (cadr keylist))
1620 (not (numberp (posn-point
1621 (event-start (cadr keylist) )))))
1622 (pop unread-command-events)))
1623
1624;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1625;; scrolling within Isearch mode. Alan Mackenzie (acm@muc.de), 2003/2/24
1626;;
1627;; The idea here is that certain vertical scrolling commands (like C-l
1628;; `recenter') should be usable WITHIN Isearch mode. For a command to be
1629;; suitable, it must NOT alter the buffer, swap to another buffer or frame,
1630;; tamper with isearch's state, or move point. It is unacceptable for the
1631;; search string to be scrolled out of the current window. If a command
1632;; attempts this, we scroll the text back again.
1633;;
1634;; We implement this feature with a property called `isearch-scroll'.
1635;; If a command's symbol has the value t for this property it is a
1636;; scrolling command. The feature needs to be enabled by setting the
1637;; customizable variable `isearch-allow-scroll' to a non-nil value.
1638;;
1639;; The universal argument commands (e.g. C-u) in simple.el are marked
1640;; as scrolling commands, and isearch.el has been amended to allow
1641;; prefix arguments to be passed through to scrolling commands. Thus
1642;; M-0 C-l will scroll point to the top of the window.
1643;;
1644;; Horizontal scrolling commands are currently not catered for.
1645;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1646
1647;; Set the isearch-scroll property on some standard functions:
1648;; Scroll-bar functions:
1649(if (fboundp 'scroll-bar-toolkit-scroll)
1650 (put 'scroll-bar-toolkit-scroll 'isearch-scroll t))
1651(if (fboundp 'mac-handle-scroll-bar-event)
1652 (put 'mac-handle-scroll-bar-event 'isearch-scroll t))
1653(if (fboundp 'w32-handle-scroll-bar-event)
1654 (put 'w32-handle-scroll-bar-event 'isearch-scroll t))
1655
1656;; Commands which scroll the window:
1657(put 'recenter 'isearch-scroll t)
1658(put 'reposition-window 'isearch-scroll t)
1659(put 'scroll-up 'isearch-scroll t)
1660(put 'scroll-down 'isearch-scroll t)
1661
1662;; Commands which act on the other window
1663(put 'list-buffers 'isearch-scroll t)
1664(put 'scroll-other-window 'isearch-scroll t)
1665(put 'scroll-other-window-down 'isearch-scroll t)
1666(put 'beginning-of-buffer-other-window 'isearch-scroll t)
1667(put 'end-of-buffer-other-window 'isearch-scroll t)
1668
1669;; Commands which change the window layout
1670(put 'delete-other-windows 'isearch-scroll t)
1671(put 'balance-windows 'isearch-scroll t)
1672(put 'split-window-vertically 'isearch-scroll t)
7f55d3b7 1673(put 'split-window-horizontally 'isearch-scroll t)
6b61353c
KH
1674(put 'enlarge-window 'isearch-scroll t)
1675
1676;; Universal argument commands
1677(put 'universal-argument 'isearch-scroll t)
1678(put 'negative-argument 'isearch-scroll t)
1679(put 'digit-argument 'isearch-scroll t)
1680
1681(defcustom isearch-allow-scroll nil
1682 "If non-nil, scrolling commands are allowed during incremental search."
1683 :type 'boolean
1684 :group 'isearch)
1685
1686(defun isearch-string-out-of-window (isearch-point)
1687 "Test whether the search string is currently outside of the window.
1688Return nil if it's completely visible, or if point is visible,
1689together with as much of the search string as will fit; the symbol
1690`above' if we need to scroll the text downwards; the symbol `below',
1691if upwards."
1692 (let ((w-start (window-start))
1693 (w-end (window-end nil t))
1694 (w-L1 (save-excursion (move-to-window-line 1) (point)))
1695 (w-L-1 (save-excursion (move-to-window-line -1) (point)))
1696 start end) ; start and end of search string in buffer
1697 (if isearch-forward
1698 (setq end isearch-point start (or isearch-other-end isearch-point))
1699 (setq start isearch-point end (or isearch-other-end isearch-point)))
1700 (cond ((or (and (>= start w-start) (<= end w-end))
1701 (if isearch-forward
1702 (and (>= isearch-point w-L-1) (< isearch-point w-end)) ; point on Line -1
1703 (and (>= isearch-point w-start) (< isearch-point w-L1)))) ; point on Line 0
1704 nil)
1705 ((and (< start w-start)
1706 (< isearch-point w-L-1))
1707 'above)
1708 (t 'below))))
1709
1710(defun isearch-back-into-window (above isearch-point)
1711 "Scroll the window to bring the search string back into view.
1712Restore point to ISEARCH-POINT in the process. ABOVE is t when the
1713search string is above the top of the window, nil when it is beneath
1714the bottom."
1715 (let (start end)
1716 (if isearch-forward
1717 (setq end isearch-point start (or isearch-other-end isearch-point))
1718 (setq start isearch-point end (or isearch-other-end isearch-point)))
1719 (if above
1720 (progn
1721 (goto-char start)
1722 (recenter 0)
1723 (when (>= isearch-point (window-end nil t))
1724 (goto-char isearch-point)
1725 (recenter -1)))
1726 (goto-char end)
1727 (recenter -1)
1728 (when (< isearch-point (window-start))
1729 (goto-char isearch-point)
1730 (recenter 0))))
1731 (goto-char isearch-point))
1732
1733(defun isearch-reread-key-sequence-naturally (keylist)
1734 "Reread key sequence KEYLIST with Isearch mode's keymap deactivated.
1735Return the key sequence as a string/vector."
1736 (isearch-unread-key-sequence keylist)
1737 (let (overriding-terminal-local-map)
1738 (read-key-sequence nil))) ; This will go through function-key-map, if nec.
1739
1740(defun isearch-lookup-scroll-key (key-seq)
1741 "If KEY-SEQ is bound to a scrolling command, return it as a symbol.
1742Otherwise return nil."
1743 (let* ((overriding-terminal-local-map nil)
1744 (binding (key-binding key-seq)))
1745 (and binding (symbolp binding) (commandp binding)
1746 (eq (get binding 'isearch-scroll) t)
1747 binding)))
8e1cae6d 1748
b457cc3b 1749(defalias 'isearch-other-control-char 'isearch-other-meta-char)
8e1cae6d 1750
6b61353c
KH
1751(defun isearch-other-meta-char (&optional arg)
1752 "Process a miscellaneous key sequence in Isearch mode.
1753
1754Try to convert the current key-sequence to something usable in Isearch
1755mode, either by converting it with `function-key-map', downcasing a
1756key with C-<upper case>, or finding a \"scrolling command\" bound to
1757it. \(In the last case, we may have to read more events.) If so,
1758either unread the converted sequence or execute the command.
1759
1760Otherwise, if `search-exit-option' is non-nil (the default) unread the
1761key-sequence and exit the search normally. If it is the symbol
1762`edit', the search string is edited in the minibuffer and the meta
1763character is unread so that it applies to editing the string.
1764
1765ARG is the prefix argument. It will be transmitted through to the
1766scrolling command or to the command whose key-sequence exits
1767Isearch mode."
1768 (interactive "P")
1769 (let* ((key (if current-prefix-arg ; not nec the same as ARG
1770 (substring (this-command-keys) universal-argument-num-events)
1771 (this-command-keys)))
c6431f12 1772 (main-event (aref key 0))
6b61353c
KH
1773 (keylist (listify-key-sequence key))
1774 scroll-command isearch-point)
24b5caec 1775 (cond ((and (= (length key) 1)
c40bb1ba 1776 (let ((lookup (lookup-key local-function-key-map key)))
3f866b53
KH
1777 (not (or (null lookup) (integerp lookup)
1778 (keymapp lookup)))))
24b5caec
RS
1779 ;; Handle a function key that translates into something else.
1780 ;; If the key has a global definition too,
1781 ;; exit and unread the key itself, so its global definition runs.
1782 ;; Otherwise, unread the translation,
1783 ;; so that the translated key takes effect within isearch.
d94eb6eb 1784 (cancel-kbd-macro-events)
24b5caec 1785 (if (lookup-key global-map key)
02b2f510 1786 (progn
24b5caec
RS
1787 (isearch-done)
1788 (apply 'isearch-unread keylist))
a5cc922e 1789 (setq keylist
c40bb1ba 1790 (listify-key-sequence (lookup-key local-function-key-map key)))
a5cc922e
KH
1791 (while keylist
1792 (setq key (car keylist))
1793 ;; If KEY is a printing char, we handle it here
1794 ;; directly to avoid the input method and keyboard
1795 ;; coding system translating it.
1796 (if (and (integerp key)
6480c508 1797 (>= key ?\s) (/= key 127) (< key 256))
a5cc922e
KH
1798 (progn
1799 (isearch-process-search-char key)
1800 (setq keylist (cdr keylist)))
1801 ;; As the remaining keys in KEYLIST can't be handled
1802 ;; here, we must reread them.
1803 (apply 'isearch-unread keylist)
1804 (setq keylist nil)))))
24b5caec 1805 (
c6431f12
KH
1806 ;; Handle an undefined shifted control character
1807 ;; by downshifting it if that makes it defined.
1808 ;; (As read-key-sequence would normally do,
1809 ;; if we didn't have a default definition.)
1810 (let ((mods (event-modifiers main-event)))
1811 (and (integerp main-event)
1812 (memq 'shift mods)
1813 (memq 'control mods)
f438bf5c
EZ
1814 (not (memq (lookup-key isearch-mode-map
1815 (let ((copy (copy-sequence key)))
1816 (aset copy 0
1817 (- main-event
1818 (- ?\C-\S-a ?\C-a)))
1819 copy)
1820 nil)
1821 '(nil
1822 isearch-other-control-char)))))
c6431f12 1823 (setcar keylist (- main-event (- ?\C-\S-a ?\C-a)))
d94eb6eb 1824 (cancel-kbd-macro-events)
c6431f12
KH
1825 (apply 'isearch-unread keylist))
1826 ((eq search-exit-option 'edit)
1827 (apply 'isearch-unread keylist)
1828 (isearch-edit-string))
6b61353c
KH
1829 ;; Handle a scrolling function.
1830 ((and isearch-allow-scroll
1831 (progn (setq key (isearch-reread-key-sequence-naturally keylist))
1832 (setq keylist (listify-key-sequence key))
1833 (setq main-event (aref key 0))
1834 (setq scroll-command (isearch-lookup-scroll-key key))))
1835 ;; From this point onwards, KEY, KEYLIST and MAIN-EVENT hold a
1836 ;; complete key sequence, possibly as modified by function-key-map,
1837 ;; not merely the one or two event fragment which invoked
1838 ;; isearch-other-meta-char in the first place.
1839 (setq isearch-point (point))
1840 (setq prefix-arg arg)
1841 (command-execute scroll-command)
1842 (let ((ab-bel (isearch-string-out-of-window isearch-point)))
1843 (if ab-bel
35904fd3 1844 (isearch-back-into-window (eq ab-bel 'above) isearch-point)
d85519bb 1845 (goto-char isearch-point)))
6b61353c 1846 (isearch-update))
72a69d7f
JL
1847 ;; A mouse click on the isearch message starts editing the search string
1848 ((and (eq (car-safe main-event) 'down-mouse-1)
1849 (window-minibuffer-p (posn-window (event-start main-event))))
1850 ;; Swallow the up-event.
1851 (read-event)
1852 (isearch-edit-string))
c6431f12
KH
1853 (search-exit-option
1854 (let (window)
6b61353c
KH
1855 (isearch-unread-key-sequence keylist)
1856 (setq main-event (car unread-command-events))
3fb01f36 1857
346f18dc
GM
1858 ;; If we got a mouse click event, that event contains the
1859 ;; window clicked on. maybe it was read with the buffer
c6431f12
KH
1860 ;; it was clicked on. If so, that buffer, not the current one,
1861 ;; is in isearch mode. So end the search in that buffer.
346f18dc
GM
1862
1863 ;; ??? I have no idea what this if checks for, but it's
1864 ;; obviously wrong for the case that a down-mouse event
1865 ;; on another window invokes this function. The event
1866 ;; will contain the window clicked on and that window's
b48ca14f 1867 ;; buffer is certainly not always in Isearch mode.
346f18dc
GM
1868 ;;
1869 ;; Leave the code in, but check for current buffer not
1870 ;; being in Isearch mode for now, until someone tells
1871 ;; what it's really supposed to do.
1872 ;;
1873 ;; --gerd 2001-08-10.
1874
1875 (if (and (not isearch-mode)
1876 (listp main-event)
c6431f12 1877 (setq window (posn-window (event-start main-event)))
4fd017e7
RS
1878 (windowp window)
1879 (or (> (minibuffer-depth) 0)
1880 (not (window-minibuffer-p window))))
c6431f12
KH
1881 (save-excursion
1882 (set-buffer (window-buffer window))
0352b205
RS
1883 (isearch-done)
1884 (isearch-clean-overlays))
1885 (isearch-done)
6b61353c
KH
1886 (isearch-clean-overlays)
1887 (setq prefix-arg arg))))
1888 (t;; otherwise nil
c6431f12 1889 (isearch-process-search-string key key)))))
8e1cae6d 1890
8e1cae6d
JB
1891(defun isearch-quote-char ()
1892 "Quote special characters for incremental search."
1893 (interactive)
8bc15fa8 1894 (let ((char (read-quoted-char (isearch-message t))))
3c75023f 1895 ;; Assume character codes 0200 - 0377 stand for characters in some
c20d35d5
KH
1896 ;; single-byte character set, and convert them to Emacs
1897 ;; characters.
6480c508 1898 (if (and isearch-regexp (= char ?\s))
be02a7ed 1899 (if (subregexp-context-p isearch-string (length isearch-string))
30bb1443
SM
1900 (isearch-process-search-string "[ ]" " ")
1901 (isearch-process-search-char char))
ab67e8b6
RS
1902 (and enable-multibyte-characters
1903 (>= char ?\200)
1904 (<= char ?\377)
1905 (setq char (unibyte-char-to-multibyte char)))
1906 (isearch-process-search-char char))))
8e1cae6d 1907
8e1cae6d 1908(defun isearch-return-char ()
6f2df0f4 1909 "Convert return into newline for incremental search."
8e1cae6d
JB
1910 (interactive)
1911 (isearch-process-search-char ?\n))
13701709 1912(make-obsolete 'isearch-return-char 'isearch-printing-char "19.7")
8e1cae6d 1913
8e1cae6d 1914(defun isearch-printing-char ()
b68c164d 1915 "Add this ordinary printing character to the search string and search."
8e1cae6d 1916 (interactive)
117132a6 1917 (let ((char last-command-char))
45b94eb2 1918 (if (= char ?\S-\ )
6480c508 1919 (setq char ?\s))
758710cb
KH
1920 (if current-input-method
1921 (isearch-process-search-multibyte-characters char)
1922 (isearch-process-search-char char))))
8e1cae6d 1923
8e1cae6d 1924(defun isearch-process-search-char (char)
6f2df0f4
JL
1925 ;; * and ? are special in regexps when not preceded by \.
1926 ;; } and | are special in regexps when preceded by \.
1927 ;; Nothing special for + because it matches at least once.
1928 (cond
1929 ((memq char '(?* ??)) (isearch-fallback nil))
1930 ((eq char ?\}) (isearch-fallback t t))
1931 ((eq char ?|) (isearch-fallback t nil t)))
1932
8e1cae6d 1933 ;; Append the char to the search string, update the message and re-search.
191f025a
SM
1934 (isearch-process-search-string
1935 (char-to-string char)
8f3c1d76 1936 (if (>= char ?\200)
01a6ef79
RS
1937 (char-to-string char)
1938 (isearch-text-char-description char))))
8e1cae6d
JB
1939
1940(defun isearch-process-search-string (string message)
1941 (setq isearch-string (concat isearch-string string)
1942 isearch-message (concat isearch-message message))
1943 (isearch-search-and-update))
1944
1945\f
8e1cae6d
JB
1946;; Search Ring
1947
08200510
RS
1948(defun isearch-ring-adjust1 (advance)
1949 ;; Helper for isearch-ring-adjust
1950 (let* ((ring (if isearch-regexp regexp-search-ring search-ring))
8e1cae6d
JB
1951 (length (length ring))
1952 (yank-pointer-name (if isearch-regexp
08200510 1953 'regexp-search-ring-yank-pointer
8e1cae6d
JB
1954 'search-ring-yank-pointer))
1955 (yank-pointer (eval yank-pointer-name)))
1956 (if (zerop length)
1957 ()
1958 (set yank-pointer-name
1959 (setq yank-pointer
ffbc30b2
PE
1960 (mod (+ (or yank-pointer 0)
1961 (if advance -1 1))
1962 length)))
a5dcf63f 1963 (setq isearch-string (nth yank-pointer ring)
08200510
RS
1964 isearch-message (mapconcat 'isearch-text-char-description
1965 isearch-string "")))))
1966
1967(defun isearch-ring-adjust (advance)
1968 ;; Helper for isearch-ring-advance and isearch-ring-retreat
08200510 1969 (isearch-ring-adjust1 advance)
08200510
RS
1970 (if search-ring-update
1971 (progn
1972 (isearch-search)
a71a98cf 1973 (isearch-push-state)
08200510 1974 (isearch-update))
a71a98cf
JL
1975 ;; Otherwise, edit the search string instead. Note that there is
1976 ;; no need to push the search state after isearch-edit-string here
1977 ;; since isearch-edit-string already pushes its state
1978 (isearch-edit-string)))
8e1cae6d
JB
1979
1980(defun isearch-ring-advance ()
1981 "Advance to the next search string in the ring."
08200510 1982 ;; This could be more general to handle a prefix arg, but who would use it.
8e1cae6d
JB
1983 (interactive)
1984 (isearch-ring-adjust 'advance))
1985
1986(defun isearch-ring-retreat ()
1987 "Retreat to the previous search string in the ring."
1988 (interactive)
1989 (isearch-ring-adjust nil))
1990
08200510
RS
1991(defun isearch-complete1 ()
1992 ;; Helper for isearch-complete and isearch-complete-edit
1993 ;; Return t if completion OK, nil if no completion exists.
1994 (let* ((ring (if isearch-regexp regexp-search-ring search-ring))
08200510 1995 (completion-ignore-case case-fold-search)
c789e608 1996 (completion (try-completion isearch-string ring)))
08200510
RS
1997 (cond
1998 ((eq completion t)
1999 ;; isearch-string stays the same
2000 t)
2001 ((or completion ; not nil, must be a string
b7852303 2002 (= 0 (length isearch-string))) ; shouldn't have to say this
08200510 2003 (if (equal completion isearch-string) ;; no extension?
36bcac3f
RS
2004 (progn
2005 (if completion-auto-help
2006 (with-output-to-temp-buffer "*Isearch completions*"
b48ca14f 2007 (display-completion-list
c789e608 2008 (all-completions isearch-string ring))))
36bcac3f
RS
2009 t)
2010 (and completion
2011 (setq isearch-string completion))))
08200510
RS
2012 (t
2013 (message "No completion") ; waits a second if in minibuffer
2014 nil))))
2015
2016(defun isearch-complete ()
2017 "Complete the search string from the strings on the search ring.
2018The completed string is then editable in the minibuffer.
2019If there is no completion possible, say so and continue searching."
2020 (interactive)
2021 (if (isearch-complete1)
3ae4c509
RS
2022 (progn (setq isearch-message
2023 (mapconcat 'isearch-text-char-description
2024 isearch-string ""))
2025 (isearch-edit-string))
08200510
RS
2026 ;; else
2027 (sit-for 1)
2028 (isearch-update)))
8e1cae6d 2029
08200510
RS
2030(defun isearch-complete-edit ()
2031 "Same as `isearch-complete' except in the minibuffer."
2032 (interactive)
c789e608 2033 (setq isearch-string (field-string))
08200510 2034 (if (isearch-complete1)
8e1cae6d 2035 (progn
b7b66466 2036 (delete-field)
08200510 2037 (insert isearch-string))))
8e1cae6d
JB
2038
2039\f
8e1cae6d
JB
2040;; Message string
2041
2042(defun isearch-message (&optional c-q-hack ellipsis)
2043 ;; Generate and print the message string.
2044 (let ((cursor-in-echo-area ellipsis)
d8891294
JL
2045 (m isearch-message)
2046 (cmds isearch-cmds)
2047 succ-msg)
2048 (when (or (not isearch-success) isearch-error)
2049 ;; Highlight failed part
2050 (while (or (not (isearch-success-state (car cmds)))
2051 (isearch-error-state (car cmds)))
2052 (pop cmds))
2053 (setq succ-msg (and cmds (isearch-message-state (car cmds)))
2054 m (copy-sequence m))
a71a98cf
JL
2055 (add-text-properties
2056 (if (and (stringp succ-msg)
2057 (< (length succ-msg) (length m))
2058 (equal succ-msg (substring m 0 (length succ-msg))))
2059 (length succ-msg)
2060 0)
2061 (length m) '(face isearch-fail) m)
d8891294
JL
2062 ;; Highlight failed trailing whitespace
2063 (when (string-match " +$" m)
2064 (add-text-properties (match-beginning 0) (match-end 0)
2065 '(face trailing-whitespace) m)))
2066 (setq m (concat
2067 (isearch-message-prefix c-q-hack ellipsis isearch-nonincremental)
2068 m
2069 (isearch-message-suffix c-q-hack ellipsis)))
2070 (if c-q-hack m (let ((message-log-max nil)) (message "%s" m)))))
8e1cae6d 2071
08200510 2072(defun isearch-message-prefix (&optional c-q-hack ellipsis nonincremental)
8e1cae6d
JB
2073 ;; If about to search, and previous search regexp was invalid,
2074 ;; check that it still is. If it is valid now,
2075 ;; let the message we display while searching say that it is valid.
ba653a53 2076 (and isearch-error ellipsis
8e1cae6d
JB
2077 (condition-case ()
2078 (progn (re-search-forward isearch-string (point) t)
ba653a53 2079 (setq isearch-error nil))
8e1cae6d
JB
2080 (error nil)))
2081 ;; If currently failing, display no ellipsis.
2082 (or isearch-success (setq ellipsis nil))
2083 (let ((m (concat (if isearch-success "" "failing ")
d85519bb 2084 (if isearch-adjusted "pending " "")
7badea30 2085 (if (and isearch-wrapped
6a18e4e7 2086 (not isearch-wrap-function)
7badea30
RS
2087 (if isearch-forward
2088 (> (point) isearch-opoint)
2089 (< (point) isearch-opoint)))
2090 "over")
8e1cae6d 2091 (if isearch-wrapped "wrapped ")
08200510 2092 (if isearch-word "word " "")
8e1cae6d 2093 (if isearch-regexp "regexp " "")
08200510 2094 (if nonincremental "search" "I-search")
f46d5091 2095 (if isearch-forward "" " backward")
5b56d4e4
KH
2096 (if current-input-method
2097 (concat " [" current-input-method-title "]: ")
f46d5091 2098 ": ")
8e1cae6d 2099 )))
aec11aff
KS
2100 (propertize (concat (upcase (substring m 0 1)) (substring m 1))
2101 'face 'minibuffer-prompt)))
8e1cae6d
JB
2102
2103(defun isearch-message-suffix (&optional c-q-hack ellipsis)
2104 (concat (if c-q-hack "^Q" "")
ba653a53
JL
2105 (if isearch-error
2106 (concat " [" isearch-error "]")
8e1cae6d
JB
2107 "")))
2108
2109\f
191f025a
SM
2110;; Searching
2111
512bfd85
RS
2112(defvar isearch-search-fun-function nil
2113 "Override `isearch-search-fun'.
2114This function should return the search function for isearch to use.
2115It will call this function with three arguments
2116as if it were `search-forward'.")
191f025a
SM
2117
2118(defun isearch-search-fun ()
2119 "Return the function to use for the search.
2120Can be changed via `isearch-search-fun-function' for special needs."
2121 (if isearch-search-fun-function
2122 (funcall isearch-search-fun-function)
2123 (cond
2124 (isearch-word
2125 (if isearch-forward 'word-search-forward 'word-search-backward))
2126 (isearch-regexp
2127 (if isearch-forward 're-search-forward 're-search-backward))
2128 (t
2129 (if isearch-forward 'search-forward 'search-backward)))))
8e1cae6d 2130
6cf157df
KH
2131(defun isearch-search-string (string bound noerror)
2132 ;; Search for the first occurance of STRING or its translation. If
2133 ;; found, move point to the end of the occurance, update
2134 ;; isearch-match-beg and isearch-match-end, and return point.
2135 (let ((func (isearch-search-fun))
2136 (len (length string))
2137 pos1 pos2)
2138 (setq pos1 (save-excursion (funcall func string bound noerror)))
2139 (if (and (char-table-p translation-table-for-input)
4f3b3482
SM
2140 (multibyte-string-p string)
2141 ;; Minor optimization.
2142 (string-match-p "[^[:ascii:]]" string))
2143 (let ((translated
2144 (apply 'string
2145 (mapcar (lambda (c)
2146 (or (aref translation-table-for-input c) c))
2147 string)))
2148 match-data)
6cf157df
KH
2149 (when translated
2150 (save-match-data
2151 (save-excursion
2152 (if (setq pos2 (funcall func translated bound noerror))
2153 (setq match-data (match-data t)))))
2154 (when (and pos2
2155 (or (not pos1)
2156 (if isearch-forward (< pos2 pos1) (> pos2 pos1))))
2157 (setq pos1 pos2)
2158 (set-match-data match-data)))))
d240f431
JL
2159 (when pos1
2160 ;; When using multiple buffers isearch, switch to the new buffer here,
2161 ;; because `save-excursion' above doesn't allow doing it inside funcall.
2162 (if (and isearch-buffers-next-buffer-function
2163 (buffer-live-p isearch-buffers-current-buffer))
2164 (switch-to-buffer isearch-buffers-current-buffer))
2165 (goto-char pos1))
6cf157df
KH
2166 pos1))
2167
8e1cae6d
JB
2168(defun isearch-search ()
2169 ;; Do the search with the current search string.
ac475d3a
JL
2170 (if isearch-message-function
2171 (funcall isearch-message-function nil t)
2172 (isearch-message nil t))
4453091d 2173 (if (and (eq isearch-case-fold-search t) search-upper-case)
b78559b0
RS
2174 (setq isearch-case-fold-search
2175 (isearch-no-upper-case-p isearch-string isearch-regexp)))
8e1cae6d 2176 (condition-case lossage
5e189f39
JL
2177 (let ((inhibit-point-motion-hooks
2178 (and (eq isearch-success-function 'isearch-success-function-default)
2179 search-invisible))
79c7a4fa 2180 (inhibit-quit nil)
86bfaffe 2181 (case-fold-search isearch-case-fold-search)
ab67e8b6 2182 (search-spaces-regexp search-whitespace-regexp)
86bfaffe 2183 (retry t))
ba653a53 2184 (setq isearch-error nil)
86bfaffe
RS
2185 (while retry
2186 (setq isearch-success
6cf157df 2187 (isearch-search-string isearch-string nil t))
86bfaffe
RS
2188 ;; Clear RETRY unless we matched some invisible text
2189 ;; and we aren't supposed to do that.
5e189f39 2190 (if (or (not isearch-success)
86bfaffe
RS
2191 (bobp) (eobp)
2192 (= (match-beginning 0) (match-end 0))
5e189f39
JL
2193 (funcall isearch-success-function
2194 (match-beginning 0) (match-end 0)))
86bfaffe 2195 (setq retry nil)))
99ae9e9f 2196 (setq isearch-just-started nil)
8e1cae6d
JB
2197 (if isearch-success
2198 (setq isearch-other-end
2199 (if isearch-forward (match-beginning 0) (match-end 0)))))
2200
d32696d4 2201 (quit (isearch-unread ?\C-g)
8e1cae6d
JB
2202 (setq isearch-success nil))
2203
191f025a 2204 (invalid-regexp
ba653a53 2205 (setq isearch-error (car (cdr lossage)))
8e1cae6d
JB
2206 (if (string-match
2207 "\\`Premature \\|\\`Unmatched \\|\\`Invalid "
ba653a53
JL
2208 isearch-error)
2209 (setq isearch-error "incomplete input")))
2210
2211 (search-failed
2212 (setq isearch-success nil)
2213 (setq isearch-error (nth 2 lossage)))
2214
f1c03125 2215 (error
c982ab21 2216 ;; stack overflow in regexp search.
ba653a53 2217 (setq isearch-error (format "%s" lossage))))
8e1cae6d
JB
2218
2219 (if isearch-success
2220 nil
2221 ;; Ding if failed this time after succeeding last time.
1a699acf 2222 (and (isearch-success-state (car isearch-cmds))
8e1cae6d 2223 (ding))
6a18e4e7
JL
2224 (if (functionp (isearch-pop-fun-state (car isearch-cmds)))
2225 (funcall (isearch-pop-fun-state (car isearch-cmds)) (car isearch-cmds)))
1a699acf 2226 (goto-char (isearch-point-state (car isearch-cmds)))))
8e1cae6d 2227
0352b205 2228
191f025a 2229;; Called when opening an overlay, and we are still in isearch.
0352b205 2230(defun isearch-open-overlay-temporary (ov)
b48ca14f 2231 (if (not (null (overlay-get ov 'isearch-open-invisible-temporary)))
0352b205
RS
2232 ;; Some modes would want to open the overlays temporary during
2233 ;; isearch in their own way, they should set the
2234 ;; `isearch-open-invisible-temporary' to a function doing this.
2235 (funcall (overlay-get ov 'isearch-open-invisible-temporary) ov nil)
2236 ;; Store the values for the `invisible' and `intangible'
2237 ;; properties, and then set them to nil. This way the text hidden
2238 ;; by this overlay becomes visible.
2239
380866a2 2240 ;; Do we really need to set the `intangible' property to t? Can we
0352b205
RS
2241 ;; have the point inside an overlay with an `intangible' property?
2242 ;; In 19.34 this does not exist so I cannot test it.
2243 (overlay-put ov 'isearch-invisible (overlay-get ov 'invisible))
2244 (overlay-put ov 'isearch-intangible (overlay-get ov 'intangible))
2245 (overlay-put ov 'invisible nil)
2246 (overlay-put ov 'intangible nil)))
2247
2248
191f025a
SM
2249;; This is called at the end of isearch. It will open the overlays
2250;; that contain the latest match. Obviously in case of a C-g the
2251;; point returns to the original location which surely is not contain
2252;; in any of these overlays, se we are safe in this case too.
0352b205 2253(defun isearch-open-necessary-overlays (ov)
191f025a 2254 (let ((inside-overlay (and (> (point) (overlay-start ov))
0352b205
RS
2255 (< (point) (overlay-end ov))))
2256 ;; If this exists it means that the overlay was opened using
2257 ;; this function, not by us tweaking the overlay properties.
2258 (fct-temp (overlay-get ov 'isearch-open-invisible-temporary)))
2259 (when (or inside-overlay (not fct-temp))
2260 ;; restore the values for the `invisible' and `intangible'
2261 ;; properties
2262 (overlay-put ov 'invisible (overlay-get ov 'isearch-invisible))
2263 (overlay-put ov 'intangible (overlay-get ov 'isearch-intangible))
2264 (overlay-put ov 'isearch-invisible nil)
2265 (overlay-put ov 'isearch-intangible nil))
2266 (if inside-overlay
2267 (funcall (overlay-get ov 'isearch-open-invisible) ov)
2268 (if fct-temp
2269 (funcall fct-temp ov t)))))
2270
191f025a
SM
2271;; This is called when exiting isearch. It closes the temporary
2272;; opened overlays, except the ones that contain the latest match.
0352b205
RS
2273(defun isearch-clean-overlays ()
2274 (when isearch-opened-overlays
02b2f510 2275 (mapc 'isearch-open-necessary-overlays isearch-opened-overlays)
0352b205
RS
2276 (setq isearch-opened-overlays nil)))
2277
fc0eccfc
GM
2278
2279(defun isearch-intersects-p (start0 end0 start1 end1)
2280 "Return t if regions START0..END0 and START1..END1 intersect."
eaa493df
GM
2281 (or (and (>= start0 start1) (< start0 end1))
2282 (and (> end0 start1) (<= end0 end1))
2283 (and (>= start1 start0) (< start1 end0))
2284 (and (> end1 start0) (<= end1 end0))))
fc0eccfc
GM
2285
2286
191f025a
SM
2287;; Verify if the current match is outside of each element of
2288;; `isearch-opened-overlays', if so close that overlay.
fc0eccfc
GM
2289
2290(defun isearch-close-unnecessary-overlays (begin end)
2291 (let ((overlays isearch-opened-overlays))
0352b205 2292 (setq isearch-opened-overlays nil)
fc0eccfc
GM
2293 (dolist (ov overlays)
2294 (if (isearch-intersects-p begin end (overlay-start ov) (overlay-end ov))
2295 (push ov isearch-opened-overlays)
2296 (let ((fct-temp (overlay-get ov 'isearch-open-invisible-temporary)))
2297 (if fct-temp
2298 ;; If this exists it means that the overlay was opened
2299 ;; using this function, not by us tweaking the overlay
2300 ;; properties.
2301 (funcall fct-temp ov t)
2302 (overlay-put ov 'invisible (overlay-get ov 'isearch-invisible))
2303 (overlay-put ov 'intangible (overlay-get ov 'isearch-intangible))
2304 (overlay-put ov 'isearch-invisible nil)
2305 (overlay-put ov 'isearch-intangible nil)))))))
2306
0352b205 2307
86bfaffe 2308(defun isearch-range-invisible (beg end)
79c7a4fa 2309 "Return t if all the text from BEG to END is invisible."
cd59ea72
SM
2310 (when (/= beg end)
2311 ;; Check that invisibility runs up to END.
2312 (save-excursion
2313 (goto-char beg)
2314 (let (;; can-be-opened keeps track if we can open some overlays.
2315 (can-be-opened (eq search-invisible 'open))
2316 ;; the list of overlays that could be opened
2317 (crt-overlays nil))
2318 (when (and can-be-opened isearch-hide-immediately)
2319 (isearch-close-unnecessary-overlays beg end))
2320 ;; If the following character is currently invisible,
2321 ;; skip all characters with that same `invisible' property value.
2322 ;; Do that over and over.
2323 (while (and (< (point) end)
2324 (let ((prop
2325 (get-char-property (point) 'invisible)))
2326 (if (eq buffer-invisibility-spec t)
2327 prop
2328 (or (memq prop buffer-invisibility-spec)
2329 (assq prop buffer-invisibility-spec)))))
2330 (if (get-text-property (point) 'invisible)
2331 (progn
2332 (goto-char (next-single-property-change (point) 'invisible
2333 nil end))
2334 ;; if text is hidden by an `invisible' text property
2335 ;; we cannot open it at all.
2336 (setq can-be-opened nil))
2337 (when can-be-opened
2338 (let ((overlays (overlays-at (point)))
2339 ov-list
2340 o
2341 invis-prop)
2342 (while overlays
2343 (setq o (car overlays)
2344 invis-prop (overlay-get o 'invisible))
2345 (if (if (eq buffer-invisibility-spec t)
2346 invis-prop
2347 (or (memq invis-prop buffer-invisibility-spec)
2348 (assq invis-prop buffer-invisibility-spec)))
2349 (if (overlay-get o 'isearch-open-invisible)
2350 (setq ov-list (cons o ov-list))
2351 ;; We found one overlay that cannot be
2352 ;; opened, that means the whole chunk
2353 ;; cannot be opened.
2354 (setq can-be-opened nil)))
2355 (setq overlays (cdr overlays)))
2356 (if can-be-opened
2357 ;; It makes sense to append to the open
2358 ;; overlays list only if we know that this is
2359 ;; t.
2360 (setq crt-overlays (append ov-list crt-overlays)))))
2361 (goto-char (next-overlay-change (point)))))
2362 ;; See if invisibility reaches up thru END.
2363 (if (>= (point) end)
2364 (if (and can-be-opened (consp crt-overlays))
2365 (progn
2366 (setq isearch-opened-overlays
2367 (append isearch-opened-overlays crt-overlays))
2368 (mapc 'isearch-open-overlay-temporary crt-overlays)
2369 nil)
2370 (setq isearch-hidden t)))))))
08200510 2371
5e189f39
JL
2372(defun isearch-success-function-default (beg end)
2373 "Default function to report if the new search match is successful.
2374Returns t if search can match hidden text, or otherwise checks if some
2375text from BEG to END is visible."
2376 (or (eq search-invisible t)
2377 (not (isearch-range-invisible beg end))))
2378
08200510 2379\f
191f025a 2380;; General utilities
08200510 2381
b78559b0
RS
2382(defun isearch-no-upper-case-p (string regexp-flag)
2383 "Return t if there are no upper case chars in STRING.
b7852303 2384If REGEXP-FLAG is non-nil, disregard letters preceded by `\\' (but not `\\\\')
b78559b0 2385since they have special meaning in a regexp."
b48ca14f 2386 (let (quote-flag (i 0) (len (length string)) found)
59057198
RS
2387 (while (and (not found) (< i len))
2388 (let ((char (aref string i)))
2389 (if (and regexp-flag (eq char ?\\))
2390 (setq quote-flag (not quote-flag))
2391 (if (and (not quote-flag) (not (eq char (downcase char))))
f4be3f89
RS
2392 (setq found t))
2393 (setq quote-flag nil)))
59057198 2394 (setq i (1+ i)))
c5f847b6
SM
2395 (not (or found
2396 ;; Even if there's no uppercase char, we want to detect the use
2397 ;; of [:upper:] or [:lower:] char-class, which indicates
2398 ;; clearly that the user cares about case distinction.
2399 (and regexp-flag (string-match "\\[:\\(upp\\|low\\)er:]" string)
2400 (condition-case err
2401 (progn
2402 (string-match (substring string 0 (match-beginning 0))
2403 "")
2404 nil)
2405 (invalid-regexp
2406 (equal "Unmatched [ or [^" (cadr err)))))))))
08200510 2407
b78559b0 2408;; Portability functions to support various Emacs versions.
8e1cae6d 2409
08200510 2410(defun isearch-text-char-description (c)
14373677 2411 (cond
6480c508 2412 ((< c ?\s) (format "^%c" (+ c 64)))
14373677
SM
2413 ((= c ?\^?) "^?")
2414 (t (char-to-string c))))
08200510 2415
bd1bd125 2416;; General function to unread characters or events.
99ae9e9f 2417;; Also insert them in a keyboard macro being defined.
8f90f594 2418(defun isearch-unread (&rest char-or-events)
02b2f510 2419 (mapc 'store-kbd-macro-event char-or-events)
bd1bd125
RS
2420 (setq unread-command-events
2421 (append char-or-events unread-command-events)))
08200510 2422
44336afb 2423\f
bca92193
JL
2424;; Highlighting
2425
2426(defvar isearch-overlay nil)
2427
2428(defun isearch-highlight (beg end)
704d3ae7
JL
2429 (if search-highlight
2430 (if isearch-overlay
2431 ;; Overlay already exists, just move it.
2432 (move-overlay isearch-overlay beg end (current-buffer))
2433 ;; Overlay doesn't exist, create it.
2434 (setq isearch-overlay (make-overlay beg end))
2435 ;; 1001 is higher than lazy's 1000 and ediff's 100+
2436 (overlay-put isearch-overlay 'priority 1001)
2437 (overlay-put isearch-overlay 'face isearch))))
bca92193
JL
2438
2439(defun isearch-dehighlight ()
2440 (when isearch-overlay
2441 (delete-overlay isearch-overlay)))
2442\f
191f025a
SM
2443;; isearch-lazy-highlight feature
2444;; by Bob Glickstein <http://www.zanshin.com/~bobg/>
2445
2446;; When active, *every* match for the current search string is
2447;; highlighted: the current one using the normal isearch match color
e3cde0c7 2448;; and all the others using `isearch-lazy-highlight'. The extra
191f025a
SM
2449;; highlighting makes it easier to anticipate where the cursor will
2450;; land each time you press C-s or C-r to repeat a pending search.
2451;; Highlighting of these additional matches happens in a deferred
2452;; fashion using "idle timers," so the cycles needed do not rob
2453;; isearch of its usual snappy response.
2454
2455;; IMPLEMENTATION NOTE: This depends on some isearch internals.
2456;; Specifically:
2457;; - `isearch-update' is expected to be called (at least) every time
2458;; the search string or window-start changes;
2459;; - `isearch-string' is expected to contain the current search
2460;; string as entered by the user;
2461;; - the type of the current search is expected to be given by
2462;; `isearch-word' and `isearch-regexp';
2463;; - the direction of the current search is expected to be given by
2464;; `isearch-forward';
ba653a53 2465;; - the variable `isearch-error' is expected to be true
4837b516 2466;; only if `isearch-string' is an invalid regexp.
44336afb 2467
44336afb 2468(defvar isearch-lazy-highlight-overlays nil)
c982ab21 2469(defvar isearch-lazy-highlight-wrapped nil)
f9114cec
RS
2470(defvar isearch-lazy-highlight-start-limit nil)
2471(defvar isearch-lazy-highlight-end-limit nil)
44336afb
GM
2472(defvar isearch-lazy-highlight-start nil)
2473(defvar isearch-lazy-highlight-end nil)
2474(defvar isearch-lazy-highlight-timer nil)
2475(defvar isearch-lazy-highlight-last-string nil)
c982ab21
GM
2476(defvar isearch-lazy-highlight-window nil)
2477(defvar isearch-lazy-highlight-window-start nil)
6b61353c 2478(defvar isearch-lazy-highlight-window-end nil)
46daf6c7
GM
2479(defvar isearch-lazy-highlight-case-fold-search nil)
2480(defvar isearch-lazy-highlight-regexp nil)
9a193944 2481(defvar isearch-lazy-highlight-space-regexp nil)
44336afb 2482
46fe9018 2483(defun lazy-highlight-cleanup (&optional force)
c982ab21 2484 "Stop lazy highlighting and remove extra highlighting from current buffer.
c1bc6bb6 2485FORCE non-nil means do it whether or not `lazy-highlight-cleanup'
c982ab21 2486is nil. This function is called when exiting an incremental search if
c1bc6bb6 2487`lazy-highlight-cleanup' is non-nil."
44336afb 2488 (interactive '(t))
c1bc6bb6 2489 (if (or force lazy-highlight-cleanup)
c982ab21
GM
2490 (while isearch-lazy-highlight-overlays
2491 (delete-overlay (car isearch-lazy-highlight-overlays))
2492 (setq isearch-lazy-highlight-overlays
2493 (cdr isearch-lazy-highlight-overlays))))
2494 (when isearch-lazy-highlight-timer
2495 (cancel-timer isearch-lazy-highlight-timer)
2496 (setq isearch-lazy-highlight-timer nil)))
44336afb 2497
6480c508
JB
2498(define-obsolete-function-alias 'isearch-lazy-highlight-cleanup
2499 'lazy-highlight-cleanup
2500 "22.1")
46fe9018 2501
d9dd1f33 2502(defun isearch-lazy-highlight-new-loop (&optional beg end)
c1bc6bb6 2503 "Cleanup any previous `lazy-highlight' loop and begin a new one.
f9114cec
RS
2504BEG and END specify the bounds within which highlighting should occur.
2505This is called when `isearch-update' is invoked (which can cause the
2506search string to change or the window to scroll). It is also used
2507by other Emacs features."
da79720c 2508 (when (and (null executing-kbd-macro)
c982ab21
GM
2509 (sit-for 0) ;make sure (window-start) is credible
2510 (or (not (equal isearch-string
2511 isearch-lazy-highlight-last-string))
2512 (not (eq (selected-window)
2513 isearch-lazy-highlight-window))
46daf6c7
GM
2514 (not (eq isearch-lazy-highlight-case-fold-search
2515 isearch-case-fold-search))
2516 (not (eq isearch-lazy-highlight-regexp
2517 isearch-regexp))
c982ab21 2518 (not (= (window-start)
6b61353c
KH
2519 isearch-lazy-highlight-window-start))
2520 (not (= (window-end) ; Window may have been split/joined.
2521 isearch-lazy-highlight-window-end))))
c982ab21 2522 ;; something important did indeed change
46fe9018 2523 (lazy-highlight-cleanup t) ;kill old loop & remove overlays
ba653a53 2524 (when (not isearch-error)
f9114cec
RS
2525 (setq isearch-lazy-highlight-start-limit beg
2526 isearch-lazy-highlight-end-limit end)
c982ab21
GM
2527 (setq isearch-lazy-highlight-window (selected-window)
2528 isearch-lazy-highlight-window-start (window-start)
6b61353c 2529 isearch-lazy-highlight-window-end (window-end)
c982ab21
GM
2530 isearch-lazy-highlight-start (point)
2531 isearch-lazy-highlight-end (point)
2532 isearch-lazy-highlight-last-string isearch-string
46daf6c7
GM
2533 isearch-lazy-highlight-case-fold-search isearch-case-fold-search
2534 isearch-lazy-highlight-regexp isearch-regexp
9a193944
CY
2535 isearch-lazy-highlight-wrapped nil
2536 isearch-lazy-highlight-space-regexp search-whitespace-regexp)
5f3a57c9
RS
2537 (unless (equal isearch-string "")
2538 (setq isearch-lazy-highlight-timer
c1bc6bb6 2539 (run-with-idle-timer lazy-highlight-initial-delay nil
5f3a57c9 2540 'isearch-lazy-highlight-update))))))
c982ab21
GM
2541
2542(defun isearch-lazy-highlight-search ()
2543 "Search ahead for the next or previous match, for lazy highlighting.
2544Attempt to do the search exactly the way the pending isearch would."
d9dd1f33
JL
2545 (let ((case-fold-search isearch-lazy-highlight-case-fold-search)
2546 (isearch-regexp isearch-lazy-highlight-regexp)
9a193944 2547 (search-spaces-regexp isearch-lazy-highlight-space-regexp))
ba653a53 2548 (condition-case nil
6cf157df 2549 (isearch-search-string
d9dd1f33 2550 isearch-lazy-highlight-last-string
ba653a53
JL
2551 (if isearch-forward
2552 (min (or isearch-lazy-highlight-end-limit (point-max))
2553 (if isearch-lazy-highlight-wrapped
2554 isearch-lazy-highlight-start
2555 (window-end)))
2556 (max (or isearch-lazy-highlight-start-limit (point-min))
2557 (if isearch-lazy-highlight-wrapped
2558 isearch-lazy-highlight-end
2559 (window-start))))
2560 t)
2561 (error nil))))
44336afb
GM
2562
2563(defun isearch-lazy-highlight-update ()
c982ab21 2564 "Update highlighting of other matches for current search."
c1bc6bb6 2565 (let ((max lazy-highlight-max-at-a-time)
c982ab21
GM
2566 (looping t)
2567 nomore)
6ee8e621
JL
2568 (with-local-quit
2569 (save-selected-window
2570 (if (and (window-live-p isearch-lazy-highlight-window)
2571 (not (eq (selected-window) isearch-lazy-highlight-window)))
2572 (select-window isearch-lazy-highlight-window))
2573 (save-excursion
2574 (save-match-data
2575 (goto-char (if isearch-forward
2576 isearch-lazy-highlight-end
2577 isearch-lazy-highlight-start))
2578 (while looping
2579 (let ((found (isearch-lazy-highlight-search)))
2580 (when max
2581 (setq max (1- max))
2582 (if (<= max 0)
2583 (setq looping nil)))
2584 (if found
2585 (let ((mb (match-beginning 0))
2586 (me (match-end 0)))
2587 (if (= mb me) ;zero-length match
2588 (if isearch-forward
2589 (if (= mb (if isearch-lazy-highlight-wrapped
2590 isearch-lazy-highlight-start
2591 (window-end)))
2592 (setq found nil)
2593 (forward-char 1))
2594 (if (= mb (if isearch-lazy-highlight-wrapped
2595 isearch-lazy-highlight-end
2596 (window-start)))
2597 (setq found nil)
2598 (forward-char -1)))
2599
2600 ;; non-zero-length match
2601 (let ((ov (make-overlay mb me)))
2602 (push ov isearch-lazy-highlight-overlays)
704d3ae7
JL
2603 ;; 1000 is higher than ediff's 100+,
2604 ;; but lower than isearch main overlay's 1001
2605 (overlay-put ov 'priority 1000)
46fe9018 2606 (overlay-put ov 'face lazy-highlight-face)
6ee8e621
JL
2607 (overlay-put ov 'window (selected-window))))
2608 (if isearch-forward
2609 (setq isearch-lazy-highlight-end (point))
2610 (setq isearch-lazy-highlight-start (point)))))
2611
2612 ;; not found or zero-length match at the search bound
2613 (if (not found)
2614 (if isearch-lazy-highlight-wrapped
2615 (setq looping nil
2616 nomore t)
2617 (setq isearch-lazy-highlight-wrapped t)
5ee5cd10 2618 (if isearch-forward
6ee8e621
JL
2619 (progn
2620 (setq isearch-lazy-highlight-end (window-start))
f9114cec
RS
2621 (goto-char (max (or isearch-lazy-highlight-start-limit (point-min))
2622 (window-start))))
6ee8e621 2623 (setq isearch-lazy-highlight-start (window-end))
f9114cec
RS
2624 (goto-char (min (or isearch-lazy-highlight-end-limit (point-max))
2625 (window-end))))))))
6ee8e621
JL
2626 (unless nomore
2627 (setq isearch-lazy-highlight-timer
2c987fc2 2628 (run-at-time lazy-highlight-interval nil
6ee8e621 2629 'isearch-lazy-highlight-update)))))))))
44336afb 2630
72a69d7f 2631(defun isearch-resume (string regexp word forward message case-fold)
c40a4de1 2632 "Resume an incremental search.
72a69d7f 2633STRING is the string or regexp searched for.
c40a4de1
GM
2634REGEXP non-nil means the resumed search was a regexp search.
2635WORD non-nil means resume a word search.
2636FORWARD non-nil means resume a forward search.
2637MESSAGE is the echo-area message recorded for the search resumed.
2638CASE-FOLD non-nil means the search was case-insensitive."
2639 (isearch-mode forward regexp nil nil word)
72a69d7f 2640 (setq isearch-string string
c40a4de1
GM
2641 isearch-message message
2642 isearch-case-fold-search case-fold)
72a69d7f
JL
2643 (isearch-search)
2644 (isearch-update))
191f025a 2645
81e898ea 2646;; arch-tag: 74850515-f7d8-43a6-8a2c-ca90a4c1e675
3b1e4dd1 2647;;; isearch.el ends here