(main): Use X menu code if HAVE_X_WINDOWS and not NO_X_MENU.
[bpt/emacs.git] / lisp / isearch.el
CommitLineData
282d89c0
ER
1;; isearch-mode.el --- incremental search minor mode.
2
3a801d0c
ER
3;; Copyright (C) 1992 Free Software Foundation, Inc.
4
282d89c0
ER
5;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
6;; Version: 1.2
8e1cae6d
JB
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is distributed in the hope that it will be useful,
11;; but WITHOUT ANY WARRANTY. No author or distributor
12;; accepts responsibility to anyone for the consequences of using it
13;; or for whether it serves any particular purpose or works at all,
14;; unless he says so in writing. Refer to the GNU Emacs General Public
15;; License for full details.
16
17;; Everyone is granted permission to copy, modify and redistribute
18;; GNU Emacs, but only under the conditions described in the
19;; GNU Emacs General Public License. A copy of this license is
20;; supposed to have been given to you along with GNU Emacs so you
21;; can know your rights and responsibilities. It should be in a
22;; file named COPYING. Among other things, the copyright notice
23;; and this notice must be preserved on all copies.
24
282d89c0 25;;; Commentary:
8e1cae6d
JB
26
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
42;; The key bindings active within isearch-mode are defined below in
43;; `isearch-mode-map' and `isearch-mode-meta-map' which are given
44;; bindings close to the default characters of isearch.el for
45;; version 19. With `isearch-mode', however, you can bind
46;; multi-character keys and it should be easier to add new commands.
47
48;; Note to epoch and emacs version 19 users: isearch-mode should
49;; work even if you switch windows with the mouse. However, if
50;; you isearch in a buffer that is also displayed in another window,
51;; when you switch to that other window you will still be in
52;; isearch mode but not necessarily in the right state for it to work.
53;; So ... don't do it unless you are in an experimental mood.
54;; You can also experiment with the window-local-variable routines
55;; contained in this package but not yet used.
56;; Also, I am not sure what happens when you return to an isearching
57;; buffer; ideally, the echo area should redisplay the searching status.
58;; A select-window-hook might be useful.
59
282d89c0
ER
60;;; Change Log:
61
62;;;====================================================================
63
282d89c0
ER
64;;; Revision 1.2 92/05/27 11:33:57 liberte
65;;; Several new commands and features have been added. Emacs version
66;;; 19 has a search ring, which is supported here. Other fixes found
67;;; in the version 19 isearch are included here. Also see variables
68;;; search-caps-disable-folding, search-nonincremental-instead,
69;;; search-whitespace-regexp, and commands isearch-toggle-regexp,
70;;; isearch-edit-string,
71;;;
72;;; Semi-modal searching is supported, using a recursive edit. If
73;;; isearching is started non-interactively by calling one of the
74;;; isearch commands (e.g. isearch-forward), it does not return
75;;; until the search is completed. You should still be able switch
76;;; buffers, so be careful not to get things confused.
77;;;
78
79;;; Changes for 1.1
80;;; 3/18/92 Fixed invalid-regexp.
81;;; 3/18/92 Fixed yanking in regexps.
82
83;;; Code:
84
8e1cae6d
JB
85;;;=========================================================================
86;;; The following, defined in loaddefs.el, are still used with isearch-mode.
87
88;(defvar search-last-string ""
89; "Last string search for by a search command.
90;This does not include direct calls to the primitive search functions,
91;and does not include searches that are aborted.")
92
93;(defvar search-last-regexp ""
94; "Last string searched for by a regexp search command.
95;This does not include direct calls to the primitive search functions,
96;and does not include searches that are aborted.")
97
98;(defconst search-exit-option t
99; "Non-nil means random control characters terminate incremental search.")
100
101;(defvar search-slow-window-lines 1
102; "*Number of lines in slow search display windows.")
103
104;(defconst search-slow-speed 1200
105; "*Highest terminal speed at which to use \"slow\" style incremental search.
106;This is the style where a one-line window is created to show the line
107;that the search has reached.")
108
109;;;========================================================================
110;;; Some additional options and constants.
111
112(defvar search-caps-disable-folding t
113 "*If non-nil, upper case chars disable case fold searching.
114This does not yet apply to yanked strings, however.")
115
116(defvar search-nonincremental-instead t
117 "*If non-nil, do a nonincremental search instead if exiting immediately.
118The default value of t reflects the default behavior of old
119isearch.")
120
121(defconst search-whitespace-regexp "\\s-+"
122 "*If non-nil, regular expression to match a sequence of whitespace chars.
123You might want to use something like \"[ \\t\\r\\n]+\" instead.")
124
125;;;==================================================================
126;;; Search ring.
127;;; "regex" == "regexp". One should become the standard term.
128
129(defvar search-ring nil
130 "List of search string sequences.")
131(defvar regex-search-ring nil ;; Is `regex' the new spelling?
132 "List of regular expression search string sequences.")
133
134(defconst search-ring-max 16
135 "*Maximum length of search ring before oldest elements are thrown away.")
136(defconst regex-search-ring-max 16
137 "*Maximum length of regex search ring before oldest elements are thrown away.")
138
139(defvar search-ring-yank-pointer nil
140 "The tail of the search ring whose car is the last thing searched for.")
141(defvar regex-search-ring-yank-pointer nil
142 "The tail of the regular expression search ring whose car is the last
143thing searched for.")
144
145;;;====================================================
146;;; Define isearch-mode keymap.
147
148(defvar isearch-mode-map nil
149 "Keymap for isearch-mode.")
150
151(defvar isearch-mode-meta-map nil
152 "Keymap for isearch-mode for keys with meta char prefix.")
153
154
155;; To handle meta char prefix keys, define another full keymap.
156;; The same must be done for any other prefix keys.
157;; It would be simpler to disable to global keymap, and/or
158;; have a default local key binding for any key not otherwise bound.
159(if isearch-mode-meta-map
160 nil
161 (setq isearch-mode-meta-map
162 (list 'keymap (make-vector 128 'isearch-other-meta-char)))
163 (define-key isearch-mode-meta-map "n" 'isearch-ring-advance)
164 (define-key isearch-mode-meta-map "p" 'isearch-ring-retreat)
165 (define-key isearch-mode-meta-map " " 'isearch-whitespace-chars)
166;for regexps
167
168;; (define-key isearch-mode-meta-map "?" nil) ; my help key is M-?
169 )
170
171(if isearch-mode-map
172 nil
173 (let ((i 0)
174
175 ;; Printing chars extend the selection by default.
176 (array (make-vector 128 'isearch-printing-char)))
177
178 ;; Non-printing chars by default suspend isearch mode transparently
179 (while (< i ?\ )
180 (aset array i 'isearch-other-control-char)
181 (setq i (1+ i)))
182
183 (setq i ?A)
184 (while (<= i ?Z)
185 (aset array i 'isearch-upper-case-char)
186 (setq i (1+ i)))
187
188 (setq isearch-mode-map (list 'keymap array))
189
190 ;; You can reenable global keys by unbinding them locally.
191
192 ;; For the help char this doesnt work quite as expected because
193 ;; isearch-mode is not a major mode, and the echo area is not
194 ;; restored after the help command.
195 ;; Also, we should not assume that the help-command is on C-h.
196 ;; If it is not, and the prefix is not the meta-char, we would
197 ;; have to create another map for its prefix.
198; (define-key isearch-mode-map "\C-h" nil)
199
200 ;; Several non-printing chars change the searching behavior.
201 (define-key isearch-mode-map "\C-s" 'isearch-repeat-forward)
202 (define-key isearch-mode-map "\C-r" 'isearch-repeat-backward)
203 (define-key isearch-mode-map "\177" 'isearch-delete-char)
204 (define-key isearch-mode-map "\C-g" 'isearch-quit)
205
206
207 (define-key isearch-mode-map "\C-q" 'isearch-quote-char)
208
209 ;; (define-key isearch-mode-map "\r" 'isearch-return-char)
210 ;; For version 19, CR (C-m) terminates search and LFD (C-j) matches eol.
211 (define-key isearch-mode-map "\r" 'isearch-exit)
212 (define-key isearch-mode-map "\C-j" 'isearch-printing-char)
213
214
215 (define-key isearch-mode-map "\C-w" 'isearch-yank-word)
216 (define-key isearch-mode-map "\C-y" 'isearch-yank-line)
217
218 (define-key isearch-mode-map "\C-t" 'isearch-toggle-regexp)
219 (define-key isearch-mode-map "\C-^" 'isearch-edit-string)
220
221 ;; define keys for regexp chars * ? |
222 (define-key isearch-mode-map "*" 'isearch-*-char)
223 (define-key isearch-mode-map "?" 'isearch-*-char)
224 (define-key isearch-mode-map "|" 'isearch-|-char)
225
226 ;; Assumes meta-prefix-char is \e.
227 ;; isearch-mode-meta-map must be a keymap before this.
228 (define-key isearch-mode-map "\e" isearch-mode-meta-map)
229 ))
230
231;;;========================================================
232;; Internal variables declared globally for byte-compiler.
233;; These are all made buffer-local during searching.
234
235(defvar isearch-cmds nil
236 "Stack of search status sets.")
237(defvar isearch-string ""
238 "The current search string.")
239(defvar isearch-message ""
240 "The text-char-description version of isearch-string")
241(defvar isearch-success t)
242(defvar isearch-forward nil)
243(defvar isearch-other-end nil
244 "Start of last match if forward, end if backward.")
245(defvar isearch-invalid-regexp nil)
246(defvar isearch-wrapped nil)
247(defvar isearch-barrier 0)
248
249(defvar isearch-regexp nil)
250(defvar isearch-case-fold-search nil
251 "Value of case-fold-search while actually searching.")
252
253(defvar isearch-adjusted nil)
254(defvar isearch-slow-terminal-mode nil)
255(defvar isearch-small-window nil
256 "If t, using a small window.")
257(defvar isearch-found-point nil
258 "to restore point from a small window.")
259
260(defvar isearch-found-start nil
261 "This is the window-start value found by the search.")
262(defvar isearch-opoint 0)
263(defvar isearch-window-configuration nil
264 "The window configuration active at the beginning of the search.")
265(defvar isearch-old-local-map [])
266
267(defvar isearch-yank-flag nil
268 "Flag to indicate a yank occurred, so don't move the cursor.")
269
270(defvar isearch-op-fun nil
271 "A function to be called after each input character is processed.
272(It is not called after characters that exit the search.)
273It is only set from an optional argument to `isearch-mode'.")
274
275;; This is a global variable to avoid byte-compile warnings.
276(defvar isearch-last-command-char -1
277 "Last command char.")
278
279(defvar isearch-mode-hook nil
280 "List of functions to call after starting up an incremental search.
281See `isearch-modal' for an example.
282Set with `(setq isearch-mode-hook (cons 'myhook isearch-mode-hook))
283where myhook can be a function name or lambda expression.")
284
285(defvar isearch-mode-end-hook nil
286 "List of functions to call after terminating an incremental search.
287See `isearch-mode-hook' for more details.")
288
289;;;==============================================================
290;; Minor-mode-alist changes - kind of redundant with the
291;; echo area, but if isearching in multiple windows, it can be useful.
292
293(or (assq 'isearch-mode minor-mode-alist)
294 (nconc minor-mode-alist
295 (list '(isearch-mode isearch-mode))))
296
297(defvar isearch-mode nil)
298(make-variable-buffer-local 'isearch-mode)
299
300;;;===============================================================
301;;; Entry points to isearch-mode.
302;;; These four functions should be moved to loaddefs.el
303
304(defun isearch-forward ()
305 "\
306Do incremental search forward.
307As you type characters, they add to the search string and are found.
308
309\\<isearch-mode-map>
310Type \\[isearch-delete-char] to cancel characters from end of search
311string.
312Type \\[isearch-exit] to exit, leaving point at location found.
313Type \\[isearch-repeat-forward] to search again forward,
314\\[isearch-repeat-backward] to search again backward.
315Type \\[isearch-toggle-regexp] to toggle regular expression with normal searching.
316Type \\[isearch-yank-word] to yank word from buffer onto end of
317search string and search for it.
318Type \\[isearch-yank-line] to yank rest of line onto end of search string, etc.
319Type \\[isearch-quote-char] to quote control character to search for it.
320Type C-j to match end of line.
321
322Also supported is a search ring of the previous 16 search strings.
323Type \\[isearch-ring-advance] to search for the next item in the search ring.
324Type \\[isearch-ring-retreat] to search for the previous item in the search ring.
325
326Other control and meta characters terminate the search
327 and are then executed normally.
328
329\\[isearch-quit] while searching or when search has failed
330 cancels input back to what has been found successfully.
331\\[isearch-quit] when search is successful aborts and moves point to starting point.
332
333All of these keys are bound in `isearch-mode-map' and
334`isearch-mode-meta-map'. If `isearch-forward' is called
335non-interactively, it does not return to the calling function until
336the search is done."
337 (interactive)
338 (if (interactive-p)
339 (isearch-mode t)
340 (isearch-modal t)))
341
342(defun isearch-forward-regexp ()
343 "\
344Do incremental search forward for regular expression.
345Like ordinary incremental search except that your input
346is treated as a regexp. See \\[isearch-forward] for more info."
347 (interactive)
348 (if (interactive-p)
349 (isearch-mode t t)
350 (isearch-modal t t)))
351
352(defun isearch-backward ()
353 "\
354Do incremental search backward.
355See \\[isearch-forward] for more information."
356 (interactive)
357 (if (interactive-p)
358 (isearch-mode nil)
359 (isearch-modal nil)))
360
361(defun isearch-backward-regexp ()
362 "\
363Do incremental search backward for regular expression.
364Like ordinary incremental search except that your input
365is treated as a regexp. See \\[isearch-forward] for more info."
366 (interactive)
367 (if (interactive-p)
368 (isearch-mode nil t)
369 (isearch-modal nil t)))
370
371
372(defun isearch-modal (forward &optional regexp op-fun)
373 ;; As an example of using the hooks, isearch-mode can be made
374 ;; modal (in the sense of not returning to the calling function
375 ;; until searching is completed) by entering a recursive-edit.
376 ;; This is used if the above functions are called non-interactively.
377 (let ((isearch-mode-hook
378 (cons (function (lambda () (recursive-edit)))
379 isearch-mode-hook))
380 (isearch-mode-end-hook
381 (cons (function (lambda () (exit-recursive-edit)))
382 isearch-mode-end-hook)))
383 (isearch-mode forward regexp op-fun)))
384
385\f
386;;;==================================================================
387;; isearch-mode only sets up incremental search for the minor mode.
388;; All the work is done by the isearch-mode commands.
389
390(defun isearch-mode (forward &optional regexp op-fun)
391 "Start isearch minor mode. Called by isearch-forward, etc."
392 ;; Make buffer-local variables for isearching.
393 ;; We really need window-local variables.
394 (mapcar
395 'make-local-variable
396 '(isearch-forward
397 isearch-regexp isearch-string isearch-message
398 isearch-case-fold-search
399 isearch-cmds isearch-success isearch-wrapped
400 isearch-barrier isearch-adjusted isearch-invalid-regexp
401 isearch-slow-terminal-mode isearch-other-end isearch-small-window
402 isearch-found-point isearch-found-start isearch-opoint
403 isearch-window-configuration isearch-old-local-map))
404
405 ;; Initialize global vars.
406 (setq isearch-forward forward
407 isearch-regexp regexp
408 isearch-op-fun op-fun
409 isearch-case-fold-search case-fold-search
410 isearch-string ""
411 isearch-message ""
412 isearch-cmds nil
413 isearch-success t
414 isearch-wrapped nil
415 isearch-barrier (point)
416 isearch-adjusted nil
417 isearch-yank-flag nil
418 isearch-invalid-regexp nil
419 isearch-slow-terminal-mode (and (<= (baud-rate) search-slow-speed)
420 (> (window-height)
421 (* 4 search-slow-window-lines)))
422 isearch-other-end nil
423 isearch-small-window nil
424 isearch-found-point nil
425
426 isearch-found-start nil
427 isearch-opoint (point)
428 isearch-window-configuration (current-window-configuration)
429 isearch-old-local-map (current-local-map)
430
431;; inhibit-quit t
432 )
433 (setq isearch-mode " Isearch") ;; forward? regexp?
434 (set-buffer-modified-p (buffer-modified-p)) ; update modeline
435
436 (isearch-push-state)
437
438 (use-local-map isearch-mode-map)
439 (isearch-update)
440 (run-hooks 'isearch-mode-hook)
441 )
442
443
444;;;====================================================
445;; Some high level utilities. Others below.
446
447(defun isearch-update ()
448 ;; Called after each command to update the display.
449 (or unread-command-char
450 (progn
451 (if (not (input-pending-p))
452 (isearch-message))
453 (if (and isearch-slow-terminal-mode
454 (not (or isearch-small-window
455 (pos-visible-in-window-p))))
456 (progn
457 (setq isearch-small-window t)
458 (setq isearch-found-point (point))
459 (move-to-window-line 0)
460 (let ((window-min-height 1))
461 (split-window nil (if (< search-slow-window-lines 0)
462 (1+ (- search-slow-window-lines))
463 (- (window-height)
464 (1+ search-slow-window-lines)))))
465 (if (< search-slow-window-lines 0)
466 (progn (vertical-motion (- 1 search-slow-window-lines))
467 (set-window-start (next-window) (point))
468 (set-window-hscroll (next-window)
469 (window-hscroll))
470 (set-window-hscroll (selected-window) 0))
471 (other-window 1))
472 (goto-char isearch-found-point)))))
473 (setq ;; quit-flag nil not for isearch-mode
474 isearch-adjusted nil
475 isearch-yank-flag nil)
476 )
477
478
479(defun isearch-done ()
480 ;; Called by all commands that terminate isearch-mode.
481 (use-local-map isearch-old-local-map)
482 (setq isearch-found-start (window-start (selected-window)))
483 (setq isearch-found-point (point))
484 (set-window-configuration isearch-window-configuration)
485
486 (if (> (length isearch-string) 0)
487 ;; Update the ring data.
488 (if isearch-regexp
489 (if (not (setq regex-search-ring-yank-pointer
490 (memq isearch-string regex-search-ring)))
491 (progn
492 (setq regex-search-ring (cons isearch-string regex-search-ring)
493 regex-search-ring-yank-pointer regex-search-ring)
494 (if (> (length regex-search-ring) regex-search-ring-max)
495 (setcdr (nthcdr (1- search-ring-max) regex-search-ring)
496 nil))))
497 (if (not (setq search-ring-yank-pointer
498 (memq isearch-string search-ring)))
499 (progn
500 (setq search-ring (cons isearch-string search-ring)
501 search-ring-yank-pointer search-ring)
502 (if (> (length search-ring) search-ring-max)
503 (setcdr (nthcdr (1- search-ring-max) search-ring) nil))))))
504
505 ;; If there was movement, mark the starting position.
506 ;; Maybe should test difference between and set mark iff > threshold.
507 (if (/= (point) isearch-opoint)
508 (push-mark isearch-opoint)
509 (message ""))
510 (if isearch-small-window
511 (goto-char isearch-found-point)
512 ;; Exiting the save-window-excursion clobbers window-start; restore it.
513 (set-window-start (selected-window) isearch-found-start t))
514
515 ;; Kill buffer-local variables for isearching
516 (mapcar
517 'kill-local-variable
518 '(isearch-forward
519 isearch-regexp isearch-string isearch-message
520 isearch-case-fold-search
521 isearch-cmds isearch-success isearch-wrapped
522 isearch-barrier isearch-adjusted isearch-invalid-regexp
523 isearch-slow-terminal-mode isearch-other-end isearch-small-window
524 isearch-found-point isearch-found-start isearch-opoint
525 isearch-window-configuration isearch-old-local-map))
526
527 (setq isearch-mode nil)
528 (set-buffer-modified-p (buffer-modified-p))
529 (run-hooks 'isearch-mode-end-hook)
530 )
531
532\f
533;;;====================================================
534;; Commands active while inside of the isearch minor mode.
535
536(defun isearch-exit ()
537 "Exit search normally.
538However, if this is the first command after starting incremental
539search and `search-nonincremental-instead' is non-nil, do a
540nonincremental search instead."
541
542 (interactive)
543 (if (and search-nonincremental-instead
544 (= 0 (length isearch-string)))
545 (nonincremental-search isearch-forward isearch-regexp))
546 (isearch-done))
547
548
549(defun isearch-edit-string ()
550 "Edit the search string in the minibuffer and return to incremental search."
551 ;; This doesnt back up the search point.
552 (interactive)
553 (setq isearch-string (read-string (isearch-message-prefix) isearch-string)
554 isearch-message (mapconcat 'text-char-description
555 isearch-string ""))
556 (isearch-push-state)
557 (isearch-search)
558 (isearch-update))
559
560
561(defun isearch-quit ()
562 "Quit incremental search mode if searching is successful.
563Otherwise, revert to previous successful search and continue searching."
564 (interactive)
565 (ding)
566 (discard-input)
567 (if isearch-success
568 ;; If search is successful, move back to starting point
569 ;; and really do quit.
570 (progn (goto-char isearch-opoint)
571 (isearch-done)) ; exit and quit
572 ;; If search is failing, rub out until it is once more
573 ;; successful.
574 (while (not isearch-success) (isearch-pop-state))
575 (isearch-update)))
576
577
578(defun isearch-repeat (direction)
579 ;; Utility for isearch-repeat-forward and -backward.
580 (if (eq isearch-forward (eq direction 'forward))
581 ;; C-s in forward or C-r in reverse.
582 (if (equal isearch-string "")
583 ;; If search string is empty, use last one.
584 (setq isearch-string
585;; (if isearch-regexp
586;; search-last-regexp search-last-string)
587 (or (if isearch-regexp
588 (if regex-search-ring-yank-pointer
589 (car regex-search-ring-yank-pointer)
590 (car regex-search-ring))
591 (if search-ring-yank-pointer
592 (car search-ring-yank-pointer)
593 (car search-ring)))
594 "")
595 isearch-message
596 (mapconcat 'text-char-description
597 isearch-string ""))
598 ;; If already have what to search for, repeat it.
599 (or isearch-success
600 (progn
601
602 (goto-char (if isearch-forward (point-min) (point-max)))
603 (setq isearch-wrapped t))))
604 ;; C-s in reverse or C-r in forward, change direction.
605 (setq isearch-forward (not isearch-forward)))
606
607 (setq isearch-barrier (point)) ; For subsequent \| if regexp.
608 (setq isearch-success t)
609 (or (equal isearch-string "")
610 (progn
611 ;; If repeating a search that found
612 ;; an empty string, ensure we advance.
613 (if (equal (match-end 0) (match-beginning 0))
614 (forward-char (if isearch-forward 1 -1)))
615 (isearch-search)))
616 (isearch-push-state)
617 (isearch-update))
618
619(defun isearch-repeat-forward ()
620 "Repeat incremental search forwards."
621 (interactive)
622 (isearch-repeat 'forward))
623
624(defun isearch-repeat-backward ()
625 "Repeat incremental search backwards."
626 (interactive)
627 (isearch-repeat 'backward))
628
629(defun isearch-toggle-regexp ()
630 "Toggle regexp searching on or off."
631 ;; The status stack is left unchanged.
632 (interactive)
633 (setq isearch-regexp (not isearch-regexp))
634 (isearch-update))
635
636(defun isearch-delete-char ()
637 "Discard last input item and move point back.
638If no previous match was done, just beep."
639 (interactive)
640 (if (null (cdr isearch-cmds))
641 (ding)
642 (isearch-pop-state))
643 (isearch-update))
644
645
646(defun isearch-yank (chunk)
647 ;; Helper for isearch-yank-word and isearch-yank-line
648 (let ((word (save-excursion
649 (and (not isearch-forward) isearch-other-end
650 (goto-char isearch-other-end))
651 (buffer-substring
652 (point)
653 (save-excursion
654 (cond
655 ((eq chunk 'word)
656 (forward-word 1))
657 ((eq chunk 'line)
658 (end-of-line)))
659 (point))))))
660 (if isearch-regexp (setq word (regexp-quote word)))
661 (setq isearch-string (concat isearch-string word)
662 isearch-message
663 (concat isearch-message
664 (mapconcat 'text-char-description
665 word ""))
666 ;; Don't move cursor in reverse search.
667 isearch-yank-flag t))
668 (isearch-search-and-update))
669
670
671(defun isearch-yank-word ()
672 "Pull next word from buffer into search string."
673 (interactive)
674 (isearch-yank 'word))
675
676(defun isearch-yank-line ()
677 "Pull rest of line from buffer into search string."
678 (interactive)
679 (isearch-yank 'line))
680
681
682(defun isearch-search-and-update ()
683 ;; Do the search and update the display.
684 (if (and (not isearch-success)
685 ;; unsuccessful regexp search may become
686 ;; successful by addition of characters which
687 ;; make isearch-string valid
688 (not isearch-regexp))
689 nil
690 ;; In reverse search, adding stuff at
691 ;; the end may cause zero or many more chars to be
692 ;; matched, in the string following point.
693 ;; Allow all those possibilities without moving point as
694 ;; long as the match does not extend past search origin.
695 (if (and (not isearch-forward) (not isearch-adjusted)
696 (condition-case ()
697 (looking-at (if isearch-regexp isearch-string
698 (regexp-quote isearch-string)))
699 (error nil))
700 (or isearch-yank-flag
701 (<= (match-end 0)
702 (min isearch-opoint isearch-barrier))))
703 (setq isearch-success t
704 isearch-invalid-regexp nil
705 isearch-other-end (match-end 0))
706 ;; Not regexp, not reverse, or no match at point.
707 (if (and isearch-other-end (not isearch-adjusted))
708 (goto-char (if isearch-forward isearch-other-end
709 (min isearch-opoint
710 isearch-barrier
711 (1+ isearch-other-end)))))
712 (isearch-search)
713 ))
714 (isearch-push-state)
715 (if isearch-op-fun (funcall isearch-op-fun))
716 (isearch-update))
717
718
719;; *, ?, and | chars can make a regexp more liberal.
720;; They can make a regexp match sooner
721;; or make it succeed instead of failing.
722;; So go back to place last successful search started
723;; or to the last ^S/^R (barrier), whichever is nearer.
724
725(defun isearch-*-char ()
726 "Handle * and ? specially in regexps."
727 (interactive)
728 (if isearch-regexp
729
730 (progn
731 (setq isearch-adjusted t)
732 (let ((cs (nth (if isearch-forward
733 5 ; isearch-other-end
734 2) ; saved (point)
735 (car (cdr isearch-cmds)))))
736 ;; (car isearch-cmds) is after last search;
737 ;; (car (cdr isearch-cmds)) is from before it.
738 (setq cs (or cs isearch-barrier))
739 (goto-char
740 (if isearch-forward
741 (max cs isearch-barrier)
742 (min cs isearch-barrier))))))
743 (isearch-process-search-char last-command-char))
744
745
746
747(defun isearch-|-char ()
748 "If in regexp search, jump to the barrier."
749 (interactive)
750 (if isearch-regexp
751 (progn
752 (setq isearch-adjusted t)
753 (goto-char isearch-barrier)))
754 (isearch-process-search-char last-command-char))
755
756
757
758(defun isearch-other-control-char ()
759 "Any other control char => unread it and exit the search normally.
760But only if `search-exit-option' is non-nil."
761 (interactive)
762 (if search-exit-option
763 (progn
764 (setq unread-command-char last-command-char)
765 (isearch-done))
766 ;; otherwise
767 (isearch-search-and-update)))
768
769
770(defun isearch-other-meta-char ()
771 "Any other meta char => exit the search normally and reexecute the whole key.
772But only if `search-exit-option' is non-nil."
773 ;; This will probably work in place of isearch-other-control-char too,
774 ;; but here we use unwind-protect and command-execute since it is
775 ;; a multi-char key we would want to unread.
776 (interactive)
777 (if search-exit-option
778 (unwind-protect
779 (isearch-done) ;; this exits recursive edit
780 ;; Reexecute the key.
781 (command-execute (this-command-keys)))
782 ;; otherwise
783 (isearch-search-and-update)))
784
785
786(defun isearch-quote-char ()
787 "Quote special characters for incremental search."
788 (interactive)
789 (isearch-process-search-char (read-quoted-char (isearch-message t))))
790
791
792(defun isearch-return-char ()
793 "Convert return into newline for incremental search.
794Obsolete."
795 (interactive)
796 (isearch-process-search-char ?\n))
797
798
799(defun isearch-printing-char ()
800 "Any other printing character => add it to the search string and search."
801 (interactive)
802 (isearch-process-search-char last-command-char))
803
804
805(defun isearch-upper-case-char ()
806 "Any upper case char => turn off case fold search for remainder of search."
807 ;; This feature only applies to interactively entered chars,
808 ;; but not yanked chars, repeat default searches, or search ring searches.
809 ;; Support for these should be easy to add.
810 (interactive)
811 (if search-caps-disable-folding
812 (setq isearch-case-fold-search nil))
813 (isearch-printing-char))
814
815(defun isearch-whitespace-chars ()
816 "Match all whitespace chars, if in regexp mode."
817 (interactive)
818 (if (and isearch-regexp search-whitespace-regexp)
819 (isearch-process-search-string search-whitespace-regexp " ")
820 (isearch-other-meta-char)))
821
822(defun isearch-process-search-char (char)
823 ;; Append the char to the search string, update the message and re-search.
824 (isearch-process-search-string (char-to-string char)
825
826 (text-char-description char)))
827
828(defun isearch-process-search-string (string message)
829 (setq isearch-string (concat isearch-string string)
830 isearch-message (concat isearch-message message))
831 (isearch-search-and-update))
832
833\f
834;;===========================================================
835;; Search Ring
836
837(defun isearch-ring-adjust (advance)
838 ;; helper for isearch-ring-advance and isearch-ring-retreat
839 (if (cdr isearch-cmds)
840 (isearch-pop-state))
841 (let* ((ring (if isearch-regexp regex-search-ring search-ring))
842 (length (length ring))
843 (yank-pointer-name (if isearch-regexp
844 'regex-search-ring-yank-pointer
845 'search-ring-yank-pointer))
846 (yank-pointer (eval yank-pointer-name)))
847 (if (zerop length)
848 ()
849 (set yank-pointer-name
850 (setq yank-pointer
851 (nthcdr (% (+ (- length (length yank-pointer))
852 (if advance (1- length) 1))
853 length) ring)))
854 (setq isearch-string (car yank-pointer)
855 isearch-message (mapconcat 'text-char-description
856 isearch-string ""))))
857 (isearch-push-state)
858 (isearch-search)
859 (isearch-update))
860
861(defun isearch-ring-advance ()
862 "Advance to the next search string in the ring."
863 (interactive)
864 (isearch-ring-adjust 'advance))
865
866(defun isearch-ring-retreat ()
867 "Retreat to the previous search string in the ring."
868 (interactive)
869 (isearch-ring-adjust nil))
870
871\f
872;;;=============================================================
873;; Window-local variables
874;; (not used yet - and maybe never)
875
876(defvar window-local-variable-alist nil
877 "An alist of windows associated with window local variables and values.
878The cdr of each item is another alist of variables and values.")
879
880(defvar last-local-window nil)
881(defvar last-window-local-vars nil)
882
883(defun kill-window-local-variables ()
884 "Remove the old variable list, if any."
885 (setq window-local-variable-alist
886 (delq window-local-variable-alist
887 (assq (selected-window)
888 window-local-variable-alist))))
889
890;; Assume that window-local variables are not buffer-local
891;; so we can delay storing until absolutely necessary.
892
893(defun store-window-local-variables (&rest vars-and-vals)
894 "Store the window local variables for selected window."
895 (setq last-local-window (selected-window))
896 (setq last-window-local-vars vars-and-vals))
897
898
899(defun fetch-window-local-variables ()
900 "Fetch the window local variables for selected window.
901Does nothing if the last store was for the same window."
902 (if (not (eq (selected-window) last-local-window))
903 (progn
904 ;; First store the previous values.
905 (setq window-local-variable-alist
906 (cons (cons last-local-window
907 last-window-local-vars)
908 (delq window-local-variable-alist
909 (assq last-local-window
910 window-local-variable-alist))))
911 ;; Now fetch the values for the selected-window.
912 (setq last-local-window (selected-window))
913 (setq last-window-local-vars
914 (cdr (assq last-local-window window-local-variable-alist)))
915 (let ((vars-and-vals last-window-local-vars))
916 (while vars-and-vals
917 (set (car vars-and-vals) (car (cdr vars-and-vals)))
918 (setq vars-and-vals (cdr (cdr vars-and-vals))))))))
919
920
921\f
922;;;==============================================================
923;; The search status stack (and isearch window-local variables, not used).
924
925(defun isearch-top-state ()
926;; (fetch-window-local-variables)
927 (let ((cmd (car isearch-cmds)))
928 (setq isearch-string (car cmd)
929 isearch-message (car (cdr cmd))
930 isearch-success (nth 3 cmd)
931 isearch-forward (nth 4 cmd)
932 isearch-other-end (nth 5 cmd)
933 isearch-invalid-regexp (nth 6 cmd)
934 isearch-wrapped (nth 7 cmd)
935 isearch-barrier (nth 8 cmd))
936 (goto-char (car (cdr (cdr cmd))))))
937
938(defun isearch-pop-state ()
939;; (fetch-window-local-variables)
940 (setq isearch-cmds (cdr isearch-cmds))
941 (isearch-top-state)
942 )
943
944(defun isearch-push-state ()
945 (setq isearch-cmds
946 (cons (list isearch-string isearch-message (point)
947 isearch-success isearch-forward isearch-other-end
948 isearch-invalid-regexp isearch-wrapped isearch-barrier)
949 isearch-cmds)))
950
951(defun isearch-store-variables ()
952 (store-window-local-variables
953 'isearch-cmds isearch-cmds
954 'isearch-regexp isearch-regexp
955 'isearch-adjusted isearch-adjusted
956 'isearch-slow-terminal-mode isearch-slow-terminal-mode
957 'isearch-small-window isearch-small-window
958 'isearch-found-point isearch-found-point
959 'isearch-found-start isearch-found-start
960 'isearch-opoint isearch-opoint
961 'isearch-window-configuration isearch-window-configuration
962 'isearch-old-local-map isearch-old-local-map
963 ))
964
965\f
966;;;==================================================================
967;; Message string
968
969(defun isearch-message (&optional c-q-hack ellipsis)
970 ;; Generate and print the message string.
971 (let ((cursor-in-echo-area ellipsis)
972 (m (concat
973 (isearch-message-prefix c-q-hack ellipsis)
974 isearch-message
975 (isearch-message-suffix c-q-hack ellipsis)
976 )))
977 (if c-q-hack m (message "%s" m))))
978
979(defun isearch-message-prefix (&optional c-q-hack ellipsis)
980 ;; If about to search, and previous search regexp was invalid,
981 ;; check that it still is. If it is valid now,
982 ;; let the message we display while searching say that it is valid.
983 (and isearch-invalid-regexp ellipsis
984 (condition-case ()
985 (progn (re-search-forward isearch-string (point) t)
986 (setq isearch-invalid-regexp nil))
987 (error nil)))
988 ;; If currently failing, display no ellipsis.
989 (or isearch-success (setq ellipsis nil))
990 (let ((m (concat (if isearch-success "" "failing ")
991 (if isearch-wrapped "wrapped ")
992 (if isearch-regexp "regexp " "")
993 "I-search"
994 (if isearch-forward ": " " backward: ")
995 )))
996 (aset m 0 (upcase (aref m 0)))
997 m))
998
999
1000(defun isearch-message-suffix (&optional c-q-hack ellipsis)
1001 (concat (if c-q-hack "^Q" "")
1002 (if isearch-invalid-regexp
1003 (concat " [" isearch-invalid-regexp "]")
1004 "")))
1005
1006\f
1007;;;========================================================
1008;;; Searching
1009
1010(defun isearch-search ()
1011 ;; Do the search with the current search string.
1012 (isearch-message nil t)
1013 (condition-case lossage
1014 (let ((inhibit-quit nil)
1015 (case-fold-search isearch-case-fold-search))
1016 (if isearch-regexp (setq isearch-invalid-regexp nil))
1017 (setq isearch-success
1018 (funcall
1019 (if isearch-regexp
1020 (if isearch-forward 're-search-forward 're-search-backward)
1021 (if isearch-forward 'search-forward 'search-backward))
1022 isearch-string nil t))
1023 (if isearch-success
1024 (setq isearch-other-end
1025 (if isearch-forward (match-beginning 0) (match-end 0)))))
1026
1027 (quit (setq unread-command-char ?\C-g)
1028 (setq isearch-success nil))
1029
1030 (invalid-regexp
1031 (setq isearch-invalid-regexp (car (cdr lossage)))
1032 (if (string-match
1033 "\\`Premature \\|\\`Unmatched \\|\\`Invalid "
1034 isearch-invalid-regexp)
1035 (setq isearch-invalid-regexp "incomplete input"))))
1036
1037 (if isearch-success
1038 nil
1039 ;; Ding if failed this time after succeeding last time.
1040 (and (nth 3 (car isearch-cmds))
1041 (ding))
1042 (goto-char (nth 2 (car isearch-cmds)))))
1043
1044;;;=================================================
1045;; This is called from incremental-search
1046;; if the first input character is the exit character.
1047
1048;; We store the search string in `isearch-string'
1049;; which has been bound already by `isearch-search'
1050;; so that, when we exit, it is copied into `search-last-string'.
1051
1052(defun nonincremental-search (forward regexp)
1053 ;; This may be broken. Anyway, it could be replaced by the
1054 ;; isearch-edit-string command instead.
1055 (setq isearch-forward forward
1056 isearch-regexp regexp)
1057 (let (char function
1058 inhibit-quit
1059 (cursor-in-echo-area t))
1060 ;; Prompt assuming not word search,
1061 (setq isearch-message
1062
1063 (if isearch-regexp
1064
1065 (if isearch-forward "Regexp search: "
1066 "Regexp search backward: ")
1067 (if isearch-forward "Search: " "Search backward: ")))
1068 (message "%s" isearch-message)
1069 ;; Read 1 char and switch to word search if it is ^W.
1070 (setq char (read-char))
1071 (if (eq char search-yank-word-char)
1072 (setq isearch-message (if isearch-forward "Word search: "
1073
1074 "Word search backward: "))
1075 ;; Otherwise let that 1 char be part of the search string.
1076 (setq unread-command-char char))
1077 (setq function
1078 (if (eq char search-yank-word-char)
1079 (if isearch-forward 'word-search-forward 'word-search-backward)
1080 (if isearch-regexp
1081 (if isearch-forward 're-search-forward 're-search-backward)
1082 (if isearch-forward 'search-forward 'search-backward))))
1083 ;; Read the search string with corrected prompt.
1084 (setq isearch-string (read-string isearch-message isearch-string))
1085 ;; Empty means use default.
1086 (if (= 0 (length isearch-string))
1087 (setq isearch-string search-last-string)
1088 ;; Set last search string now so it is set even if we fail.
1089 (setq search-last-string isearch-string))
1090 ;; Since we used the minibuffer, we should be available for redo.
1091 (setq command-history
1092
1093 (cons (list function isearch-string) command-history))
1094 ;; Go ahead and search.
1095 (let ((case-fold-search isearch-case-fold-search))
1096 (funcall function isearch-string))))