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