Comment out Oct 18 change to font-lock-after-change-function
[bpt/emacs.git] / lisp / isearch.el
CommitLineData
76550a57 1;;; isearch.el --- incremental search minor mode.
3b1e4dd1 2
d733c5ec 3;; Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
3a801d0c 4
3b1e4dd1
ER
5;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
6
0cabad13 7;; |$Date: 1994/11/15 16:56:44 $|$Revision: 1.77 $
8e1cae6d 8
54d2ecd3 9;; This file is part of GNU Emacs.
8e1cae6d 10
59243403
RS
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
13;; the Free Software Foundation; either version 2, or (at your option)
14;; any later version.
15
8e1cae6d 16;; GNU Emacs is distributed in the hope that it will be useful,
59243403
RS
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs; see the file COPYING. If not, write to
23;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
8e1cae6d 24
3b1e4dd1
ER
25;;; Commentary:
26
8e1cae6d
JB
27;;;====================================================================
28;; Instructions
29
08200510
RS
30;; For programmed use of isearch-mode, e.g. calling (isearch-forward),
31;; isearch-mode behaves modally and does not return until the search
32;; is completed. It uses a recursive-edit to behave this way. Note:
33;; gnus does it wrong: (call-interactively 'isearch-forward).
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
43;; Note to emacs version 19 users: isearch-mode should work even if
44;; you switch windows with the mouse, in which case isearch-mode is
45;; terminated automatically before the switch. This is true of lemacs
46;; too, with a few more cleanups I've neglected in this release.
47;; No one has supplied patches for epoch yet.
48
49;; The search ring and completion commands automatically put you in
50;; the minibuffer to edit the string. This gives you a chance to
51;; modify the search string before executing the search. There are
52;; three commands to terminate the editing: C-s and C-r exit the
53;; minibuffer and search forward and reverse respectively, while C-m
54;; exits and does a nonincremental search.
55
56;; Exiting immediately from isearch uses isearch-edit-string instead
57;; of nonincremental-search, if search-nonincremental-instead is non-nil.
58;; The name of this option should probably be changed if we decide to
59;; keep the behavior. No point in forcing nonincremental search until
60;; the last possible moment.
61
62;; TODO
eb8c3be9 63;; - Integrate the emacs 19 generalized command history.
08200510
RS
64;; - Think about incorporating query-replace.
65;; - Hooks and options for failed search.
282d89c0 66
3b1e4dd1
ER
67;;; Change Log:
68
8cb2ceaa
RS
69;;; Changes before those recorded in ChangeLog:
70
08200510
RS
71;;; Revision 1.4 92/09/14 16:26:02 liberte
72;;; Added prefix args to isearch-forward, etc. to switch between
73;;; string and regular expression searching.
74;;; Added some support for lemacs.
75;;; Added general isearch-highlight option - but only for lemacs so far.
76;;; Added support for frame switching in emacs 19.
77;;; Added word search option to isearch-edit-string.
78;;; Renamed isearch-quit to isearch-abort.
79;;; Numerous changes to comments and doc strings.
282d89c0 80;;;
08200510
RS
81;;; Revision 1.3 92/06/29 13:10:08 liberte
82;;; Moved modal isearch-mode handling into isearch-mode.
83;;; Got rid of buffer-local isearch variables.
84;;; isearch-edit-string used by ring adjustments, completion, and
85;;; nonincremental searching. C-s and C-r are additional exit commands.
86;;; Renamed all regex to regexp.
87;;; Got rid of found-start and found-point globals.
88;;; Generalized handling of upper-case chars.
89
90;;; Revision 1.2 92/05/27 11:33:57 liberte
91;;; Emacs version 19 has a search ring, which is supported here.
92;;; Other fixes found in the version 19 isearch are included here.
93;;;
94;;; Also see variables search-caps-disable-folding,
95;;; search-nonincremental-instead, search-whitespace-regexp, and
96;;; commands isearch-toggle-regexp, isearch-edit-string.
97;;;
98;;; semi-modal isearching is supported.
282d89c0
ER
99
100;;; Changes for 1.1
101;;; 3/18/92 Fixed invalid-regexp.
102;;; 3/18/92 Fixed yanking in regexps.
103
3b1e4dd1 104;;; Code:
08200510
RS
105
106\f
58451992
RS
107;;;========================================================================
108;;; Some additional options and constants.
08200510 109
fdf5afa4 110(defconst search-exit-option t
a8f783b2 111 "*Non-nil means random control characters terminate incremental search.")
fdf5afa4
RS
112
113(defvar search-slow-window-lines 1
114 "*Number of lines in slow search display windows.
115These are the short windows used during incremental search on slow terminals.
116Negative means put the slow search window at the top (normally it's at bottom)
117and the value is minus the number of lines.")
118
119(defvar search-slow-speed 1200
120 "*Highest terminal speed at which to use \"slow\" style incremental search.
121This is the style where a one-line window is created to show the line
122that the search has reached.")
8e1cae6d 123
b78559b0 124(defvar search-upper-case 'not-yanks
8e1cae6d 125 "*If non-nil, upper case chars disable case fold searching.
08200510
RS
126That is, upper and lower case chars must match exactly.
127This applies no matter where the chars come from, but does not
fdf5afa4
RS
128apply to chars in regexps that are prefixed with `\\'.
129If this value is `not-yanks', yanked text is always downcased.")
8e1cae6d
JB
130
131(defvar search-nonincremental-instead t
132 "*If non-nil, do a nonincremental search instead if exiting immediately.
08200510
RS
133Actually, `isearch-edit-string' is called to let you enter the search
134string, and RET terminates editing and does a nonincremental search.")
8e1cae6d
JB
135
136(defconst search-whitespace-regexp "\\s-+"
137 "*If non-nil, regular expression to match a sequence of whitespace chars.
138You might want to use something like \"[ \\t\\r\\n]+\" instead.")
139
a8f783b2
RS
140;; I removed the * from the doc string because highlighting is not
141;; currently a clean thing to do. Once highlighting is made clean,
142;; this feature can be re-enabled and advertised.
08200510 143(defvar search-highlight nil
b78559b0 144 "*Non-nil means incremental search highlights the current match.")
08200510
RS
145
146(defvar isearch-mode-hook nil
147 "Function(s) to call after starting up an incremental search.")
148
149(defvar isearch-mode-end-hook nil
150 "Function(s) to call after terminating an incremental search.")
151
8e1cae6d
JB
152;;;==================================================================
153;;; Search ring.
8e1cae6d
JB
154
155(defvar search-ring nil
156 "List of search string sequences.")
08200510 157(defvar regexp-search-ring nil
8e1cae6d
JB
158 "List of regular expression search string sequences.")
159
160(defconst search-ring-max 16
161 "*Maximum length of search ring before oldest elements are thrown away.")
08200510
RS
162(defconst regexp-search-ring-max 16
163 "*Maximum length of regexp search ring before oldest elements are thrown away.")
8e1cae6d
JB
164
165(defvar search-ring-yank-pointer nil
a5dcf63f
RS
166 "Index in `search-ring' of last string reused.
167nil if none yet.")
08200510 168(defvar regexp-search-ring-yank-pointer nil
a5dcf63f
RS
169 "Index in `regexp-search-ring' of last string reused.
170nil if none yet.")
8e1cae6d 171
08200510
RS
172(defvar search-ring-update nil
173 "*Non-nil if advancing or retreating in the search ring should cause search.
174Default value, nil, means edit the string instead.")
175
8e1cae6d
JB
176;;;====================================================
177;;; Define isearch-mode keymap.
178
179(defvar isearch-mode-map nil
180 "Keymap for isearch-mode.")
181
08200510
RS
182(or isearch-mode-map
183 (let* ((i 0)
fdf5afa4 184 (map (make-keymap)))
fcf8ba15
RS
185 (or (vectorp (nth 1 map))
186 (error "The initialization of isearch-mode-map must be updated"))
187 ;; Give this map a vector 256 long, for dense binding
188 ;; of a larger range of ordinary characters.
189 (setcar (cdr map) (make-vector 256 nil))
08200510 190
ac689515
RS
191 ;; Make function keys, etc, exit the search.
192 (define-key map [t] 'isearch-other-control-char)
08200510 193 ;; Control chars, by default, end isearch mode transparently.
ac689515
RS
194 ;; We need these explicit definitions because, in a dense keymap,
195 ;; the binding for t does not affect characters.
196 ;; We use a dense keymap to save space.
08200510
RS
197 (while (< i ?\ )
198 (define-key map (make-string 1 i) 'isearch-other-control-char)
199 (setq i (1+ i)))
200
8cb2ceaa 201 ;; Printing chars extend the search string by default.
ac689515 202 (setq i ?\ )
8d7e4e80 203 (while (< i (length (nth 1 map)))
8cb2ceaa 204 (define-key map (vector i) 'isearch-printing-char)
08200510
RS
205 (setq i (1+ i)))
206
207 ;; Several non-printing chars change the searching behavior.
208 (define-key map "\C-s" 'isearch-repeat-forward)
209 (define-key map "\C-r" 'isearch-repeat-backward)
210 (define-key map "\177" 'isearch-delete-char)
211 (define-key map "\C-g" 'isearch-abort)
8e1cae6d 212
08200510
RS
213 (define-key map "\C-q" 'isearch-quote-char)
214
08200510
RS
215 (define-key map "\r" 'isearch-exit)
216 (define-key map "\C-j" 'isearch-printing-char)
217 (define-key map "\t" 'isearch-printing-char)
218 (define-key map " " 'isearch-whitespace-chars)
8e1cae6d 219
08200510
RS
220 (define-key map "\C-w" 'isearch-yank-word)
221 (define-key map "\C-y" 'isearch-yank-line)
222
eccd3117
RS
223 ;; Bind the ASCII-equivalent "function keys" explicitly to nil
224 ;; so that the default binding does not apply.
225 ;; As a result, these keys translate thru function-key-map
226 ;; as normal, and they have the effect of the equivalent ASCII char.
e7cb0106 227 ;; We bind [escape] below.
eccd3117
RS
228 (define-key map [tab] 'nil)
229 (define-key map [kp-0] 'nil)
230 (define-key map [kp-1] 'nil)
231 (define-key map [kp-2] 'nil)
232 (define-key map [kp-3] 'nil)
233 (define-key map [kp-4] 'nil)
234 (define-key map [kp-5] 'nil)
235 (define-key map [kp-6] 'nil)
236 (define-key map [kp-7] 'nil)
237 (define-key map [kp-8] 'nil)
238 (define-key map [kp-9] 'nil)
239 (define-key map [kp-add] 'nil)
240 (define-key map [kp-subtract] 'nil)
241 (define-key map [kp-multiply] 'nil)
242 (define-key map [kp-divide] 'nil)
243 (define-key map [kp-decimal] 'nil)
244 (define-key map [kp-separator] 'nil)
245 (define-key map [kp-equal] 'nil)
246 (define-key map [kp-tab] 'nil)
247 (define-key map [kp-space] 'nil)
248 (define-key map [kp-enter] 'nil)
249 (define-key map [delete] 'nil)
250 (define-key map [backspace] 'nil)
251 (define-key map [return] 'nil)
252 (define-key map [newline] 'nil)
e7cb0106 253
08200510
RS
254 ;; Define keys for regexp chars * ? |.
255 ;; Nothing special for + because it matches at least once.
256 (define-key map "*" 'isearch-*-char)
257 (define-key map "?" 'isearch-*-char)
258 (define-key map "|" 'isearch-|-char)
259
58f1634a
RS
260;;; Turned off because I find I expect to get the global definition--rms.
261;;; ;; Instead bind C-h to special help command for isearch-mode.
262;;; (define-key map "\C-h" 'isearch-mode-help)
08200510
RS
263
264 ;; To handle local bindings with meta char prefix keys, define
265 ;; another full keymap. This must be done for any other prefix
266 ;; keys as well, one full keymap per char of the prefix key. It
267 ;; would be simpler to disable the global keymap, and/or have a
268 ;; default local key binding for any key not otherwise bound.
e7cb0106
RS
269 (let ((meta-map (make-sparse-keymap)))
270 (define-key map (char-to-string meta-prefix-char) meta-map)
271 (define-key map [escape] meta-map))
ac689515 272 (define-key map (vector meta-prefix-char t) 'isearch-other-meta-char)
08200510
RS
273
274 (define-key map "\M-n" 'isearch-ring-advance)
275 (define-key map "\M-p" 'isearch-ring-retreat)
30d47262 276 (define-key map "\M-y" 'isearch-yank-kill)
1a3a6707 277
08200510
RS
278 (define-key map "\M-\t" 'isearch-complete)
279
58451992
RS
280 ;; Switching frames should terminate isearch-mode
281 (define-key map [switch-frame] 'isearch-switch-frame-handler)
08200510
RS
282
283 (setq isearch-mode-map map)
284 ))
8e1cae6d 285
08200510
RS
286;; Some bindings you may want to put in your isearch-mode-hook.
287;; Suggest some alternates...
4453091d 288;; (define-key isearch-mode-map "\C-t" 'isearch-toggle-case-fold)
08200510
RS
289;; (define-key isearch-mode-map "\C-t" 'isearch-toggle-regexp)
290;; (define-key isearch-mode-map "\C-^" 'isearch-edit-string)
8e1cae6d 291
8e1cae6d 292
08200510
RS
293(defvar minibuffer-local-isearch-map nil
294 "Keymap for editing isearch strings in the minibuffer.")
8e1cae6d 295
08200510
RS
296(or minibuffer-local-isearch-map
297 (let ((map (copy-keymap minibuffer-local-map)))
298 (define-key map "\r" 'isearch-nonincremental-exit-minibuffer)
35a4d143
RS
299 (define-key map "\M-n" 'isearch-ring-advance-edit)
300 (define-key map "\M-p" 'isearch-ring-retreat-edit)
08200510
RS
301 (define-key map "\M-\t" 'isearch-complete-edit)
302 (define-key map "\C-s" 'isearch-forward-exit-minibuffer)
303 (define-key map "\C-r" 'isearch-reverse-exit-minibuffer)
304 (setq minibuffer-local-isearch-map map)
305 ))
8e1cae6d
JB
306
307;;;========================================================
308;; Internal variables declared globally for byte-compiler.
08200510
RS
309;; These are all set with setq while isearching
310;; and bound locally while editing the search string.
311
312(defvar isearch-forward nil) ; Searching in the forward direction.
313(defvar isearch-regexp nil) ; Searching for a regexp.
314(defvar isearch-word nil) ; Searching for words.
315
316(defvar isearch-cmds nil) ; Stack of search status sets.
317(defvar isearch-string "") ; The current search string.
318(defvar isearch-message "") ; text-char-description version of isearch-string
319
320(defvar isearch-success t) ; Searching is currently successful.
321(defvar isearch-invalid-regexp nil) ; Regexp not well formed.
c5f6b356 322(defvar isearch-within-brackets nil) ; Regexp has unclosed [.
08200510
RS
323(defvar isearch-other-end nil) ; Start (end) of match if forward (backward).
324(defvar isearch-wrapped nil) ; Searching restarted from the top (bottom).
8e1cae6d
JB
325(defvar isearch-barrier 0)
326
4453091d
RS
327; case-fold-search while searching.
328; either nil, t, or 'yes. 'yes means the same as t except that mixed
329; case in the search string is ignored.
330(defvar isearch-case-fold-search nil)
8e1cae6d
JB
331
332(defvar isearch-adjusted nil)
333(defvar isearch-slow-terminal-mode nil)
08200510
RS
334;;; If t, using a small window.
335(defvar isearch-small-window nil)
8e1cae6d 336(defvar isearch-opoint 0)
08200510
RS
337;;; The window configuration active at the beginning of the search.
338(defvar isearch-window-configuration nil)
8e1cae6d 339
08200510
RS
340;; Flag to indicate a yank occurred, so don't move the cursor.
341(defvar isearch-yank-flag nil)
8e1cae6d 342
08200510
RS
343;;; A function to be called after each input character is processed.
344;;; (It is not called after characters that exit the search.)
345;;; It is only set from an optional argument to `isearch-mode'.
346(defvar isearch-op-fun nil)
8e1cae6d 347
08200510
RS
348;;; Is isearch-mode in a recursive edit for modal searching.
349(defvar isearch-recursive-edit nil)
8e1cae6d 350
08200510
RS
351;;; Should isearch be terminated after doing one search?
352(defvar isearch-nonincremental nil)
353
354;; New value of isearch-forward after isearch-edit-string.
355(defvar isearch-new-forward nil)
8e1cae6d 356
8e1cae6d
JB
357
358;;;==============================================================
359;; Minor-mode-alist changes - kind of redundant with the
360;; echo area, but if isearching in multiple windows, it can be useful.
361
362(or (assq 'isearch-mode minor-mode-alist)
363 (nconc minor-mode-alist
364 (list '(isearch-mode isearch-mode))))
365
08200510 366(defvar isearch-mode nil) ;; Name of the minor mode, if non-nil.
8e1cae6d
JB
367(make-variable-buffer-local 'isearch-mode)
368
fdf5afa4
RS
369(define-key global-map "\C-s" 'isearch-forward)
370(define-key esc-map "\C-s" 'isearch-forward-regexp)
371(define-key global-map "\C-r" 'isearch-backward)
372(define-key esc-map "\C-r" 'isearch-backward-regexp)
373
8e1cae6d
JB
374;;;===============================================================
375;;; Entry points to isearch-mode.
08200510 376;;; These four functions should replace those in loaddefs.el
b457cc3b 377;;; An alternative is to defalias isearch-forward etc to isearch-mode,
08200510 378;;; and look at this-command to set the options accordingly.
8e1cae6d 379
eceee2c0 380(defun isearch-forward (&optional regexp-p no-recursive-edit)
8e1cae6d
JB
381 "\
382Do incremental search forward.
08200510
RS
383With a prefix argument, do an incremental regular expression search instead.
384\\<isearch-mode-map>
8e1cae6d 385As you type characters, they add to the search string and are found.
08200510 386The following non-printing keys are bound in `isearch-mode-map'.
8e1cae6d 387
08200510 388Type \\[isearch-delete-char] to cancel characters from end of search string.
8e1cae6d 389Type \\[isearch-exit] to exit, leaving point at location found.
08200510
RS
390Type LFD (C-j) to match end of line.
391Type \\[isearch-repeat-forward] to search again forward,\
392 \\[isearch-repeat-backward] to search again backward.
393Type \\[isearch-yank-word] to yank word from buffer onto end of search\
394 string and search for it.
395Type \\[isearch-yank-line] to yank rest of line onto end of search string\
396 and search for it.
8e1cae6d 397Type \\[isearch-quote-char] to quote control character to search for it.
08200510
RS
398\\[isearch-abort] while searching or when search has failed cancels input\
399 back to what has
400 been found successfully.
401\\[isearch-abort] when search is successful aborts and moves point to\
402 starting point.
8e1cae6d
JB
403
404Also supported is a search ring of the previous 16 search strings.
405Type \\[isearch-ring-advance] to search for the next item in the search ring.
08200510
RS
406Type \\[isearch-ring-retreat] to search for the previous item in the search\
407 ring.
408Type \\[isearch-complete] to complete the search string using the search ring.
8e1cae6d 409
08200510
RS
410The above keys, bound in `isearch-mode-map', are often controlled by
411 options; do M-x apropos on search-.* to find them.
8e1cae6d 412Other control and meta characters terminate the search
08200510 413 and are then executed normally (depending on `search-exit-option').
8e1cae6d 414
08200510
RS
415If this function is called non-interactively, it does not return to
416the calling function until the search is done."
8e1cae6d 417
eceee2c0 418 (interactive "P\np")
4ae7d00a 419 (isearch-mode t (not (null regexp-p)) nil (not no-recursive-edit)))
8e1cae6d 420
eceee2c0 421(defun isearch-forward-regexp (&optional not-regexp no-recursive-edit)
8e1cae6d
JB
422 "\
423Do incremental search forward for regular expression.
08200510 424With a prefix argument, do a regular string search instead.
8e1cae6d
JB
425Like ordinary incremental search except that your input
426is treated as a regexp. See \\[isearch-forward] for more info."
eceee2c0 427 (interactive "P\np")
4ae7d00a 428 (isearch-mode t (null not-regexp) nil (not no-recursive-edit)))
8e1cae6d 429
eceee2c0 430(defun isearch-backward (&optional regexp-p no-recursive-edit)
8e1cae6d
JB
431 "\
432Do incremental search backward.
08200510 433With a prefix argument, do a regular expression search instead.
8e1cae6d 434See \\[isearch-forward] for more information."
eceee2c0 435 (interactive "P\np")
4ae7d00a 436 (isearch-mode nil (not (null regexp-p)) nil (not no-recursive-edit)))
8e1cae6d 437
eceee2c0 438(defun isearch-backward-regexp (&optional not-regexp no-recursive-edit)
8e1cae6d
JB
439 "\
440Do incremental search backward for regular expression.
08200510 441With a prefix argument, do a regular string search instead.
8e1cae6d
JB
442Like ordinary incremental search except that your input
443is treated as a regexp. See \\[isearch-forward] for more info."
eceee2c0 444 (interactive "P\np")
4ae7d00a 445 (isearch-mode nil (null not-regexp) nil (not no-recursive-edit)))
08200510
RS
446
447
448(defun isearch-mode-help ()
449 (interactive)
450 (describe-function 'isearch-forward)
451 (isearch-update))
8e1cae6d
JB
452
453\f
454;;;==================================================================
455;; isearch-mode only sets up incremental search for the minor mode.
456;; All the work is done by the isearch-mode commands.
457
08200510
RS
458;; Not used yet:
459;;(defconst isearch-commands '(isearch-forward isearch-backward
460;; isearch-forward-regexp isearch-backward-regexp)
461;; "List of commands for which isearch-mode does not recursive-edit.")
462
463
464(defun isearch-mode (forward &optional regexp op-fun recursive-edit word-p)
8e1cae6d 465 "Start isearch minor mode. Called by isearch-forward, etc."
8e1cae6d
JB
466
467 ;; Initialize global vars.
468 (setq isearch-forward forward
469 isearch-regexp regexp
08200510 470 isearch-word word-p
8e1cae6d
JB
471 isearch-op-fun op-fun
472 isearch-case-fold-search case-fold-search
473 isearch-string ""
474 isearch-message ""
475 isearch-cmds nil
476 isearch-success t
477 isearch-wrapped nil
478 isearch-barrier (point)
479 isearch-adjusted nil
480 isearch-yank-flag nil
481 isearch-invalid-regexp nil
c5f6b356 482 isearch-within-brackets nil
0cabad13 483 isearch-slow-terminal-mode (and (<= baud-rate search-slow-speed)
8e1cae6d
JB
484 (> (window-height)
485 (* 4 search-slow-window-lines)))
486 isearch-other-end nil
487 isearch-small-window nil
8e1cae6d 488
8e1cae6d 489 isearch-opoint (point)
a5dcf63f
RS
490 search-ring-yank-pointer nil
491 regexp-search-ring-yank-pointer nil)
292a8dff
RS
492 (setq isearch-window-configuration
493 (if isearch-slow-terminal-mode (current-window-configuration) nil))
70418205 494
8e1cae6d
JB
495 (setq isearch-mode " Isearch") ;; forward? regexp?
496 (set-buffer-modified-p (buffer-modified-p)) ; update modeline
497
498 (isearch-push-state)
499
849cfd72
RS
500 (make-local-variable 'overriding-local-map)
501 (setq overriding-local-map isearch-mode-map)
8e1cae6d
JB
502 (isearch-update)
503 (run-hooks 'isearch-mode-hook)
08200510
RS
504
505 ;; isearch-mode can be made modal (in the sense of not returning to
506 ;; the calling function until searching is completed) by entering
507 ;; a recursive-edit and exiting it when done isearching.
130bf67c
RS
508 (if recursive-edit
509 (let ((isearch-recursive-edit t))
510 (recursive-edit)))
0daa17f3 511 isearch-success)
8e1cae6d
JB
512
513
514;;;====================================================
515;; Some high level utilities. Others below.
516
517(defun isearch-update ()
518 ;; Called after each command to update the display.
58451992 519 (if (null unread-command-events)
8e1cae6d
JB
520 (progn
521 (if (not (input-pending-p))
522 (isearch-message))
523 (if (and isearch-slow-terminal-mode
524 (not (or isearch-small-window
525 (pos-visible-in-window-p))))
08200510 526 (let ((found-point (point)))
8e1cae6d 527 (setq isearch-small-window t)
8e1cae6d
JB
528 (move-to-window-line 0)
529 (let ((window-min-height 1))
530 (split-window nil (if (< search-slow-window-lines 0)
531 (1+ (- search-slow-window-lines))
532 (- (window-height)
533 (1+ search-slow-window-lines)))))
534 (if (< search-slow-window-lines 0)
535 (progn (vertical-motion (- 1 search-slow-window-lines))
536 (set-window-start (next-window) (point))
537 (set-window-hscroll (next-window)
538 (window-hscroll))
539 (set-window-hscroll (selected-window) 0))
540 (other-window 1))
08200510
RS
541 (goto-char found-point)))
542 (if isearch-other-end
543 (if (< isearch-other-end (point)) ; isearch-forward?
544 (isearch-highlight isearch-other-end (point))
99afb671
RS
545 (isearch-highlight (point) isearch-other-end))
546 (isearch-dehighlight nil))
08200510 547 ))
8e1cae6d
JB
548 (setq ;; quit-flag nil not for isearch-mode
549 isearch-adjusted nil
550 isearch-yank-flag nil)
551 )
552
553
0daa17f3 554(defun isearch-done (&optional nopush edit)
8e1cae6d 555 ;; Called by all commands that terminate isearch-mode.
35a4d143 556 ;; If NOPUSH is non-nil, we don't push the string on the search ring.
849cfd72 557 (setq overriding-local-map nil)
08200510
RS
558 ;; (setq pre-command-hook isearch-old-pre-command-hook) ; for lemacs
559 (isearch-dehighlight t)
560 (let ((found-start (window-start (selected-window)))
561 (found-point (point)))
70418205
RS
562 (if isearch-window-configuration
563 (set-window-configuration isearch-window-configuration))
08200510 564
d49b6338
RS
565 (if isearch-small-window
566 (goto-char found-point)
567 ;; Exiting the save-window-excursion clobbers window-start; restore it.
568 (set-window-start (selected-window) found-start t)))
569
08200510
RS
570 ;; If there was movement, mark the starting position.
571 ;; Maybe should test difference between and set mark iff > threshold.
572 (if (/= (point) isearch-opoint)
7872ee4d 573 (progn
48be3850
RS
574 (or (and transient-mark-mode mark-active)
575 (push-mark isearch-opoint t))
7872ee4d
RS
576 (or executing-macro (> (minibuffer-depth) 0)
577 (message "Mark saved where search started")))
08200510
RS
578 ;; (message "") why is this needed?
579 )
08200510
RS
580
581 (setq isearch-mode nil)
582 (set-buffer-modified-p (buffer-modified-p)) ;; update modeline
8e1cae6d 583
35a4d143 584 (if (and (> (length isearch-string) 0) (not nopush))
8e1cae6d
JB
585 ;; Update the ring data.
586 (if isearch-regexp
a8f783b2
RS
587 (if (or (null regexp-search-ring)
588 (not (string= isearch-string (car regexp-search-ring))))
8e1cae6d 589 (progn
08200510 590 (setq regexp-search-ring
a5dcf63f 591 (cons isearch-string regexp-search-ring))
08200510
RS
592 (if (> (length regexp-search-ring) regexp-search-ring-max)
593 (setcdr (nthcdr (1- search-ring-max) regexp-search-ring)
8e1cae6d 594 nil))))
a8f783b2
RS
595 (if (or (null search-ring)
596 (not (string= isearch-string (car search-ring))))
8e1cae6d 597 (progn
a5dcf63f 598 (setq search-ring (cons isearch-string search-ring))
8e1cae6d
JB
599 (if (> (length search-ring) search-ring-max)
600 (setcdr (nthcdr (1- search-ring-max) search-ring) nil))))))
601
8e1cae6d 602 (run-hooks 'isearch-mode-end-hook)
0daa17f3 603 (and (not edit) isearch-recursive-edit (exit-recursive-edit)))
08200510
RS
604
605;;;=======================================================
606;;; Switching buffers should first terminate isearch-mode.
eb8c3be9 607;;; This is done quite differently for each variant of emacs.
08200510
RS
608;;; For lemacs, see Exiting in lemacs below
609
610;; For Emacs 19, the frame switch event is handled.
611(defun isearch-switch-frame-handler ()
612 (interactive) ;; Is this necessary?
613 ;; First terminate isearch-mode.
614 (isearch-done)
dba1ec55 615 (handle-switch-frame (car (cdr (isearch-last-command-char)))))
08200510
RS
616
617;;;========================================================
8e1cae6d
JB
618
619\f
620;;;====================================================
621;; Commands active while inside of the isearch minor mode.
622
623(defun isearch-exit ()
624 "Exit search normally.
625However, if this is the first command after starting incremental
626search and `search-nonincremental-instead' is non-nil, do a
08200510 627nonincremental search instead via `isearch-edit-string'."
8e1cae6d
JB
628 (interactive)
629 (if (and search-nonincremental-instead
630 (= 0 (length isearch-string)))
08200510
RS
631 (let ((isearch-nonincremental t))
632 (isearch-edit-string)))
8e1cae6d
JB
633 (isearch-done))
634
635
636(defun isearch-edit-string ()
08200510
RS
637 "Edit the search string in the minibuffer.
638The following additional command keys are active while editing.
639\\<minibuffer-local-isearch-map>
640\\[exit-minibuffer] to resume incremental searching with the edited string.
641\\[isearch-nonincremental-exit-minibuffer] to do one nonincremental search.
642\\[isearch-forward-exit-minibuffer] to resume isearching forward.
8eb40e74 643\\[isearch-reverse-exit-minibuffer] to resume isearching backward.
08200510 644\\[isearch-ring-advance-edit] to replace the search string with the next item in the search ring.
eb8c3be9 645\\[isearch-ring-retreat-edit] to replace the search string with the previous item in the search ring.
08200510 646\\[isearch-complete-edit] to complete the search string using the search ring.
8eb40e74 647\\<isearch-mode-map>
08200510
RS
648If first char entered is \\[isearch-yank-word], then do word search instead."
649
650 ;; This code is very hairy for several reasons, explained in the code.
651 ;; Mainly, isearch-mode must be terminated while editing and then restarted.
652 ;; If there were a way to catch any change of buffer from the minibuffer,
653 ;; this could be simplified greatly.
eb8c3be9 654 ;; Editing doesn't back up the search point. Should it?
8e1cae6d 655 (interactive)
08200510 656 (condition-case err
a9a5a9fa 657 (let ((isearch-nonincremental isearch-nonincremental)
08200510
RS
658
659 ;; Locally bind all isearch global variables to protect them
660 ;; from recursive isearching.
661 ;; isearch-string -message and -forward are not bound
662 ;; so they may be changed. Instead, save the values.
663 (isearch-new-string isearch-string)
664 (isearch-new-message isearch-message)
665 (isearch-new-forward isearch-forward)
666 (isearch-new-word isearch-word)
667
668 (isearch-regexp isearch-regexp)
669 (isearch-op-fun isearch-op-fun)
670 (isearch-cmds isearch-cmds)
671 (isearch-success isearch-success)
672 (isearch-wrapped isearch-wrapped)
673 (isearch-barrier isearch-barrier)
674 (isearch-adjusted isearch-adjusted)
675 (isearch-yank-flag isearch-yank-flag)
676 (isearch-invalid-regexp isearch-invalid-regexp)
c5f6b356 677 (isearch-within-brackets isearch-within-brackets)
08200510
RS
678 (isearch-other-end isearch-other-end)
679 (isearch-opoint isearch-opoint)
680 (isearch-slow-terminal-mode isearch-slow-terminal-mode)
681 (isearch-small-window isearch-small-window)
682 (isearch-recursive-edit isearch-recursive-edit)
683 ;; Save current configuration so we can restore it here.
684 (isearch-window-configuration (current-window-configuration))
685 )
686
687 ;; Actually terminate isearching until editing is done.
688 ;; This is so that the user can do anything without failure,
689 ;; like switch buffers and start another isearch, and return.
690 (condition-case err
0daa17f3 691 (isearch-done t t)
08200510
RS
692 (exit nil)) ; was recursive editing
693
694 (isearch-message) ;; for read-char
695 (unwind-protect
696 (let* (;; Why does following read-char echo?
697 ;;(echo-keystrokes 0) ;; not needed with above message
d94307ee 698 (e (let ((cursor-in-echo-area t))
235beb32 699 (read-event)))
08200510
RS
700 ;; Binding minibuffer-history-symbol to nil is a work-around
701 ;; for some incompatibility with gmhist.
702 (minibuffer-history-symbol))
703 ;; If the first character the user types when we prompt them
704 ;; for a string is the yank-word character, then go into
705 ;; word-search mode. Otherwise unread that character and
706 ;; read a key the normal way.
707 ;; Word search does not apply (yet) to regexp searches,
708 ;; no check is made here.
709 (message (isearch-message-prefix nil nil t))
710 (if (eq 'isearch-yank-word
235beb32 711 (lookup-key isearch-mode-map (vector e)))
08200510
RS
712 (setq isearch-word t ;; so message-prefix is right
713 isearch-new-word t)
714 (isearch-unread e))
a5dcf63f
RS
715 (setq cursor-in-echo-area nil)
716 (setq isearch-new-string
35a4d143 717 (let (junk-ring)
71e2ab54
RS
718 (read-from-minibuffer
719 (isearch-message-prefix nil nil isearch-nonincremental)
720 isearch-string
721 minibuffer-local-isearch-map nil
722 'junk-ring))
7e846b10
RS
723 isearch-new-message
724 (mapconcat 'isearch-text-char-description
725 isearch-new-string "")))
08200510
RS
726 ;; Always resume isearching by restarting it.
727 (isearch-mode isearch-forward
728 isearch-regexp
729 isearch-op-fun
0daa17f3 730 nil
08200510
RS
731 isearch-word)
732
733 ;; Copy new local values to isearch globals
734 (setq isearch-string isearch-new-string
735 isearch-message isearch-new-message
736 isearch-forward isearch-new-forward
737 isearch-word isearch-new-word))
738
739 ;; Empty isearch-string means use default.
740 (if (= 0 (length isearch-string))
a8f783b2
RS
741 (setq isearch-string (car (if isearch-regexp regexp-search-ring
742 search-ring)))
743 ;; This used to set the last search string,
744 ;; but I think it is not right to do that here.
745 ;; Only the string actually used should be saved.
746 )
08200510
RS
747
748 ;; Reinvoke the pending search.
749 (isearch-push-state)
750 (isearch-search)
751 (isearch-update)
752 (if isearch-nonincremental
753 (progn
754 ;; (sit-for 1) ;; needed if isearch-done does: (message "")
755 (isearch-done))))
8e1cae6d 756
08200510
RS
757 (quit ; handle abort-recursive-edit
758 (isearch-abort) ;; outside of let to restore outside global values
759 )))
760
761(defun isearch-nonincremental-exit-minibuffer ()
762 (interactive)
763 (setq isearch-nonincremental t)
764 (exit-minibuffer))
765
766(defun isearch-forward-exit-minibuffer ()
767 (interactive)
768 (setq isearch-new-forward t)
769 (exit-minibuffer))
8e1cae6d 770
08200510 771(defun isearch-reverse-exit-minibuffer ()
8e1cae6d 772 (interactive)
08200510
RS
773 (setq isearch-new-forward nil)
774 (exit-minibuffer))
775
776
777(defun isearch-abort ()
778 "Abort incremental search mode if searching is successful, signalling quit.
779Otherwise, revert to previous successful search and continue searching.
780Use `isearch-exit' to quit without signalling."
781 (interactive)
eb8c3be9 782;; (ding) signal instead below, if quitting
8e1cae6d
JB
783 (discard-input)
784 (if isearch-success
785 ;; If search is successful, move back to starting point
786 ;; and really do quit.
787 (progn (goto-char isearch-opoint)
35a4d143 788 (isearch-done t) ; exit isearch
a5dcf63f 789 (signal 'quit nil)) ; and pass on quit signal
08200510 790 ;; If search is failing, rub out until it is once more successful.
8e1cae6d
JB
791 (while (not isearch-success) (isearch-pop-state))
792 (isearch-update)))
793
794
795(defun isearch-repeat (direction)
796 ;; Utility for isearch-repeat-forward and -backward.
797 (if (eq isearch-forward (eq direction 'forward))
798 ;; C-s in forward or C-r in reverse.
799 (if (equal isearch-string "")
800 ;; If search string is empty, use last one.
801 (setq isearch-string
8e1cae6d 802 (or (if isearch-regexp
a5dcf63f
RS
803 (car regexp-search-ring)
804 (car search-ring))
8e1cae6d
JB
805 "")
806 isearch-message
08200510 807 (mapconcat 'isearch-text-char-description
8e1cae6d
JB
808 isearch-string ""))
809 ;; If already have what to search for, repeat it.
810 (or isearch-success
811 (progn
812
813 (goto-char (if isearch-forward (point-min) (point-max)))
814 (setq isearch-wrapped t))))
815 ;; C-s in reverse or C-r in forward, change direction.
816 (setq isearch-forward (not isearch-forward)))
817
818 (setq isearch-barrier (point)) ; For subsequent \| if regexp.
6fefdc4b
RS
819
820 (if (equal isearch-string "")
821 (setq isearch-success t)
822 (if (and isearch-success (equal (match-end 0) (match-beginning 0)))
8e1cae6d
JB
823 ;; If repeating a search that found
824 ;; an empty string, ensure we advance.
6fefdc4b
RS
825 (if (if isearch-forward (eobp) (bobp))
826 ;; If there's nowhere to advance to, fail (and wrap next time).
827 (progn
828 (setq isearch-success nil)
829 (ding))
830 (forward-char (if isearch-forward 1 -1))
831 (isearch-search))
832 (isearch-search)))
833
8e1cae6d
JB
834 (isearch-push-state)
835 (isearch-update))
836
837(defun isearch-repeat-forward ()
838 "Repeat incremental search forwards."
839 (interactive)
840 (isearch-repeat 'forward))
841
842(defun isearch-repeat-backward ()
843 "Repeat incremental search backwards."
844 (interactive)
845 (isearch-repeat 'backward))
846
847(defun isearch-toggle-regexp ()
848 "Toggle regexp searching on or off."
849 ;; The status stack is left unchanged.
850 (interactive)
851 (setq isearch-regexp (not isearch-regexp))
08200510 852 (if isearch-regexp (setq isearch-word nil))
8e1cae6d
JB
853 (isearch-update))
854
4453091d
RS
855(defun isearch-toggle-case-fold ()
856 "Toggle case folding in searching on or off."
857 (interactive)
858 (setq isearch-case-fold-search
859 (if isearch-case-fold-search nil 'yes))
860 (message "%s%s [case %ssensitive]"
71e2ab54 861 (isearch-message-prefix nil nil isearch-nonincremental)
4453091d
RS
862 isearch-message
863 (if isearch-case-fold-search "in" ""))
864 (setq isearch-adjusted t)
865 (sit-for 1)
866 (isearch-update))
867
8e1cae6d
JB
868(defun isearch-delete-char ()
869 "Discard last input item and move point back.
870If no previous match was done, just beep."
871 (interactive)
872 (if (null (cdr isearch-cmds))
873 (ding)
874 (isearch-pop-state))
875 (isearch-update))
876
877
878(defun isearch-yank (chunk)
879 ;; Helper for isearch-yank-word and isearch-yank-line
30d47262
RS
880 ;; CHUNK should be word, line or kill.
881 (let ((string (cond
882 ((eq chunk 'kill)
883 (current-kill 0))
884 (t
885 (save-excursion
886 (and (not isearch-forward) isearch-other-end
887 (goto-char isearch-other-end))
888 (buffer-substring
889 (point)
890 (save-excursion
891 (cond
892 ((eq chunk 'word)
893 (forward-word 1))
894 ((eq chunk 'line)
895 (end-of-line)))
896 (point))))))))
08200510
RS
897 ;; Downcase the string if not supposed to case-fold yanked strings.
898 (if (and isearch-case-fold-search
fdf5afa4 899 (eq 'not-yanks search-upper-case))
08200510
RS
900 (setq string (downcase string)))
901 (if isearch-regexp (setq string (regexp-quote string)))
902 (setq isearch-string (concat isearch-string string)
8e1cae6d
JB
903 isearch-message
904 (concat isearch-message
08200510
RS
905 (mapconcat 'isearch-text-char-description
906 string ""))
8e1cae6d
JB
907 ;; Don't move cursor in reverse search.
908 isearch-yank-flag t))
909 (isearch-search-and-update))
910
30d47262
RS
911(defun isearch-yank-kill ()
912 "Pull string from kill ring into search string."
913 (interactive)
914 (isearch-yank 'kill))
8e1cae6d
JB
915
916(defun isearch-yank-word ()
917 "Pull next word from buffer into search string."
918 (interactive)
919 (isearch-yank 'word))
920
921(defun isearch-yank-line ()
922 "Pull rest of line from buffer into search string."
923 (interactive)
924 (isearch-yank 'line))
925
926
927(defun isearch-search-and-update ()
928 ;; Do the search and update the display.
929 (if (and (not isearch-success)
930 ;; unsuccessful regexp search may become
931 ;; successful by addition of characters which
932 ;; make isearch-string valid
933 (not isearch-regexp))
934 nil
935 ;; In reverse search, adding stuff at
936 ;; the end may cause zero or many more chars to be
937 ;; matched, in the string following point.
938 ;; Allow all those possibilities without moving point as
939 ;; long as the match does not extend past search origin.
940 (if (and (not isearch-forward) (not isearch-adjusted)
941 (condition-case ()
942 (looking-at (if isearch-regexp isearch-string
943 (regexp-quote isearch-string)))
944 (error nil))
945 (or isearch-yank-flag
946 (<= (match-end 0)
947 (min isearch-opoint isearch-barrier))))
948 (setq isearch-success t
949 isearch-invalid-regexp nil
c5f6b356 950 isearch-within-brackets nil
8e1cae6d
JB
951 isearch-other-end (match-end 0))
952 ;; Not regexp, not reverse, or no match at point.
953 (if (and isearch-other-end (not isearch-adjusted))
954 (goto-char (if isearch-forward isearch-other-end
955 (min isearch-opoint
956 isearch-barrier
957 (1+ isearch-other-end)))))
958 (isearch-search)
959 ))
960 (isearch-push-state)
961 (if isearch-op-fun (funcall isearch-op-fun))
962 (isearch-update))
963
964
965;; *, ?, and | chars can make a regexp more liberal.
08200510 966;; They can make a regexp match sooner or make it succeed instead of failing.
8e1cae6d
JB
967;; So go back to place last successful search started
968;; or to the last ^S/^R (barrier), whichever is nearer.
08200510 969;; + needs no special handling because the string must match at least once.
8e1cae6d
JB
970
971(defun isearch-*-char ()
972 "Handle * and ? specially in regexps."
973 (interactive)
974 (if isearch-regexp
975
976 (progn
977 (setq isearch-adjusted t)
978 (let ((cs (nth (if isearch-forward
979 5 ; isearch-other-end
980 2) ; saved (point)
981 (car (cdr isearch-cmds)))))
982 ;; (car isearch-cmds) is after last search;
983 ;; (car (cdr isearch-cmds)) is from before it.
984 (setq cs (or cs isearch-barrier))
985 (goto-char
986 (if isearch-forward
987 (max cs isearch-barrier)
988 (min cs isearch-barrier))))))
08200510 989 (isearch-process-search-char (isearch-last-command-char)))
8e1cae6d
JB
990
991
8e1cae6d
JB
992(defun isearch-|-char ()
993 "If in regexp search, jump to the barrier."
994 (interactive)
995 (if isearch-regexp
996 (progn
997 (setq isearch-adjusted t)
998 (goto-char isearch-barrier)))
08200510 999 (isearch-process-search-char (isearch-last-command-char)))
8e1cae6d
JB
1000
1001
b457cc3b 1002(defalias 'isearch-other-control-char 'isearch-other-meta-char)
8e1cae6d
JB
1003
1004(defun isearch-other-meta-char ()
8f90f594 1005 "Exit the search normally and reread this key sequence.
35a4d143
RS
1006But only if `search-exit-option' is non-nil, the default.
1007If it is the symbol `edit', the search string is edited in the minibuffer
1008and the meta character is unread so that it applies to editing the string."
8e1cae6d 1009 (interactive)
35a4d143
RS
1010 (cond ((eq search-exit-option 'edit)
1011 (let ((key (this-command-keys)))
e7cb0106 1012 (apply 'isearch-unread (listify-key-sequence key)))
35a4d143
RS
1013 (isearch-edit-string))
1014 (search-exit-option
bd1bd125
RS
1015 (let* ((key (this-command-keys))
1016 (main-event (aref key 0))
1017 window)
70418205 1018 (apply 'isearch-unread (listify-key-sequence key))
285eb5ef
RS
1019 ;; Properly handle scroll-bar and mode-line clicks
1020 ;; for which a dummy prefix event was generated as (aref key 0).
1021 (and (> (length key) 1)
1022 (symbolp (aref key 0))
1023 (listp (aref key 1))
4b43d418 1024 (not (numberp (posn-point (event-start (aref key 1)))))
bd1bd125
RS
1025 ;; Convert the event back into its raw form,
1026 ;; with the dummy prefix implicit in the mouse event,
1027 ;; so it will get split up once again.
0cabad13 1028 (progn (setq unread-command-events
bd1bd125
RS
1029 (cdr unread-command-events))
1030 (setq main-event (car unread-command-events))
1031 (setcar (cdr (event-start main-event))
1032 (car (nth 1 (event-start main-event))))))
70418205
RS
1033 ;; If we got a mouse click, maybe it was read with the buffer
1034 ;; it was clicked on. If so, that buffer, not the current one,
1035 ;; is in isearch mode. So end the search in that buffer.
bd1bd125
RS
1036 (if (and (listp main-event)
1037 (setq window (posn-window (event-start main-event)))
70418205
RS
1038 (windowp window))
1039 (save-excursion
1040 (set-buffer (window-buffer window))
1041 (isearch-done))
1042 (isearch-done))))
35a4d143
RS
1043 (t;; otherwise nil
1044 (isearch-process-search-string (this-command-keys)
1045 (this-command-keys)))))
8e1cae6d 1046
8e1cae6d
JB
1047(defun isearch-quote-char ()
1048 "Quote special characters for incremental search."
1049 (interactive)
1050 (isearch-process-search-char (read-quoted-char (isearch-message t))))
1051
8e1cae6d
JB
1052(defun isearch-return-char ()
1053 "Convert return into newline for incremental search.
1054Obsolete."
1055 (interactive)
1056 (isearch-process-search-char ?\n))
1057
8e1cae6d 1058(defun isearch-printing-char ()
b68c164d 1059 "Add this ordinary printing character to the search string and search."
8e1cae6d 1060 (interactive)
08200510 1061 (isearch-process-search-char (isearch-last-command-char)))
8e1cae6d
JB
1062
1063(defun isearch-whitespace-chars ()
08200510 1064 "Match all whitespace chars, if in regexp mode.
b68c164d 1065If you want to search for just a space, type C-q SPC."
8e1cae6d 1066 (interactive)
08200510 1067 (if isearch-regexp
c5f6b356 1068 (if (and search-whitespace-regexp (not isearch-within-brackets))
08200510
RS
1069 (isearch-process-search-string search-whitespace-regexp " ")
1070 (isearch-printing-char))
1071 (progn
eb8c3be9 1072 ;; This way of doing word search doesn't correctly extend current search.
08200510
RS
1073 ;; (setq isearch-word t)
1074 ;; (setq isearch-adjusted t)
1075 ;; (goto-char isearch-barrier)
1076 (isearch-printing-char))))
8e1cae6d
JB
1077
1078(defun isearch-process-search-char (char)
1079 ;; Append the char to the search string, update the message and re-search.
08200510
RS
1080 (isearch-process-search-string
1081 (isearch-char-to-string char)
1082 (isearch-text-char-description char)))
8e1cae6d
JB
1083
1084(defun isearch-process-search-string (string message)
1085 (setq isearch-string (concat isearch-string string)
1086 isearch-message (concat isearch-message message))
1087 (isearch-search-and-update))
1088
1089\f
1090;;===========================================================
1091;; Search Ring
1092
08200510
RS
1093(defun isearch-ring-adjust1 (advance)
1094 ;; Helper for isearch-ring-adjust
1095 (let* ((ring (if isearch-regexp regexp-search-ring search-ring))
8e1cae6d
JB
1096 (length (length ring))
1097 (yank-pointer-name (if isearch-regexp
08200510 1098 'regexp-search-ring-yank-pointer
8e1cae6d
JB
1099 'search-ring-yank-pointer))
1100 (yank-pointer (eval yank-pointer-name)))
1101 (if (zerop length)
1102 ()
1103 (set yank-pointer-name
1104 (setq yank-pointer
ffbc30b2
PE
1105 (mod (+ (or yank-pointer 0)
1106 (if advance -1 1))
1107 length)))
a5dcf63f 1108 (setq isearch-string (nth yank-pointer ring)
08200510
RS
1109 isearch-message (mapconcat 'isearch-text-char-description
1110 isearch-string "")))))
1111
1112(defun isearch-ring-adjust (advance)
1113 ;; Helper for isearch-ring-advance and isearch-ring-retreat
1114 (if (cdr isearch-cmds) ;; is there more than one thing on stack?
1115 (isearch-pop-state))
1116 (isearch-ring-adjust1 advance)
8e1cae6d 1117 (isearch-push-state)
08200510
RS
1118 (if search-ring-update
1119 (progn
1120 (isearch-search)
1121 (isearch-update))
1122 (isearch-edit-string)
1123 ))
8e1cae6d
JB
1124
1125(defun isearch-ring-advance ()
1126 "Advance to the next search string in the ring."
08200510 1127 ;; This could be more general to handle a prefix arg, but who would use it.
8e1cae6d
JB
1128 (interactive)
1129 (isearch-ring-adjust 'advance))
1130
1131(defun isearch-ring-retreat ()
1132 "Retreat to the previous search string in the ring."
1133 (interactive)
1134 (isearch-ring-adjust nil))
1135
a5dcf63f
RS
1136(defun isearch-ring-advance-edit (n)
1137 "Insert the next element of the search history into the minibuffer."
1138 (interactive "p")
1139 (let* ((yank-pointer-name (if isearch-regexp
1140 'regexp-search-ring-yank-pointer
1141 'search-ring-yank-pointer))
1142 (yank-pointer (eval yank-pointer-name))
1143 (ring (if isearch-regexp regexp-search-ring search-ring))
1144 (length (length ring)))
1145 (if (zerop length)
1146 ()
1147 (set yank-pointer-name
1148 (setq yank-pointer
ffbc30b2
PE
1149 (mod (- (or yank-pointer 0) n)
1150 length)))
a5dcf63f 1151
a5dcf63f 1152 (erase-buffer)
35a4d143 1153 (insert (nth yank-pointer ring))
49c13105 1154 (goto-char (point-max)))))
a5dcf63f
RS
1155
1156(defun isearch-ring-retreat-edit (n)
1157 "Inserts the previous element of the search history into the minibuffer."
1158 (interactive "p")
1159 (isearch-ring-advance-edit (- n)))
1160
1161;;(defun isearch-ring-adjust-edit (advance)
1162;; "Use the next or previous search string in the ring while in minibuffer."
1163;; (isearch-ring-adjust1 advance)
1164;; (erase-buffer)
1165;; (insert isearch-string))
1166
1167;;(defun isearch-ring-advance-edit ()
1168;; (interactive)
1169;; (isearch-ring-adjust-edit 'advance))
1170
1171;;(defun isearch-ring-retreat-edit ()
1172;; "Retreat to the previous search string in the ring while in the minibuffer."
1173;; (interactive)
1174;; (isearch-ring-adjust-edit nil))
08200510
RS
1175
1176
1177(defun isearch-complete1 ()
1178 ;; Helper for isearch-complete and isearch-complete-edit
1179 ;; Return t if completion OK, nil if no completion exists.
1180 (let* ((ring (if isearch-regexp regexp-search-ring search-ring))
1181 (alist (mapcar (function (lambda (string) (list string))) ring))
1182 (completion-ignore-case case-fold-search)
1183 (completion (try-completion isearch-string alist)))
1184 (cond
1185 ((eq completion t)
1186 ;; isearch-string stays the same
1187 t)
1188 ((or completion ; not nil, must be a string
1189 (= 0 (length isearch-string))) ; shouldnt have to say this
1190 (if (equal completion isearch-string) ;; no extension?
1191 (if completion-auto-help
1192 (with-output-to-temp-buffer "*Isearch completions*"
1193 (display-completion-list
1194 (all-completions isearch-string alist))))
1195 (setq isearch-string completion))
1196 t)
1197 (t
1198 (message "No completion") ; waits a second if in minibuffer
1199 nil))))
1200
1201(defun isearch-complete ()
1202 "Complete the search string from the strings on the search ring.
1203The completed string is then editable in the minibuffer.
1204If there is no completion possible, say so and continue searching."
1205 (interactive)
1206 (if (isearch-complete1)
1207 (isearch-edit-string)
1208 ;; else
1209 (sit-for 1)
1210 (isearch-update)))
8e1cae6d 1211
08200510
RS
1212(defun isearch-complete-edit ()
1213 "Same as `isearch-complete' except in the minibuffer."
1214 (interactive)
1215 (setq isearch-string (buffer-string))
1216 (if (isearch-complete1)
8e1cae6d 1217 (progn
08200510
RS
1218 (erase-buffer)
1219 (insert isearch-string))))
8e1cae6d
JB
1220
1221\f
1222;;;==============================================================
1223;; The search status stack (and isearch window-local variables, not used).
08200510 1224;; Need a structure for this.
8e1cae6d
JB
1225
1226(defun isearch-top-state ()
8e1cae6d
JB
1227 (let ((cmd (car isearch-cmds)))
1228 (setq isearch-string (car cmd)
1229 isearch-message (car (cdr cmd))
1230 isearch-success (nth 3 cmd)
1231 isearch-forward (nth 4 cmd)
1232 isearch-other-end (nth 5 cmd)
08200510
RS
1233 isearch-word (nth 6 cmd)
1234 isearch-invalid-regexp (nth 7 cmd)
1235 isearch-wrapped (nth 8 cmd)
c5f6b356 1236 isearch-barrier (nth 9 cmd)
f551b97d
RS
1237 isearch-within-brackets (nth 10 cmd)
1238 isearch-case-fold-search (nth 11 cmd))
8e1cae6d
JB
1239 (goto-char (car (cdr (cdr cmd))))))
1240
1241(defun isearch-pop-state ()
8e1cae6d
JB
1242 (setq isearch-cmds (cdr isearch-cmds))
1243 (isearch-top-state)
1244 )
1245
1246(defun isearch-push-state ()
1247 (setq isearch-cmds
1248 (cons (list isearch-string isearch-message (point)
1249 isearch-success isearch-forward isearch-other-end
08200510 1250 isearch-word
c5f6b356 1251 isearch-invalid-regexp isearch-wrapped isearch-barrier
f551b97d 1252 isearch-within-brackets isearch-case-fold-search)
8e1cae6d
JB
1253 isearch-cmds)))
1254
8e1cae6d
JB
1255\f
1256;;;==================================================================
1257;; Message string
1258
1259(defun isearch-message (&optional c-q-hack ellipsis)
1260 ;; Generate and print the message string.
1261 (let ((cursor-in-echo-area ellipsis)
1262 (m (concat
08200510 1263 (isearch-message-prefix c-q-hack ellipsis isearch-nonincremental)
8e1cae6d
JB
1264 isearch-message
1265 (isearch-message-suffix c-q-hack ellipsis)
1266 )))
1267 (if c-q-hack m (message "%s" m))))
1268
08200510 1269(defun isearch-message-prefix (&optional c-q-hack ellipsis nonincremental)
8e1cae6d
JB
1270 ;; If about to search, and previous search regexp was invalid,
1271 ;; check that it still is. If it is valid now,
1272 ;; let the message we display while searching say that it is valid.
1273 (and isearch-invalid-regexp ellipsis
1274 (condition-case ()
1275 (progn (re-search-forward isearch-string (point) t)
8eb40e74
KH
1276 (setq isearch-invalid-regexp nil
1277 isearch-within-brackets nil))
8e1cae6d
JB
1278 (error nil)))
1279 ;; If currently failing, display no ellipsis.
1280 (or isearch-success (setq ellipsis nil))
1281 (let ((m (concat (if isearch-success "" "failing ")
1282 (if isearch-wrapped "wrapped ")
08200510 1283 (if isearch-word "word " "")
8e1cae6d 1284 (if isearch-regexp "regexp " "")
08200510 1285 (if nonincremental "search" "I-search")
8e1cae6d
JB
1286 (if isearch-forward ": " " backward: ")
1287 )))
1288 (aset m 0 (upcase (aref m 0)))
1289 m))
1290
1291
1292(defun isearch-message-suffix (&optional c-q-hack ellipsis)
1293 (concat (if c-q-hack "^Q" "")
1294 (if isearch-invalid-regexp
1295 (concat " [" isearch-invalid-regexp "]")
1296 "")))
1297
1298\f
1299;;;========================================================
1300;;; Searching
1301
1302(defun isearch-search ()
1303 ;; Do the search with the current search string.
1304 (isearch-message nil t)
4453091d 1305 (if (and (eq isearch-case-fold-search t) search-upper-case)
b78559b0
RS
1306 (setq isearch-case-fold-search
1307 (isearch-no-upper-case-p isearch-string isearch-regexp)))
8e1cae6d
JB
1308 (condition-case lossage
1309 (let ((inhibit-quit nil)
1310 (case-fold-search isearch-case-fold-search))
1311 (if isearch-regexp (setq isearch-invalid-regexp nil))
c5f6b356 1312 (setq isearch-within-brackets nil)
8e1cae6d
JB
1313 (setq isearch-success
1314 (funcall
08200510
RS
1315 (cond (isearch-word
1316 (if isearch-forward
1317 'word-search-forward 'word-search-backward))
1318 (isearch-regexp
1319 (if isearch-forward
1320 're-search-forward 're-search-backward))
1321 (t
1322 (if isearch-forward 'search-forward 'search-backward)))
8e1cae6d
JB
1323 isearch-string nil t))
1324 (if isearch-success
1325 (setq isearch-other-end
1326 (if isearch-forward (match-beginning 0) (match-end 0)))))
1327
d32696d4 1328 (quit (isearch-unread ?\C-g)
8e1cae6d
JB
1329 (setq isearch-success nil))
1330
1331 (invalid-regexp
1332 (setq isearch-invalid-regexp (car (cdr lossage)))
c5f6b356
RS
1333 (setq isearch-within-brackets (string-match "\\`Unmatched \\["
1334 isearch-invalid-regexp))
8e1cae6d
JB
1335 (if (string-match
1336 "\\`Premature \\|\\`Unmatched \\|\\`Invalid "
1337 isearch-invalid-regexp)
f1c03125
RS
1338 (setq isearch-invalid-regexp "incomplete input")))
1339 (error
1340 ;; stack overflow in regexp search.
1341 (setq isearch-invalid-regexp (car (cdr lossage)))))
8e1cae6d
JB
1342
1343 (if isearch-success
1344 nil
1345 ;; Ding if failed this time after succeeding last time.
1346 (and (nth 3 (car isearch-cmds))
1347 (ding))
1348 (goto-char (nth 2 (car isearch-cmds)))))
1349
08200510
RS
1350
1351\f
1352;;;========================================================
1353;;; Highlighting
1354
b78559b0 1355(defvar isearch-overlay nil)
08200510 1356
b78559b0 1357(defun isearch-highlight (beg end)
f5f6a944 1358 (if (or (null search-highlight) (null window-system))
08200510 1359 nil
b78559b0
RS
1360 (or isearch-overlay (setq isearch-overlay (make-overlay beg end)))
1361 (move-overlay isearch-overlay beg end (current-buffer))
82318db5
RS
1362 (overlay-put isearch-overlay 'face
1363 (if (internal-find-face 'isearch nil)
1364 'isearch 'region))))
b78559b0
RS
1365
1366(defun isearch-dehighlight (totally)
1367 (if isearch-overlay
1368 (delete-overlay isearch-overlay)))
08200510
RS
1369
1370;;;===========================================================
1371;;; General utilities
1372
08200510 1373
b78559b0
RS
1374(defun isearch-no-upper-case-p (string regexp-flag)
1375 "Return t if there are no upper case chars in STRING.
1376If REGEXP-FLAG is non-nil, disregard letters preceeded by `\\' (but not `\\\\')
1377since they have special meaning in a regexp."
08200510 1378 (let ((case-fold-search nil))
b78559b0
RS
1379 (not (string-match (if regexp-flag "\\(^\\|\\\\\\\\\\|[^\\]\\)[A-Z]"
1380 "[A-Z]")
1381 string))))
08200510
RS
1382
1383
8e1cae6d 1384;;;=================================================
b78559b0 1385;; Portability functions to support various Emacs versions.
8e1cae6d 1386
08200510
RS
1387;; To quiet the byte-compiler.
1388(defvar unread-command-event)
dbc4e1c1 1389(defvar unread-command-events)
08200510 1390(defvar last-command-event)
8e1cae6d 1391
08200510 1392(defun isearch-char-to-string (c)
0cabad13 1393 (make-string 1 c))
08200510
RS
1394
1395(defun isearch-text-char-description (c)
9d78ff8b
RS
1396 (if (and (integerp c) (or (< c ?\ ) (= c ?\^?)))
1397 (text-char-description c)
1398 (isearch-char-to-string c)))
08200510 1399
bd1bd125 1400;; General function to unread characters or events.
8f90f594 1401(defun isearch-unread (&rest char-or-events)
bd1bd125
RS
1402 (setq unread-command-events
1403 (append char-or-events unread-command-events)))
08200510
RS
1404
1405(defun isearch-last-command-char ()
1406 ;; General function to return the last command character.
58451992 1407 last-command-char)
08200510 1408
3b1e4dd1 1409;;; isearch.el ends here