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