1 ;; isearch-mode.el --- incremental search minor mode.
3 ;; Copyright (C) 1992 Free Software Foundation, Inc.
5 ;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
8 ;; This file is part of GNU Emacs.
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.
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.
27 ;;;====================================================================
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.
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
39 ;; (fset 'isearch 'isearch-mode)
40 ;; (autoload 'isearch-mode "isearch-mode")
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.
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.
62 ;;;====================================================================
64 ;;; $Header: /import/kaplan/kaplan/liberte/Isearch/RCS/isearch-mode.el,v 1.2 92/05/27 11:33:57 liberte Exp Locker: liberte $
65 ;;; $Log: isearch-mode.el,v $
66 ;;; Revision 1.2 92/05/27 11:33:57 liberte
67 ;;; Several new commands and features have been added. Emacs version
68 ;;; 19 has a search ring, which is supported here. Other fixes found
69 ;;; in the version 19 isearch are included here. Also see variables
70 ;;; search-caps-disable-folding, search-nonincremental-instead,
71 ;;; search-whitespace-regexp, and commands isearch-toggle-regexp,
72 ;;; isearch-edit-string,
74 ;;; Semi-modal searching is supported, using a recursive edit. If
75 ;;; isearching is started non-interactively by calling one of the
76 ;;; isearch commands (e.g. isearch-forward), it does not return
77 ;;; until the search is completed. You should still be able switch
78 ;;; buffers, so be careful not to get things confused.
82 ;;; 3/18/92 Fixed invalid-regexp.
83 ;;; 3/18/92 Fixed yanking in regexps.
87 ;;;=========================================================================
88 ;;; The following, defined in loaddefs.el, are still used with isearch-mode.
90 ;(defvar search-last-string ""
91 ; "Last string search for by a search command.
92 ;This does not include direct calls to the primitive search functions,
93 ;and does not include searches that are aborted.")
95 ;(defvar search-last-regexp ""
96 ; "Last string searched for by a regexp search command.
97 ;This does not include direct calls to the primitive search functions,
98 ;and does not include searches that are aborted.")
100 ;(defconst search-exit-option t
101 ; "Non-nil means random control characters terminate incremental search.")
103 ;(defvar search-slow-window-lines 1
104 ; "*Number of lines in slow search display windows.")
106 ;(defconst search-slow-speed 1200
107 ; "*Highest terminal speed at which to use \"slow\" style incremental search.
108 ;This is the style where a one-line window is created to show the line
109 ;that the search has reached.")
111 ;;;========================================================================
112 ;;; Some additional options and constants.
114 (defvar search-caps-disable-folding t
115 "*If non-nil, upper case chars disable case fold searching.
116 This does not yet apply to yanked strings, however.")
118 (defvar search-nonincremental-instead t
119 "*If non-nil, do a nonincremental search instead if exiting immediately.
120 The default value of t reflects the default behavior of old
123 (defconst search-whitespace-regexp
"\\s-+"
124 "*If non-nil, regular expression to match a sequence of whitespace chars.
125 You might want to use something like \"[ \\t\\r\\n]+\" instead.")
127 ;;;==================================================================
129 ;;; "regex" == "regexp". One should become the standard term.
131 (defvar search-ring nil
132 "List of search string sequences.")
133 (defvar regex-search-ring nil
;; Is `regex' the new spelling?
134 "List of regular expression search string sequences.")
136 (defconst search-ring-max
16
137 "*Maximum length of search ring before oldest elements are thrown away.")
138 (defconst regex-search-ring-max
16
139 "*Maximum length of regex search ring before oldest elements are thrown away.")
141 (defvar search-ring-yank-pointer nil
142 "The tail of the search ring whose car is the last thing searched for.")
143 (defvar regex-search-ring-yank-pointer nil
144 "The tail of the regular expression search ring whose car is the last
145 thing searched for.")
147 ;;;====================================================
148 ;;; Define isearch-mode keymap.
150 (defvar isearch-mode-map nil
151 "Keymap for isearch-mode.")
153 (defvar isearch-mode-meta-map nil
154 "Keymap for isearch-mode for keys with meta char prefix.")
157 ;; To handle meta char prefix keys, define another full keymap.
158 ;; The same must be done for any other prefix keys.
159 ;; It would be simpler to disable to global keymap, and/or
160 ;; have a default local key binding for any key not otherwise bound.
161 (if isearch-mode-meta-map
163 (setq isearch-mode-meta-map
164 (list 'keymap
(make-vector 128 'isearch-other-meta-char
)))
165 (define-key isearch-mode-meta-map
"n" 'isearch-ring-advance
)
166 (define-key isearch-mode-meta-map
"p" 'isearch-ring-retreat
)
167 (define-key isearch-mode-meta-map
" " 'isearch-whitespace-chars
)
170 ;; (define-key isearch-mode-meta-map "?" nil) ; my help key is M-?
177 ;; Printing chars extend the selection by default.
178 (array (make-vector 128 'isearch-printing-char
)))
180 ;; Non-printing chars by default suspend isearch mode transparently
182 (aset array i
'isearch-other-control-char
)
187 (aset array i
'isearch-upper-case-char
)
190 (setq isearch-mode-map
(list 'keymap array
))
192 ;; You can reenable global keys by unbinding them locally.
194 ;; For the help char this doesnt work quite as expected because
195 ;; isearch-mode is not a major mode, and the echo area is not
196 ;; restored after the help command.
197 ;; Also, we should not assume that the help-command is on C-h.
198 ;; If it is not, and the prefix is not the meta-char, we would
199 ;; have to create another map for its prefix.
200 ; (define-key isearch-mode-map "\C-h" nil)
202 ;; Several non-printing chars change the searching behavior.
203 (define-key isearch-mode-map
"\C-s" 'isearch-repeat-forward
)
204 (define-key isearch-mode-map
"\C-r" 'isearch-repeat-backward
)
205 (define-key isearch-mode-map
"\177" 'isearch-delete-char
)
206 (define-key isearch-mode-map
"\C-g" 'isearch-quit
)
209 (define-key isearch-mode-map
"\C-q" 'isearch-quote-char
)
211 ;; (define-key isearch-mode-map "\r" 'isearch-return-char)
212 ;; For version 19, CR (C-m) terminates search and LFD (C-j) matches eol.
213 (define-key isearch-mode-map
"\r" 'isearch-exit
)
214 (define-key isearch-mode-map
"\C-j" 'isearch-printing-char
)
217 (define-key isearch-mode-map
"\C-w" 'isearch-yank-word
)
218 (define-key isearch-mode-map
"\C-y" 'isearch-yank-line
)
220 (define-key isearch-mode-map
"\C-t" 'isearch-toggle-regexp
)
221 (define-key isearch-mode-map
"\C-^" 'isearch-edit-string
)
223 ;; define keys for regexp chars * ? |
224 (define-key isearch-mode-map
"*" 'isearch-
*-char
)
225 (define-key isearch-mode-map
"?" 'isearch-
*-char
)
226 (define-key isearch-mode-map
"|" 'isearch-|-char
)
228 ;; Assumes meta-prefix-char is \e.
229 ;; isearch-mode-meta-map must be a keymap before this.
230 (define-key isearch-mode-map
"\e" isearch-mode-meta-map
)
233 ;;;========================================================
234 ;; Internal variables declared globally for byte-compiler.
235 ;; These are all made buffer-local during searching.
237 (defvar isearch-cmds nil
238 "Stack of search status sets.")
239 (defvar isearch-string
""
240 "The current search string.")
241 (defvar isearch-message
""
242 "The text-char-description version of isearch-string")
243 (defvar isearch-success t
)
244 (defvar isearch-forward nil
)
245 (defvar isearch-other-end nil
246 "Start of last match if forward, end if backward.")
247 (defvar isearch-invalid-regexp nil
)
248 (defvar isearch-wrapped nil
)
249 (defvar isearch-barrier
0)
251 (defvar isearch-regexp nil
)
252 (defvar isearch-case-fold-search nil
253 "Value of case-fold-search while actually searching.")
255 (defvar isearch-adjusted nil
)
256 (defvar isearch-slow-terminal-mode nil
)
257 (defvar isearch-small-window nil
258 "If t, using a small window.")
259 (defvar isearch-found-point nil
260 "to restore point from a small window.")
262 (defvar isearch-found-start nil
263 "This is the window-start value found by the search.")
264 (defvar isearch-opoint
0)
265 (defvar isearch-window-configuration nil
266 "The window configuration active at the beginning of the search.")
267 (defvar isearch-old-local-map
[])
269 (defvar isearch-yank-flag nil
270 "Flag to indicate a yank occurred, so don't move the cursor.")
272 (defvar isearch-op-fun nil
273 "A function to be called after each input character is processed.
274 (It is not called after characters that exit the search.)
275 It is only set from an optional argument to `isearch-mode'.")
277 ;; This is a global variable to avoid byte-compile warnings.
278 (defvar isearch-last-command-char -
1
279 "Last command char.")
281 (defvar isearch-mode-hook nil
282 "List of functions to call after starting up an incremental search.
283 See `isearch-modal' for an example.
284 Set with `(setq isearch-mode-hook (cons 'myhook isearch-mode-hook))
285 where myhook can be a function name or lambda expression.")
287 (defvar isearch-mode-end-hook nil
288 "List of functions to call after terminating an incremental search.
289 See `isearch-mode-hook' for more details.")
291 ;;;==============================================================
292 ;; Minor-mode-alist changes - kind of redundant with the
293 ;; echo area, but if isearching in multiple windows, it can be useful.
295 (or (assq 'isearch-mode minor-mode-alist
)
296 (nconc minor-mode-alist
297 (list '(isearch-mode isearch-mode
))))
299 (defvar isearch-mode nil
)
300 (make-variable-buffer-local 'isearch-mode
)
302 ;;;===============================================================
303 ;;; Entry points to isearch-mode.
304 ;;; These four functions should be moved to loaddefs.el
306 (defun isearch-forward ()
308 Do incremental search forward.
309 As you type characters, they add to the search string and are found.
312 Type \\[isearch-delete-char] to cancel characters from end of search
314 Type \\[isearch-exit] to exit, leaving point at location found.
315 Type \\[isearch-repeat-forward] to search again forward,
316 \\[isearch-repeat-backward] to search again backward.
317 Type \\[isearch-toggle-regexp] to toggle regular expression with normal searching.
318 Type \\[isearch-yank-word] to yank word from buffer onto end of
319 search string and search for it.
320 Type \\[isearch-yank-line] to yank rest of line onto end of search string, etc.
321 Type \\[isearch-quote-char] to quote control character to search for it.
322 Type C-j to match end of line.
324 Also supported is a search ring of the previous 16 search strings.
325 Type \\[isearch-ring-advance] to search for the next item in the search ring.
326 Type \\[isearch-ring-retreat] to search for the previous item in the search ring.
328 Other control and meta characters terminate the search
329 and are then executed normally.
331 \\[isearch-quit] while searching or when search has failed
332 cancels input back to what has been found successfully.
333 \\[isearch-quit] when search is successful aborts and moves point to starting point.
335 All of these keys are bound in `isearch-mode-map' and
336 `isearch-mode-meta-map'. If `isearch-forward' is called
337 non-interactively, it does not return to the calling function until
344 (defun isearch-forward-regexp ()
346 Do incremental search forward for regular expression.
347 Like ordinary incremental search except that your input
348 is treated as a regexp. See \\[isearch-forward] for more info."
352 (isearch-modal t t
)))
354 (defun isearch-backward ()
356 Do incremental search backward.
357 See \\[isearch-forward] for more information."
361 (isearch-modal nil
)))
363 (defun isearch-backward-regexp ()
365 Do incremental search backward for regular expression.
366 Like ordinary incremental search except that your input
367 is treated as a regexp. See \\[isearch-forward] for more info."
371 (isearch-modal nil t
)))
374 (defun isearch-modal (forward &optional regexp op-fun
)
375 ;; As an example of using the hooks, isearch-mode can be made
376 ;; modal (in the sense of not returning to the calling function
377 ;; until searching is completed) by entering a recursive-edit.
378 ;; This is used if the above functions are called non-interactively.
379 (let ((isearch-mode-hook
380 (cons (function (lambda () (recursive-edit)))
382 (isearch-mode-end-hook
383 (cons (function (lambda () (exit-recursive-edit)))
384 isearch-mode-end-hook
)))
385 (isearch-mode forward regexp op-fun
)))
388 ;;;==================================================================
389 ;; isearch-mode only sets up incremental search for the minor mode.
390 ;; All the work is done by the isearch-mode commands.
392 (defun isearch-mode (forward &optional regexp op-fun
)
393 "Start isearch minor mode. Called by isearch-forward, etc."
394 ;; Make buffer-local variables for isearching.
395 ;; We really need window-local variables.
399 isearch-regexp isearch-string isearch-message
400 isearch-case-fold-search
401 isearch-cmds isearch-success isearch-wrapped
402 isearch-barrier isearch-adjusted isearch-invalid-regexp
403 isearch-slow-terminal-mode isearch-other-end isearch-small-window
404 isearch-found-point isearch-found-start isearch-opoint
405 isearch-window-configuration isearch-old-local-map
))
407 ;; Initialize global vars.
408 (setq isearch-forward forward
409 isearch-regexp regexp
410 isearch-op-fun op-fun
411 isearch-case-fold-search case-fold-search
417 isearch-barrier
(point)
419 isearch-yank-flag nil
420 isearch-invalid-regexp nil
421 isearch-slow-terminal-mode
(and (<= (baud-rate) search-slow-speed
)
423 (* 4 search-slow-window-lines
)))
424 isearch-other-end nil
425 isearch-small-window nil
426 isearch-found-point nil
428 isearch-found-start nil
429 isearch-opoint
(point)
430 isearch-window-configuration
(current-window-configuration)
431 isearch-old-local-map
(current-local-map)
435 (setq isearch-mode
" Isearch") ;; forward? regexp?
436 (set-buffer-modified-p (buffer-modified-p)) ; update modeline
440 (use-local-map isearch-mode-map
)
442 (run-hooks 'isearch-mode-hook
)
446 ;;;====================================================
447 ;; Some high level utilities. Others below.
449 (defun isearch-update ()
450 ;; Called after each command to update the display.
451 (or unread-command-char
453 (if (not (input-pending-p))
455 (if (and isearch-slow-terminal-mode
456 (not (or isearch-small-window
457 (pos-visible-in-window-p))))
459 (setq isearch-small-window t
)
460 (setq isearch-found-point
(point))
461 (move-to-window-line 0)
462 (let ((window-min-height 1))
463 (split-window nil
(if (< search-slow-window-lines
0)
464 (1+ (- search-slow-window-lines
))
466 (1+ search-slow-window-lines
)))))
467 (if (< search-slow-window-lines
0)
468 (progn (vertical-motion (- 1 search-slow-window-lines
))
469 (set-window-start (next-window) (point))
470 (set-window-hscroll (next-window)
472 (set-window-hscroll (selected-window) 0))
474 (goto-char isearch-found-point
)))))
475 (setq ;; quit-flag nil not for isearch-mode
477 isearch-yank-flag nil
)
481 (defun isearch-done ()
482 ;; Called by all commands that terminate isearch-mode.
483 (use-local-map isearch-old-local-map
)
484 (setq isearch-found-start
(window-start (selected-window)))
485 (setq isearch-found-point
(point))
486 (set-window-configuration isearch-window-configuration
)
488 (if (> (length isearch-string
) 0)
489 ;; Update the ring data.
491 (if (not (setq regex-search-ring-yank-pointer
492 (memq isearch-string regex-search-ring
)))
494 (setq regex-search-ring
(cons isearch-string regex-search-ring
)
495 regex-search-ring-yank-pointer regex-search-ring
)
496 (if (> (length regex-search-ring
) regex-search-ring-max
)
497 (setcdr (nthcdr (1- search-ring-max
) regex-search-ring
)
499 (if (not (setq search-ring-yank-pointer
500 (memq isearch-string search-ring
)))
502 (setq search-ring
(cons isearch-string search-ring
)
503 search-ring-yank-pointer search-ring
)
504 (if (> (length search-ring
) search-ring-max
)
505 (setcdr (nthcdr (1- search-ring-max
) search-ring
) nil
))))))
507 ;; If there was movement, mark the starting position.
508 ;; Maybe should test difference between and set mark iff > threshold.
509 (if (/= (point) isearch-opoint
)
510 (push-mark isearch-opoint
)
512 (if isearch-small-window
513 (goto-char isearch-found-point
)
514 ;; Exiting the save-window-excursion clobbers window-start; restore it.
515 (set-window-start (selected-window) isearch-found-start t
))
517 ;; Kill buffer-local variables for isearching
521 isearch-regexp isearch-string isearch-message
522 isearch-case-fold-search
523 isearch-cmds isearch-success isearch-wrapped
524 isearch-barrier isearch-adjusted isearch-invalid-regexp
525 isearch-slow-terminal-mode isearch-other-end isearch-small-window
526 isearch-found-point isearch-found-start isearch-opoint
527 isearch-window-configuration isearch-old-local-map
))
529 (setq isearch-mode nil
)
530 (set-buffer-modified-p (buffer-modified-p))
531 (run-hooks 'isearch-mode-end-hook
)
535 ;;;====================================================
536 ;; Commands active while inside of the isearch minor mode.
538 (defun isearch-exit ()
539 "Exit search normally.
540 However, if this is the first command after starting incremental
541 search and `search-nonincremental-instead' is non-nil, do a
542 nonincremental search instead."
545 (if (and search-nonincremental-instead
546 (= 0 (length isearch-string
)))
547 (nonincremental-search isearch-forward isearch-regexp
))
551 (defun isearch-edit-string ()
552 "Edit the search string in the minibuffer and return to incremental search."
553 ;; This doesnt back up the search point.
555 (setq isearch-string
(read-string (isearch-message-prefix) isearch-string
)
556 isearch-message
(mapconcat 'text-char-description
563 (defun isearch-quit ()
564 "Quit incremental search mode if searching is successful.
565 Otherwise, revert to previous successful search and continue searching."
570 ;; If search is successful, move back to starting point
571 ;; and really do quit.
572 (progn (goto-char isearch-opoint
)
573 (isearch-done)) ; exit and quit
574 ;; If search is failing, rub out until it is once more
576 (while (not isearch-success
) (isearch-pop-state))
580 (defun isearch-repeat (direction)
581 ;; Utility for isearch-repeat-forward and -backward.
582 (if (eq isearch-forward
(eq direction
'forward
))
583 ;; C-s in forward or C-r in reverse.
584 (if (equal isearch-string
"")
585 ;; If search string is empty, use last one.
587 ;; (if isearch-regexp
588 ;; search-last-regexp search-last-string)
589 (or (if isearch-regexp
590 (if regex-search-ring-yank-pointer
591 (car regex-search-ring-yank-pointer
)
592 (car regex-search-ring
))
593 (if search-ring-yank-pointer
594 (car search-ring-yank-pointer
)
598 (mapconcat 'text-char-description
600 ;; If already have what to search for, repeat it.
604 (goto-char (if isearch-forward
(point-min) (point-max)))
605 (setq isearch-wrapped t
))))
606 ;; C-s in reverse or C-r in forward, change direction.
607 (setq isearch-forward
(not isearch-forward
)))
609 (setq isearch-barrier
(point)) ; For subsequent \| if regexp.
610 (setq isearch-success t
)
611 (or (equal isearch-string
"")
613 ;; If repeating a search that found
614 ;; an empty string, ensure we advance.
615 (if (equal (match-end 0) (match-beginning 0))
616 (forward-char (if isearch-forward
1 -
1)))
621 (defun isearch-repeat-forward ()
622 "Repeat incremental search forwards."
624 (isearch-repeat 'forward
))
626 (defun isearch-repeat-backward ()
627 "Repeat incremental search backwards."
629 (isearch-repeat 'backward
))
631 (defun isearch-toggle-regexp ()
632 "Toggle regexp searching on or off."
633 ;; The status stack is left unchanged.
635 (setq isearch-regexp
(not isearch-regexp
))
638 (defun isearch-delete-char ()
639 "Discard last input item and move point back.
640 If no previous match was done, just beep."
642 (if (null (cdr isearch-cmds
))
648 (defun isearch-yank (chunk)
649 ;; Helper for isearch-yank-word and isearch-yank-line
650 (let ((word (save-excursion
651 (and (not isearch-forward
) isearch-other-end
652 (goto-char isearch-other-end
))
662 (if isearch-regexp
(setq word
(regexp-quote word
)))
663 (setq isearch-string
(concat isearch-string word
)
665 (concat isearch-message
666 (mapconcat 'text-char-description
668 ;; Don't move cursor in reverse search.
669 isearch-yank-flag t
))
670 (isearch-search-and-update))
673 (defun isearch-yank-word ()
674 "Pull next word from buffer into search string."
676 (isearch-yank 'word
))
678 (defun isearch-yank-line ()
679 "Pull rest of line from buffer into search string."
681 (isearch-yank 'line
))
684 (defun isearch-search-and-update ()
685 ;; Do the search and update the display.
686 (if (and (not isearch-success
)
687 ;; unsuccessful regexp search may become
688 ;; successful by addition of characters which
689 ;; make isearch-string valid
690 (not isearch-regexp
))
692 ;; In reverse search, adding stuff at
693 ;; the end may cause zero or many more chars to be
694 ;; matched, in the string following point.
695 ;; Allow all those possibilities without moving point as
696 ;; long as the match does not extend past search origin.
697 (if (and (not isearch-forward
) (not isearch-adjusted
)
699 (looking-at (if isearch-regexp isearch-string
700 (regexp-quote isearch-string
)))
702 (or isearch-yank-flag
704 (min isearch-opoint isearch-barrier
))))
705 (setq isearch-success t
706 isearch-invalid-regexp nil
707 isearch-other-end
(match-end 0))
708 ;; Not regexp, not reverse, or no match at point.
709 (if (and isearch-other-end
(not isearch-adjusted
))
710 (goto-char (if isearch-forward isearch-other-end
713 (1+ isearch-other-end
)))))
717 (if isearch-op-fun
(funcall isearch-op-fun
))
721 ;; *, ?, and | chars can make a regexp more liberal.
722 ;; They can make a regexp match sooner
723 ;; or make it succeed instead of failing.
724 ;; So go back to place last successful search started
725 ;; or to the last ^S/^R (barrier), whichever is nearer.
727 (defun isearch-*-char
()
728 "Handle * and ? specially in regexps."
733 (setq isearch-adjusted t
)
734 (let ((cs (nth (if isearch-forward
735 5 ; isearch-other-end
737 (car (cdr isearch-cmds
)))))
738 ;; (car isearch-cmds) is after last search;
739 ;; (car (cdr isearch-cmds)) is from before it.
740 (setq cs
(or cs isearch-barrier
))
743 (max cs isearch-barrier
)
744 (min cs isearch-barrier
))))))
745 (isearch-process-search-char last-command-char
))
749 (defun isearch-|-char
()
750 "If in regexp search, jump to the barrier."
754 (setq isearch-adjusted t
)
755 (goto-char isearch-barrier
)))
756 (isearch-process-search-char last-command-char
))
760 (defun isearch-other-control-char ()
761 "Any other control char => unread it and exit the search normally.
762 But only if `search-exit-option' is non-nil."
764 (if search-exit-option
766 (setq unread-command-char last-command-char
)
769 (isearch-search-and-update)))
772 (defun isearch-other-meta-char ()
773 "Any other meta char => exit the search normally and reexecute the whole key.
774 But only if `search-exit-option' is non-nil."
775 ;; This will probably work in place of isearch-other-control-char too,
776 ;; but here we use unwind-protect and command-execute since it is
777 ;; a multi-char key we would want to unread.
779 (if search-exit-option
781 (isearch-done) ;; this exits recursive edit
782 ;; Reexecute the key.
783 (command-execute (this-command-keys)))
785 (isearch-search-and-update)))
788 (defun isearch-quote-char ()
789 "Quote special characters for incremental search."
791 (isearch-process-search-char (read-quoted-char (isearch-message t
))))
794 (defun isearch-return-char ()
795 "Convert return into newline for incremental search.
798 (isearch-process-search-char ?
\n))
801 (defun isearch-printing-char ()
802 "Any other printing character => add it to the search string and search."
804 (isearch-process-search-char last-command-char
))
807 (defun isearch-upper-case-char ()
808 "Any upper case char => turn off case fold search for remainder of search."
809 ;; This feature only applies to interactively entered chars,
810 ;; but not yanked chars, repeat default searches, or search ring searches.
811 ;; Support for these should be easy to add.
813 (if search-caps-disable-folding
814 (setq isearch-case-fold-search nil
))
815 (isearch-printing-char))
817 (defun isearch-whitespace-chars ()
818 "Match all whitespace chars, if in regexp mode."
820 (if (and isearch-regexp search-whitespace-regexp
)
821 (isearch-process-search-string search-whitespace-regexp
" ")
822 (isearch-other-meta-char)))
824 (defun isearch-process-search-char (char)
825 ;; Append the char to the search string, update the message and re-search.
826 (isearch-process-search-string (char-to-string char
)
828 (text-char-description char
)))
830 (defun isearch-process-search-string (string message
)
831 (setq isearch-string
(concat isearch-string string
)
832 isearch-message
(concat isearch-message message
))
833 (isearch-search-and-update))
836 ;;===========================================================
839 (defun isearch-ring-adjust (advance)
840 ;; helper for isearch-ring-advance and isearch-ring-retreat
841 (if (cdr isearch-cmds
)
843 (let* ((ring (if isearch-regexp regex-search-ring search-ring
))
844 (length (length ring
))
845 (yank-pointer-name (if isearch-regexp
846 'regex-search-ring-yank-pointer
847 'search-ring-yank-pointer
))
848 (yank-pointer (eval yank-pointer-name
)))
851 (set yank-pointer-name
853 (nthcdr (%
(+ (- length
(length yank-pointer
))
854 (if advance
(1- length
) 1))
856 (setq isearch-string
(car yank-pointer
)
857 isearch-message
(mapconcat 'text-char-description
858 isearch-string
""))))
863 (defun isearch-ring-advance ()
864 "Advance to the next search string in the ring."
866 (isearch-ring-adjust 'advance
))
868 (defun isearch-ring-retreat ()
869 "Retreat to the previous search string in the ring."
871 (isearch-ring-adjust nil
))
874 ;;;=============================================================
875 ;; Window-local variables
876 ;; (not used yet - and maybe never)
878 (defvar window-local-variable-alist nil
879 "An alist of windows associated with window local variables and values.
880 The cdr of each item is another alist of variables and values.")
882 (defvar last-local-window nil
)
883 (defvar last-window-local-vars nil
)
885 (defun kill-window-local-variables ()
886 "Remove the old variable list, if any."
887 (setq window-local-variable-alist
888 (delq window-local-variable-alist
889 (assq (selected-window)
890 window-local-variable-alist
))))
892 ;; Assume that window-local variables are not buffer-local
893 ;; so we can delay storing until absolutely necessary.
895 (defun store-window-local-variables (&rest vars-and-vals
)
896 "Store the window local variables for selected window."
897 (setq last-local-window
(selected-window))
898 (setq last-window-local-vars vars-and-vals
))
901 (defun fetch-window-local-variables ()
902 "Fetch the window local variables for selected window.
903 Does nothing if the last store was for the same window."
904 (if (not (eq (selected-window) last-local-window
))
906 ;; First store the previous values.
907 (setq window-local-variable-alist
908 (cons (cons last-local-window
909 last-window-local-vars
)
910 (delq window-local-variable-alist
911 (assq last-local-window
912 window-local-variable-alist
))))
913 ;; Now fetch the values for the selected-window.
914 (setq last-local-window
(selected-window))
915 (setq last-window-local-vars
916 (cdr (assq last-local-window window-local-variable-alist
)))
917 (let ((vars-and-vals last-window-local-vars
))
919 (set (car vars-and-vals
) (car (cdr vars-and-vals
)))
920 (setq vars-and-vals
(cdr (cdr vars-and-vals
))))))))
924 ;;;==============================================================
925 ;; The search status stack (and isearch window-local variables, not used).
927 (defun isearch-top-state ()
928 ;; (fetch-window-local-variables)
929 (let ((cmd (car isearch-cmds
)))
930 (setq isearch-string
(car cmd
)
931 isearch-message
(car (cdr cmd
))
932 isearch-success
(nth 3 cmd
)
933 isearch-forward
(nth 4 cmd
)
934 isearch-other-end
(nth 5 cmd
)
935 isearch-invalid-regexp
(nth 6 cmd
)
936 isearch-wrapped
(nth 7 cmd
)
937 isearch-barrier
(nth 8 cmd
))
938 (goto-char (car (cdr (cdr cmd
))))))
940 (defun isearch-pop-state ()
941 ;; (fetch-window-local-variables)
942 (setq isearch-cmds
(cdr isearch-cmds
))
946 (defun isearch-push-state ()
948 (cons (list isearch-string isearch-message
(point)
949 isearch-success isearch-forward isearch-other-end
950 isearch-invalid-regexp isearch-wrapped isearch-barrier
)
953 (defun isearch-store-variables ()
954 (store-window-local-variables
955 'isearch-cmds isearch-cmds
956 'isearch-regexp isearch-regexp
957 'isearch-adjusted isearch-adjusted
958 'isearch-slow-terminal-mode isearch-slow-terminal-mode
959 'isearch-small-window isearch-small-window
960 'isearch-found-point isearch-found-point
961 'isearch-found-start isearch-found-start
962 'isearch-opoint isearch-opoint
963 'isearch-window-configuration isearch-window-configuration
964 'isearch-old-local-map isearch-old-local-map
968 ;;;==================================================================
971 (defun isearch-message (&optional c-q-hack ellipsis
)
972 ;; Generate and print the message string.
973 (let ((cursor-in-echo-area ellipsis
)
975 (isearch-message-prefix c-q-hack ellipsis
)
977 (isearch-message-suffix c-q-hack ellipsis
)
979 (if c-q-hack m
(message "%s" m
))))
981 (defun isearch-message-prefix (&optional c-q-hack ellipsis
)
982 ;; If about to search, and previous search regexp was invalid,
983 ;; check that it still is. If it is valid now,
984 ;; let the message we display while searching say that it is valid.
985 (and isearch-invalid-regexp ellipsis
987 (progn (re-search-forward isearch-string
(point) t
)
988 (setq isearch-invalid-regexp nil
))
990 ;; If currently failing, display no ellipsis.
991 (or isearch-success
(setq ellipsis nil
))
992 (let ((m (concat (if isearch-success
"" "failing ")
993 (if isearch-wrapped
"wrapped ")
994 (if isearch-regexp
"regexp " "")
996 (if isearch-forward
": " " backward: ")
998 (aset m
0 (upcase (aref m
0)))
1002 (defun isearch-message-suffix (&optional c-q-hack ellipsis
)
1003 (concat (if c-q-hack
"^Q" "")
1004 (if isearch-invalid-regexp
1005 (concat " [" isearch-invalid-regexp
"]")
1009 ;;;========================================================
1012 (defun isearch-search ()
1013 ;; Do the search with the current search string.
1014 (isearch-message nil t
)
1015 (condition-case lossage
1016 (let ((inhibit-quit nil
)
1017 (case-fold-search isearch-case-fold-search
))
1018 (if isearch-regexp
(setq isearch-invalid-regexp nil
))
1019 (setq isearch-success
1022 (if isearch-forward
're-search-forward
're-search-backward
)
1023 (if isearch-forward
'search-forward
'search-backward
))
1024 isearch-string nil t
))
1026 (setq isearch-other-end
1027 (if isearch-forward
(match-beginning 0) (match-end 0)))))
1029 (quit (setq unread-command-char ?\C-g
)
1030 (setq isearch-success nil
))
1033 (setq isearch-invalid-regexp
(car (cdr lossage
)))
1035 "\\`Premature \\|\\`Unmatched \\|\\`Invalid "
1036 isearch-invalid-regexp
)
1037 (setq isearch-invalid-regexp
"incomplete input"))))
1041 ;; Ding if failed this time after succeeding last time.
1042 (and (nth 3 (car isearch-cmds
))
1044 (goto-char (nth 2 (car isearch-cmds
)))))
1046 ;;;=================================================
1047 ;; This is called from incremental-search
1048 ;; if the first input character is the exit character.
1050 ;; We store the search string in `isearch-string'
1051 ;; which has been bound already by `isearch-search'
1052 ;; so that, when we exit, it is copied into `search-last-string'.
1054 (defun nonincremental-search (forward regexp
)
1055 ;; This may be broken. Anyway, it could be replaced by the
1056 ;; isearch-edit-string command instead.
1057 (setq isearch-forward forward
1058 isearch-regexp regexp
)
1061 (cursor-in-echo-area t
))
1062 ;; Prompt assuming not word search,
1063 (setq isearch-message
1067 (if isearch-forward
"Regexp search: "
1068 "Regexp search backward: ")
1069 (if isearch-forward
"Search: " "Search backward: ")))
1070 (message "%s" isearch-message
)
1071 ;; Read 1 char and switch to word search if it is ^W.
1072 (setq char
(read-char))
1073 (if (eq char search-yank-word-char
)
1074 (setq isearch-message
(if isearch-forward
"Word search: "
1076 "Word search backward: "))
1077 ;; Otherwise let that 1 char be part of the search string.
1078 (setq unread-command-char char
))
1080 (if (eq char search-yank-word-char
)
1081 (if isearch-forward
'word-search-forward
'word-search-backward
)
1083 (if isearch-forward
're-search-forward
're-search-backward
)
1084 (if isearch-forward
'search-forward
'search-backward
))))
1085 ;; Read the search string with corrected prompt.
1086 (setq isearch-string
(read-string isearch-message isearch-string
))
1087 ;; Empty means use default.
1088 (if (= 0 (length isearch-string
))
1089 (setq isearch-string search-last-string
)
1090 ;; Set last search string now so it is set even if we fail.
1091 (setq search-last-string isearch-string
))
1092 ;; Since we used the minibuffer, we should be available for redo.
1093 (setq command-history
1095 (cons (list function isearch-string
) command-history
))
1096 ;; Go ahead and search.
1097 (let ((case-fold-search isearch-case-fold-search
))
1098 (funcall function isearch-string
))))