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