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