isearch.el 60.8 KB
Newer Older
1
;;; isearch.el --- incremental search minor mode.
2

3
;; Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
Eric S. Raymond's avatar
Eric S. Raymond committed
4

5
;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
6
;; Maintainer: FSF
Jim Blandy's avatar
Jim Blandy committed
7

David J. MacKenzie's avatar
David J. MacKenzie committed
8
;; This file is part of GNU Emacs.
Jim Blandy's avatar
Jim Blandy committed
9

10 11 12 13 14
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

Jim Blandy's avatar
Jim Blandy committed
15
;; GNU Emacs is distributed in the hope that it will be useful,
16 17 18 19 20
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
Erik Naggum's avatar
Erik Naggum committed
21 22 23
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
Jim Blandy's avatar
Jim Blandy committed
24

25 26
;;; Commentary:

Jim Blandy's avatar
Jim Blandy committed
27 28
;; Instructions

29 30 31 32 33
;; For programmed use of isearch-mode, e.g. calling (isearch-forward),
;; isearch-mode behaves modally and does not return until the search
;; is completed.  It uses a recursive-edit to behave this way.  Note:
;; gnus does it wrong: (call-interactively 'isearch-forward).

Jim Blandy's avatar
Jim Blandy committed
34
;; The key bindings active within isearch-mode are defined below in
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
;; `isearch-mode-map' which is given bindings close to the default
;; characters of the original isearch.el.  With `isearch-mode',
;; however, you can bind multi-character keys and it should be easier
;; to add new commands.  One bug though: keys with meta-prefix cannot
;; be longer than two chars.  Also see minibuffer-local-isearch-map
;; for bindings active during `isearch-edit-string'.

;; Note to emacs version 19 users: isearch-mode should work even if
;; you switch windows with the mouse, in which case isearch-mode is
;; terminated automatically before the switch.  This is true of lemacs
;; too, with a few more cleanups I've neglected in this release. 
;; No one has supplied patches for epoch yet.

;; The search ring and completion commands automatically put you in
;; the minibuffer to edit the string.  This gives you a chance to
;; modify the search string before executing the search.  There are
;; three commands to terminate the editing: C-s and C-r exit the
;; minibuffer and search forward and reverse respectively, while C-m
;; exits and does a nonincremental search.

;; Exiting immediately from isearch uses isearch-edit-string instead
;; of nonincremental-search, if search-nonincremental-instead is non-nil.
;; The name of this option should probably be changed if we decide to
;; keep the behavior.  No point in forcing nonincremental search until
;; the last possible moment.

;; TODO
62
;; - Integrate the emacs 19 generalized command history.
63 64
;; - Think about incorporating query-replace.
;; - Hooks and options for failed search.
Eric S. Raymond's avatar
Eric S. Raymond committed
65

66 67
;;; Change Log:

Erik Naggum's avatar
Erik Naggum committed
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
;; Changes before those recorded in ChangeLog:

;; Revision 1.4  92/09/14  16:26:02  liberte
;; Added prefix args to isearch-forward, etc. to switch between
;;    string and regular expression searching.
;; Added some support for lemacs.
;; Added general isearch-highlight option - but only for lemacs so far.
;; Added support for frame switching in emacs 19.
;; Added word search option to isearch-edit-string.
;; Renamed isearch-quit to isearch-abort.
;; Numerous changes to comments and doc strings.
;; 
;; Revision 1.3  92/06/29  13:10:08  liberte
;; Moved modal isearch-mode handling into isearch-mode.
;; Got rid of buffer-local isearch variables.
;; isearch-edit-string used by ring adjustments, completion, and
;; nonincremental searching.  C-s and C-r are additional exit commands.
;; Renamed all regex to regexp.
;; Got rid of found-start and found-point globals.
;; Generalized handling of upper-case chars.

;; Revision 1.2  92/05/27  11:33:57  liberte
;; Emacs version 19 has a search ring, which is supported here.
;; Other fixes found in the version 19 isearch are included here.
;;
;; Also see variables search-caps-disable-folding,
;; search-nonincremental-instead, search-whitespace-regexp, and
;; commands isearch-toggle-regexp, isearch-edit-string.
;;
;; semi-modal isearching is supported.

;; Changes for 1.1
;; 3/18/92 Fixed invalid-regexp.
;; 3/18/92 Fixed yanking in regexps.
Eric S. Raymond's avatar
Eric S. Raymond committed
102

103
;;; Code:
104 105


106
;;; Some additional options and constants.
107

108 109 110 111 112
(defgroup isearch nil
  "Incremental search minor mode."
  :prefix "isearch-"
  :prefix "search-"
  :group 'matching)
113

114 115 116 117 118 119 120

(defcustom search-exit-option t
  "*Non-nil means random control characters terminate incremental search."
  :type 'boolean
  :group 'isearch)

(defcustom search-slow-window-lines 1
121 122 123
  "*Number of lines in slow search display windows.
These are the short windows used during incremental search on slow terminals.
Negative means put the slow search window at the top (normally it's at bottom)
124 125 126
and the value is minus the number of lines."
  :type 'integer
  :group 'isearch)
127

128
(defcustom search-slow-speed 1200
129 130
  "*Highest terminal speed at which to use \"slow\" style incremental search.
This is the style where a one-line window is created to show the line
131 132 133
that the search has reached."
  :type 'integer
  :group 'isearch)
Jim Blandy's avatar
Jim Blandy committed
134

135
(defcustom search-upper-case 'not-yanks
Jim Blandy's avatar
Jim Blandy committed
136
  "*If non-nil, upper case chars disable case fold searching.
137 138
That is, upper and lower case chars must match exactly.
This applies no matter where the chars come from, but does not
139
apply to chars in regexps that are prefixed with `\\'.
140 141 142 143 144
If this value is `not-yanks', yanked text is always downcased."
  :type '(choice (const :tag "off" nil)
		 (const not-yanks)
		 (sexp :tag "on" :format "%t\n" t))
  :group 'isearch)
Jim Blandy's avatar
Jim Blandy committed
145

146
(defcustom search-nonincremental-instead t
Jim Blandy's avatar
Jim Blandy committed
147
  "*If non-nil, do a nonincremental search instead if exiting immediately.
148
Actually, `isearch-edit-string' is called to let you enter the search
149 150 151
string, and RET terminates editing and does a nonincremental search."
  :type 'boolean
  :group 'isearch)
Jim Blandy's avatar
Jim Blandy committed
152

153
(defcustom search-whitespace-regexp "\\s-+"
Jim Blandy's avatar
Jim Blandy committed
154
  "*If non-nil, regular expression to match a sequence of whitespace chars.
155
This applies to regular expression incremental search.
156 157 158
You might want to use something like \"[ \\t\\r\\n]+\" instead."
  :type 'regexp
  :group 'isearch)
Jim Blandy's avatar
Jim Blandy committed
159

160
(defcustom search-highlight t
161 162 163
  "*Non-nil means incremental search highlights the current match."
  :type 'boolean
  :group 'isearch)
164

165 166 167 168 169 170 171 172 173
(defcustom search-invisible 'open
  "If t incremental search can match hidden text.
nil means don't match invisible text.
If the value is `open', if the text matched is made invisible by
an overlay having an `invisible' property and that overlay has a property
`isearch-open-invisible', then incremental search will show the contents.
\(This applies when using `outline.el' and `hideshow.el'.)"
  :type '(choice (const :tag "Match hidden text" t)
		 (const :tag "Open overlays" open)
174
		 (const :tag "Don't match hidden text" nil))
175 176 177
  :group 'isearch)

(defcustom isearch-hide-immediately t
178 179 180 181 182
  "If non-nil, re-hide an invisible match right away.
This variable makes a difference when `search-invisible' is set to `open'.
It means that after search makes some invisible text visible
to show the match, it makes the text invisible again when the match moves.
Ordinarily the text becomes invisible again at the end of the search."  
183 184
  :type 'boolean 
  :group 'isearch)
185

186 187 188 189 190 191
(defvar isearch-mode-hook nil
  "Function(s) to call after starting up an incremental search.")

(defvar isearch-mode-end-hook nil
  "Function(s) to call after terminating an incremental search.")

Jim Blandy's avatar
Jim Blandy committed
192 193 194 195
;;; Search ring.

(defvar search-ring nil
  "List of search string sequences.")
196
(defvar regexp-search-ring nil
Jim Blandy's avatar
Jim Blandy committed
197 198
  "List of regular expression search string sequences.")

199 200 201 202 203 204 205 206
(defcustom search-ring-max 16
  "*Maximum length of search ring before oldest elements are thrown away."
  :type 'integer
  :group 'isearch)
(defcustom regexp-search-ring-max 16
  "*Maximum length of regexp search ring before oldest elements are thrown away."
  :type 'integer
  :group 'isearch)
Jim Blandy's avatar
Jim Blandy committed
207 208

(defvar search-ring-yank-pointer nil
209 210
  "Index in `search-ring' of last string reused.
nil if none yet.")
211
(defvar regexp-search-ring-yank-pointer nil
212 213
  "Index in `regexp-search-ring' of last string reused.
nil if none yet.")
Jim Blandy's avatar
Jim Blandy committed
214

215
(defcustom search-ring-update nil
216
  "*Non-nil if advancing or retreating in the search ring should cause search.
217 218 219
Default value, nil, means edit the string instead."
  :type 'boolean
  :group 'isearch)
220

Jim Blandy's avatar
Jim Blandy committed
221 222 223 224 225
;;; Define isearch-mode keymap.

(defvar isearch-mode-map nil
  "Keymap for isearch-mode.")

226 227
(or isearch-mode-map
    (let* ((i 0)
228
	   (map (make-keymap)))
229
      (or (vectorp (nth 1 map))
230
	  (char-table-p (nth 1 map))
231
	  (error "The initialization of isearch-mode-map must be updated"))
232
      ;; Make Latin-1, Latin-2, Latin-3 and Latin-4 characters
233
      ;; search for themselves.
234 235 236 237
      (aset (nth 1 map) (make-char 'latin-iso8859-1) 'isearch-printing-char)
      (aset (nth 1 map) (make-char 'latin-iso8859-2) 'isearch-printing-char)
      (aset (nth 1 map) (make-char 'latin-iso8859-3) 'isearch-printing-char)
      (aset (nth 1 map) (make-char 'latin-iso8859-4) 'isearch-printing-char)
238
      (aset (nth 1 map) (make-char 'latin-iso8859-9) 'isearch-printing-char)
239 240
      ;; Make function keys, etc, exit the search.
      (define-key map [t] 'isearch-other-control-char)
241
      ;; Control chars, by default, end isearch mode transparently.
242 243 244
      ;; We need these explicit definitions because, in a dense keymap, 
      ;; the binding for t does not affect characters.
      ;; We use a dense keymap to save space.
245 246 247 248
      (while (< i ?\ )
	(define-key map (make-string 1 i) 'isearch-other-control-char)
	(setq i (1+ i)))

249
      ;; Single-byte printing chars extend the search string by default.
250
      (setq i ?\ )
251
      (while (< i 256)
252
	(define-key map (vector i) 'isearch-printing-char)
253 254
	(setq i (1+ i)))

255 256 257 258 259 260 261 262 263 264
      ;; To handle local bindings with meta char prefix keys, define
      ;; another full keymap.  This must be done for any other prefix
      ;; keys as well, one full keymap per char of the prefix key.  It
      ;; would be simpler to disable the global keymap, and/or have a
      ;; default local key binding for any key not otherwise bound.
      (let ((meta-map (make-sparse-keymap)))
	(define-key map (char-to-string meta-prefix-char) meta-map)
	(define-key map [escape] meta-map))
      (define-key map (vector meta-prefix-char t) 'isearch-other-meta-char)

265 266 267 268 269
      ;; Several non-printing chars change the searching behavior.
      (define-key map "\C-s" 'isearch-repeat-forward)
      (define-key map "\C-r" 'isearch-repeat-backward)
      (define-key map "\177" 'isearch-delete-char)
      (define-key map "\C-g" 'isearch-abort)
270 271 272
      ;; This assumes \e is the meta-prefix-char.
      (or (= ?\e meta-prefix-char)
	  (error "Inconsistency in isearch.el"))
273 274
      (define-key map "\e\e\e" 'isearch-cancel)
      (define-key map  [escape escape escape] 'isearch-cancel)
Jim Blandy's avatar
Jim Blandy committed
275
    
276 277 278 279 280 281
      (define-key map "\C-q" 'isearch-quote-char)

      (define-key map "\r" 'isearch-exit)
      (define-key map "\C-j" 'isearch-printing-char)
      (define-key map "\t" 'isearch-printing-char)
      (define-key map " " 'isearch-whitespace-chars)
282
      (define-key map [?\S-\ ] 'isearch-whitespace-chars)
Jim Blandy's avatar
Jim Blandy committed
283
    
284 285 286 287 288 289 290 291 292
      (define-key map "\C-w" 'isearch-yank-word)
      (define-key map "\C-y" 'isearch-yank-line)

      ;; Define keys for regexp chars * ? |.
      ;; Nothing special for + because it matches at least once.
      (define-key map "*" 'isearch-*-char)
      (define-key map "?" 'isearch-*-char)
      (define-key map "|" 'isearch-|-char)

293 294 295
;;; Turned off because I find I expect to get the global definition--rms.
;;;      ;; Instead bind C-h to special help command for isearch-mode.
;;;      (define-key map "\C-h" 'isearch-mode-help)
296 297 298

      (define-key map "\M-n" 'isearch-ring-advance)
      (define-key map "\M-p" 'isearch-ring-retreat)
299
      (define-key map "\M-y" 'isearch-yank-kill)
300

301 302
      (define-key map "\M-\t" 'isearch-complete)

303 304 305 306 307 308 309
      ;; Pass frame events transparently so they won't exit the search.
      ;; In particular, if we have more than one display open, then a
      ;; switch-frame might be generated by someone typing at another keyboard.
      (define-key map [switch-frame] nil)
      (define-key map [delete-frame] nil)
      (define-key map [iconify-frame] nil)
      (define-key map [make-frame-visible] nil)
Karl Heuer's avatar
Karl Heuer committed
310 311 312
      ;; For searching multilingual text.
      (define-key map "\C-\\" 'isearch-toggle-input-method)
      (define-key map "\C-^" 'isearch-toggle-specified-input-method)
313

314 315
      (setq isearch-mode-map map)
      ))
Jim Blandy's avatar
Jim Blandy committed
316

317 318
;; Some bindings you may want to put in your isearch-mode-hook.
;; Suggest some alternates...
319
;; (define-key isearch-mode-map "\C-t" 'isearch-toggle-case-fold)
320 321
;; (define-key isearch-mode-map "\C-t" 'isearch-toggle-regexp)
;; (define-key isearch-mode-map "\C-^" 'isearch-edit-string)
Jim Blandy's avatar
Jim Blandy committed
322 323


324 325
(defvar minibuffer-local-isearch-map nil
  "Keymap for editing isearch strings in the minibuffer.")
Jim Blandy's avatar
Jim Blandy committed
326

327 328 329
(or minibuffer-local-isearch-map
    (let ((map (copy-keymap minibuffer-local-map)))
      (define-key map "\r" 'isearch-nonincremental-exit-minibuffer)
Richard M. Stallman's avatar
Richard M. Stallman committed
330 331
      (define-key map "\M-n" 'isearch-ring-advance-edit)
      (define-key map "\M-p" 'isearch-ring-retreat-edit)
332 333 334 335 336
      (define-key map "\M-\t" 'isearch-complete-edit)
      (define-key map "\C-s" 'isearch-forward-exit-minibuffer)
      (define-key map "\C-r" 'isearch-reverse-exit-minibuffer)
      (setq minibuffer-local-isearch-map map)
      ))
Jim Blandy's avatar
Jim Blandy committed
337 338

;; Internal variables declared globally for byte-compiler.
339 340 341 342 343 344 345 346 347 348 349 350 351
;; These are all set with setq while isearching
;; and bound locally while editing the search string.

(defvar isearch-forward nil)	; Searching in the forward direction.
(defvar isearch-regexp nil)	; Searching for a regexp.
(defvar isearch-word nil)	; Searching for words.

(defvar isearch-cmds nil)   ; Stack of search status sets.
(defvar isearch-string "")  ; The current search string.
(defvar isearch-message "") ; text-char-description version of isearch-string

(defvar isearch-success t)		; Searching is currently successful.
(defvar isearch-invalid-regexp nil)	; Regexp not well formed.
352
(defvar isearch-within-brackets nil)	; Regexp has unclosed [.
353 354
(defvar isearch-other-end nil)	; Start (end) of match if forward (backward).
(defvar isearch-wrapped nil)	; Searching restarted from the top (bottom).
Jim Blandy's avatar
Jim Blandy committed
355
(defvar isearch-barrier 0)
356
(defvar isearch-just-started nil)
Jim Blandy's avatar
Jim Blandy committed
357

358 359 360 361
; case-fold-search while searching.
;   either nil, t, or 'yes.  'yes means the same as t except that mixed
;   case in the search string is ignored.
(defvar isearch-case-fold-search nil)
Jim Blandy's avatar
Jim Blandy committed
362 363 364

(defvar isearch-adjusted nil)
(defvar isearch-slow-terminal-mode nil)
365 366
;;; If t, using a small window.
(defvar isearch-small-window nil)
Jim Blandy's avatar
Jim Blandy committed
367
(defvar isearch-opoint 0)
368 369
;;; The window configuration active at the beginning of the search.
(defvar isearch-window-configuration nil)
Jim Blandy's avatar
Jim Blandy committed
370

371 372
;; Flag to indicate a yank occurred, so don't move the cursor.
(defvar isearch-yank-flag nil)
Jim Blandy's avatar
Jim Blandy committed
373

374 375 376 377
;;; A function to be called after each input character is processed.
;;; (It is not called after characters that exit the search.)
;;; It is only set from an optional argument to `isearch-mode'.
(defvar isearch-op-fun nil)
Jim Blandy's avatar
Jim Blandy committed
378

379 380
;;;  Is isearch-mode in a recursive edit for modal searching.
(defvar isearch-recursive-edit nil)
Jim Blandy's avatar
Jim Blandy committed
381

382 383 384 385 386
;;; Should isearch be terminated after doing one search?
(defvar isearch-nonincremental nil)

;; New value of isearch-forward after isearch-edit-string.
(defvar isearch-new-forward nil)
Jim Blandy's avatar
Jim Blandy committed
387

388 389
;; Accumulate here the overlays opened during searching.
(defvar isearch-opened-overlays nil)
Jim Blandy's avatar
Jim Blandy committed
390 391 392 393 394 395 396 397

;; Minor-mode-alist changes - kind of redundant with the
;; echo area, but if isearching in multiple windows, it can be useful.

(or (assq 'isearch-mode minor-mode-alist)
    (nconc minor-mode-alist
	   (list '(isearch-mode isearch-mode))))

398
(defvar isearch-mode nil) ;; Name of the minor mode, if non-nil.
Jim Blandy's avatar
Jim Blandy committed
399 400
(make-variable-buffer-local 'isearch-mode)

401 402 403 404 405
(define-key global-map "\C-s" 'isearch-forward)
(define-key esc-map "\C-s" 'isearch-forward-regexp)
(define-key global-map "\C-r" 'isearch-backward)
(define-key esc-map "\C-r" 'isearch-backward-regexp)

Jim Blandy's avatar
Jim Blandy committed
406
;;; Entry points to isearch-mode.
407
;;; These four functions should replace those in loaddefs.el
408
;;; An alternative is to defalias isearch-forward etc to isearch-mode,
409
;;; and look at this-command to set the options accordingly.
Jim Blandy's avatar
Jim Blandy committed
410

411
(defun isearch-forward (&optional regexp-p no-recursive-edit)
Jim Blandy's avatar
Jim Blandy committed
412 413
  "\
Do incremental search forward.
414 415
With a prefix argument, do an incremental regular expression search instead.
\\<isearch-mode-map>
Jim Blandy's avatar
Jim Blandy committed
416
As you type characters, they add to the search string and are found.
417
The following non-printing keys are bound in `isearch-mode-map'.  
Jim Blandy's avatar
Jim Blandy committed
418

419
Type \\[isearch-delete-char] to cancel characters from end of search string.
Jim Blandy's avatar
Jim Blandy committed
420
Type \\[isearch-exit] to exit, leaving point at location found.
421 422 423 424 425 426 427
Type LFD (C-j) to match end of line.
Type \\[isearch-repeat-forward] to search again forward,\
 \\[isearch-repeat-backward] to search again backward.
Type \\[isearch-yank-word] to yank word from buffer onto end of search\
 string and search for it.
Type \\[isearch-yank-line] to yank rest of line onto end of search string\
 and search for it.
428
Type \\[isearch-yank-kill] to yank the last string of killed text.
Jim Blandy's avatar
Jim Blandy committed
429
Type \\[isearch-quote-char] to quote control character to search for it.
430 431 432 433 434
\\[isearch-abort] while searching or when search has failed cancels input\
 back to what has
 been found successfully.
\\[isearch-abort] when search is successful aborts and moves point to\
 starting point.
Jim Blandy's avatar
Jim Blandy committed
435 436 437

Also supported is a search ring of the previous 16 search strings.
Type \\[isearch-ring-advance] to search for the next item in the search ring.
438 439 440
Type \\[isearch-ring-retreat] to search for the previous item in the search\
 ring.
Type \\[isearch-complete] to complete the search string using the search ring.
Jim Blandy's avatar
Jim Blandy committed
441

442 443
The above keys, bound in `isearch-mode-map', are often controlled by 
 options; do M-x apropos on search-.* to find them.
Jim Blandy's avatar
Jim Blandy committed
444
Other control and meta characters terminate the search
445
 and are then executed normally (depending on `search-exit-option').
446
Likewise for function keys and mouse button events.
Jim Blandy's avatar
Jim Blandy committed
447

448 449
If this function is called non-interactively, it does not return to
the calling function until the search is done."
Jim Blandy's avatar
Jim Blandy committed
450

451
  (interactive "P\np")
452
  (isearch-mode t (not (null regexp-p)) nil (not no-recursive-edit)))
Jim Blandy's avatar
Jim Blandy committed
453

454
(defun isearch-forward-regexp (&optional not-regexp no-recursive-edit)
Jim Blandy's avatar
Jim Blandy committed
455 456
  "\
Do incremental search forward for regular expression.
457
With a prefix argument, do a regular string search instead.
Jim Blandy's avatar
Jim Blandy committed
458 459
Like ordinary incremental search except that your input
is treated as a regexp.  See \\[isearch-forward] for more info."
460
  (interactive "P\np")
461
  (isearch-mode t (null not-regexp) nil (not no-recursive-edit)))
Jim Blandy's avatar
Jim Blandy committed
462

463
(defun isearch-backward (&optional regexp-p no-recursive-edit)
Jim Blandy's avatar
Jim Blandy committed
464 465
  "\
Do incremental search backward.
466
With a prefix argument, do a regular expression search instead.
Jim Blandy's avatar
Jim Blandy committed
467
See \\[isearch-forward] for more information."
468
  (interactive "P\np")
469
  (isearch-mode nil (not (null regexp-p)) nil (not no-recursive-edit)))
Jim Blandy's avatar
Jim Blandy committed
470

471
(defun isearch-backward-regexp (&optional not-regexp no-recursive-edit)
Jim Blandy's avatar
Jim Blandy committed
472 473
  "\
Do incremental search backward for regular expression.
474
With a prefix argument, do a regular string search instead.
Jim Blandy's avatar
Jim Blandy committed
475 476
Like ordinary incremental search except that your input
is treated as a regexp.  See \\[isearch-forward] for more info."
477
  (interactive "P\np")
478
  (isearch-mode nil (null not-regexp) nil (not no-recursive-edit)))
479 480 481 482 483 484


(defun isearch-mode-help ()
  (interactive)
  (describe-function 'isearch-forward)
  (isearch-update))
Jim Blandy's avatar
Jim Blandy committed
485 486 487 488 489


;; isearch-mode only sets up incremental search for the minor mode.
;; All the work is done by the isearch-mode commands.

490
;; Not used yet:
491
;;(defvar isearch-commands '(isearch-forward isearch-backward
492 493 494 495 496
;;			     isearch-forward-regexp isearch-backward-regexp)
;;  "List of commands for which isearch-mode does not recursive-edit.")
			     

(defun isearch-mode (forward &optional regexp op-fun recursive-edit word-p)
Richard M. Stallman's avatar
Richard M. Stallman committed
497 498 499
  "Start isearch minor mode.  Called by `isearch-forward', etc.

\\{isearch-mode-map}"
Jim Blandy's avatar
Jim Blandy committed
500 501 502 503

  ;; Initialize global vars.
  (setq isearch-forward forward
	isearch-regexp regexp
504
	isearch-word word-p
Jim Blandy's avatar
Jim Blandy committed
505 506 507 508 509 510 511 512 513 514 515
	isearch-op-fun op-fun
	isearch-case-fold-search case-fold-search
	isearch-string ""
	isearch-message ""
	isearch-cmds nil
	isearch-success t
	isearch-wrapped nil
	isearch-barrier (point)
	isearch-adjusted nil
	isearch-yank-flag nil
	isearch-invalid-regexp nil
516
	isearch-within-brackets nil
517
	isearch-slow-terminal-mode (and (<= baud-rate search-slow-speed)
Jim Blandy's avatar
Jim Blandy committed
518 519 520 521
					(> (window-height)
					   (* 4 search-slow-window-lines)))
	isearch-other-end nil
	isearch-small-window nil
522
	isearch-just-started t
Jim Blandy's avatar
Jim Blandy committed
523 524

	isearch-opoint (point)
525
	search-ring-yank-pointer nil
526
	isearch-opened-overlays nil
527
	regexp-search-ring-yank-pointer nil)
528
  (looking-at "")
529 530
  (setq isearch-window-configuration
	(if isearch-slow-terminal-mode (current-window-configuration) nil))
531

532 533 534 535 536 537 538 539
  ;; Maybe make minibuffer frame visible and/or raise it.
  (let ((frame (window-frame (minibuffer-window))))
    (if (not (memq (frame-live-p frame) '(nil t)))
	(progn
	  (make-frame-visible frame)
	  (if minibuffer-auto-raise
	      (raise-frame frame)))))

Jim Blandy's avatar
Jim Blandy committed
540
  (setq	isearch-mode " Isearch")  ;; forward? regexp?
541
  (force-mode-line-update)
Jim Blandy's avatar
Jim Blandy committed
542 543 544

  (isearch-push-state)

545
  (setq overriding-terminal-local-map isearch-mode-map)
Jim Blandy's avatar
Jim Blandy committed
546 547
  (isearch-update)
  (run-hooks 'isearch-mode-hook)
548

549
  (add-hook 'mouse-leave-buffer-hook 'isearch-done)
550

551 552 553
  ;; isearch-mode can be made modal (in the sense of not returning to 
  ;; the calling function until searching is completed) by entering 
  ;; a recursive-edit and exiting it when done isearching.
554 555 556
  (if recursive-edit
      (let ((isearch-recursive-edit t))
	(recursive-edit)))
557
  isearch-success)
Jim Blandy's avatar
Jim Blandy committed
558 559 560 561 562 563


;; Some high level utilities.  Others below.

(defun isearch-update ()
  ;; Called after each command to update the display.  
564
  (if (null unread-command-events)
Jim Blandy's avatar
Jim Blandy committed
565 566 567 568 569 570
      (progn
	(if (not (input-pending-p))
	    (isearch-message))
	(if (and isearch-slow-terminal-mode
		 (not (or isearch-small-window 
			  (pos-visible-in-window-p))))
571
	    (let ((found-point (point)))
Jim Blandy's avatar
Jim Blandy committed
572 573 574 575 576 577 578 579 580 581 582 583 584 585
	      (setq isearch-small-window t)
	      (move-to-window-line 0)
	      (let ((window-min-height 1))
		(split-window nil (if (< search-slow-window-lines 0)
				      (1+ (- search-slow-window-lines))
				    (- (window-height)
				       (1+ search-slow-window-lines)))))
	      (if (< search-slow-window-lines 0)
		  (progn (vertical-motion (- 1 search-slow-window-lines))
			 (set-window-start (next-window) (point))
			 (set-window-hscroll (next-window)
					     (window-hscroll))
			 (set-window-hscroll (selected-window) 0))
		(other-window 1))
586 587 588 589
	      (goto-char found-point)))
	(if isearch-other-end
	    (if (< isearch-other-end (point)) ; isearch-forward?
		(isearch-highlight isearch-other-end (point))
590 591
	      (isearch-highlight (point) isearch-other-end))
	  (isearch-dehighlight nil))
592
	))
Jim Blandy's avatar
Jim Blandy committed
593 594 595 596 597
  (setq ;; quit-flag nil  not for isearch-mode
   isearch-adjusted nil
   isearch-yank-flag nil)
  )

598
(defun isearch-done (&optional nopush edit)
599
  (remove-hook 'mouse-leave-buffer-hook 'isearch-done)
Jim Blandy's avatar
Jim Blandy committed
600
  ;; Called by all commands that terminate isearch-mode.
Richard M. Stallman's avatar
Richard M. Stallman committed
601
  ;; If NOPUSH is non-nil, we don't push the string on the search ring.
602
  (setq overriding-terminal-local-map nil)
603 604 605 606
  ;; (setq pre-command-hook isearch-old-pre-command-hook) ; for lemacs
  (isearch-dehighlight t)
  (let ((found-start (window-start (selected-window)))
	(found-point (point)))
607 608
    (if isearch-window-configuration
	(set-window-configuration isearch-window-configuration))
609

610 611 612
    (if isearch-small-window
	(goto-char found-point)
      ;; Exiting the save-window-excursion clobbers window-start; restore it.
613
      (set-window-start (selected-window) found-start t))
614

615 616 617
    ;; If there was movement, mark the starting position.
    ;; Maybe should test difference between and set mark iff > threshold.
    (if (/= (point) isearch-opoint)
618 619 620
	(or (and transient-mark-mode mark-active)
	    (progn
	      (push-mark isearch-opoint t)
621
	      (or executing-kbd-macro (> (minibuffer-depth) 0)
622
		  (message "Mark saved where search started"))))))
623 624

  (setq isearch-mode nil)
625
  (force-mode-line-update)
Jim Blandy's avatar
Jim Blandy committed
626

Richard M. Stallman's avatar
Richard M. Stallman committed
627
  (if (and (> (length isearch-string) 0) (not nopush))
Jim Blandy's avatar
Jim Blandy committed
628
      ;; Update the ring data.
629
      (isearch-update-ring isearch-string isearch-regexp))
Jim Blandy's avatar
Jim Blandy committed
630 631

  (run-hooks 'isearch-mode-end-hook)
632
  (and (not edit) isearch-recursive-edit (exit-recursive-edit)))
633

634 635 636 637 638
(defun isearch-update-ring (string &optional regexp)
  "Add STRING to the beginning of the search ring.
REGEXP says which ring to use."
  (if regexp 
      (if (or (null regexp-search-ring)
639
	      (not (string= string (car regexp-search-ring))))
640 641
	  (progn
	    (setq regexp-search-ring
642
		  (cons string regexp-search-ring))
643 644 645 646
	    (if (> (length regexp-search-ring) regexp-search-ring-max)
		(setcdr (nthcdr (1- search-ring-max) regexp-search-ring)
			nil))))
    (if (or (null search-ring)
647
	    (not (string= string (car search-ring))))
648
	(progn
649
	  (setq search-ring (cons string search-ring))
650 651 652
	  (if (> (length search-ring) search-ring-max)
	      (setcdr (nthcdr (1- search-ring-max) search-ring) nil))))))

653
;;; Switching buffers should first terminate isearch-mode.
654
;;; This is done quite differently for each variant of emacs.
655 656 657 658 659 660 661
;;; For lemacs, see Exiting in lemacs below

;; For Emacs 19, the frame switch event is handled.
(defun isearch-switch-frame-handler ()
  (interactive) ;; Is this necessary?
  ;; First terminate isearch-mode.
  (isearch-done)
662
  (isearch-clean-overlays) 
663
  (handle-switch-frame (car (cdr (isearch-last-command-char)))))
664

Jim Blandy's avatar
Jim Blandy committed
665 666 667 668 669 670 671

;; Commands active while inside of the isearch minor mode.

(defun isearch-exit ()
  "Exit search normally.
However, if this is the first command after starting incremental
search and `search-nonincremental-instead' is non-nil, do a
672
nonincremental search instead via `isearch-edit-string'."
Jim Blandy's avatar
Jim Blandy committed
673 674 675
  (interactive)
  (if (and search-nonincremental-instead 
	   (= 0 (length isearch-string)))
676 677
      (let ((isearch-nonincremental t))
	(isearch-edit-string)))
678 679
  (isearch-done)
  (isearch-clean-overlays))
Jim Blandy's avatar
Jim Blandy committed
680 681 682


(defun isearch-edit-string ()
683 684 685 686 687 688
  "Edit the search string in the minibuffer.
The following additional command keys are active while editing.
\\<minibuffer-local-isearch-map>
\\[exit-minibuffer] to resume incremental searching with the edited string.
\\[isearch-nonincremental-exit-minibuffer] to do one nonincremental search.
\\[isearch-forward-exit-minibuffer] to resume isearching forward.
Karl Heuer's avatar
Karl Heuer committed
689
\\[isearch-reverse-exit-minibuffer] to resume isearching backward.
690
\\[isearch-ring-advance-edit] to replace the search string with the next item in the search ring.
691
\\[isearch-ring-retreat-edit] to replace the search string with the previous item in the search ring.
692
\\[isearch-complete-edit] to complete the search string using the search ring.
Karl Heuer's avatar
Karl Heuer committed
693
\\<isearch-mode-map>
694 695 696 697 698 699
If first char entered is \\[isearch-yank-word], then do word search instead."

  ;; This code is very hairy for several reasons, explained in the code.
  ;; Mainly, isearch-mode must be terminated while editing and then restarted.
  ;; If there were a way to catch any change of buffer from the minibuffer,
  ;; this could be simplified greatly.
700
  ;; Editing doesn't back up the search point.  Should it?
Jim Blandy's avatar
Jim Blandy committed
701
  (interactive)
702
  (condition-case err
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
      (progn
	(let ((isearch-nonincremental isearch-nonincremental)

	      ;; Locally bind all isearch global variables to protect them
	      ;; from recursive isearching.
	      ;; isearch-string -message and -forward are not bound
	      ;; so they may be changed.  Instead, save the values.
	      (isearch-new-string isearch-string)
	      (isearch-new-message isearch-message)
	      (isearch-new-forward isearch-forward)
	      (isearch-new-word isearch-word)

	      (isearch-regexp isearch-regexp)
	      (isearch-op-fun isearch-op-fun)
	      (isearch-cmds isearch-cmds)
	      (isearch-success isearch-success)
	      (isearch-wrapped isearch-wrapped)
	      (isearch-barrier isearch-barrier)
	      (isearch-adjusted isearch-adjusted)
	      (isearch-yank-flag isearch-yank-flag)
	      (isearch-invalid-regexp isearch-invalid-regexp)
	      (isearch-within-brackets isearch-within-brackets)
  ;;; Don't bind this.  We want isearch-search, below, to set it.
  ;;; And the old value won't matter after that.
  ;;;	    (isearch-other-end isearch-other-end)
  ;;; Perhaps some of these other variables should be bound for a
  ;;; shorter period, ending before the next isearch-search.
  ;;; But there doesn't seem to be a real bug, so let's not risk it now.
	      (isearch-opoint isearch-opoint)
	      (isearch-slow-terminal-mode isearch-slow-terminal-mode)
	      (isearch-small-window isearch-small-window)
	      (isearch-recursive-edit isearch-recursive-edit)
	      ;; Save current configuration so we can restore it here.
	      (isearch-window-configuration (current-window-configuration))
	      )

	  ;; Actually terminate isearching until editing is done.
	  ;; This is so that the user can do anything without failure, 
	  ;; like switch buffers and start another isearch, and return.
	  (condition-case err
	      (isearch-done t t)
	    (exit nil))			; was recursive editing

	  (isearch-message) ;; for read-char
	  (unwind-protect
	      (let* (;; Why does following read-char echo?  
		     ;;(echo-keystrokes 0) ;; not needed with above message
		     (e (let ((cursor-in-echo-area t))
			  (read-event)))
		     ;; Binding minibuffer-history-symbol to nil is a work-around
		     ;; for some incompatibility with gmhist.
		     (minibuffer-history-symbol)
		     (message-log-max nil))
		;; If the first character the user types when we prompt them
		;; for a string is the yank-word character, then go into
		;; word-search mode.  Otherwise unread that character and
		;; read a key the normal way.
		;; Word search does not apply (yet) to regexp searches,
		;; no check is made here.
		(message (isearch-message-prefix nil nil t))
		(if (eq 'isearch-yank-word
			(lookup-key isearch-mode-map (vector e)))
		    (setq isearch-word t;; so message-prefix is right
			  isearch-new-word t)
		  (cancel-kbd-macro-events)
		  (isearch-unread e))
		(setq cursor-in-echo-area nil)
		(setq isearch-new-string
		      (let (junk-ring)
			(read-from-minibuffer
			 (isearch-message-prefix nil nil isearch-nonincremental)
			 isearch-string
			 minibuffer-local-isearch-map nil
			 'junk-ring))
		      isearch-new-message
		      (mapconcat 'isearch-text-char-description
				 isearch-new-string "")))
	    ;; Always resume isearching by restarting it.
	    (isearch-mode isearch-forward 
			  isearch-regexp 
			  isearch-op-fun 
			  nil
			  isearch-word)

	    ;; Copy new local values to isearch globals
	    (setq isearch-string isearch-new-string
		  isearch-message isearch-new-message
		  isearch-forward isearch-new-forward
		  isearch-word isearch-new-word))

	  ;; Empty isearch-string means use default.
	  (if (= 0 (length isearch-string))
	      (setq isearch-string (or (car (if isearch-regexp
						regexp-search-ring
					      search-ring))
				       ""))
	    ;; This used to set the last search string,
	    ;; but I think it is not right to do that here.
	    ;; Only the string actually used should be saved.
	    ))

	;; Push the state as of before this C-s.
	(isearch-push-state)
806 807 808 809 810 811 812 813

	;; Reinvoke the pending search.
	(isearch-search)
	(isearch-update)
	(if isearch-nonincremental 
	    (progn
	      ;; (sit-for 1) ;; needed if isearch-done does: (message "")
	      (isearch-done))))
Jim Blandy's avatar
Jim Blandy committed
814

815 816 817 818 819 820 821 822 823 824 825 826 827
    (quit  ; handle abort-recursive-edit
     (isearch-abort)  ;; outside of let to restore outside global values
     )))

(defun isearch-nonincremental-exit-minibuffer ()
  (interactive)
  (setq isearch-nonincremental t)
  (exit-minibuffer))

(defun isearch-forward-exit-minibuffer ()
  (interactive)
  (setq isearch-new-forward t)
  (exit-minibuffer))
Jim Blandy's avatar
Jim Blandy committed
828

829
(defun isearch-reverse-exit-minibuffer ()
Jim Blandy's avatar
Jim Blandy committed
830
  (interactive)
831 832 833
  (setq isearch-new-forward nil)
  (exit-minibuffer))

834 835 836 837 838
(defun isearch-cancel ()
  "Terminate the search and go back to the starting point."
  (interactive)
  (goto-char isearch-opoint)
  (isearch-done t)
839
  (isearch-clean-overlays)
840
  (signal 'quit nil))  ; and pass on quit signal
841 842

(defun isearch-abort ()
843
  "Abort incremental search mode if searching is successful, signaling quit.
844
Otherwise, revert to previous successful search and continue searching.
845
Use `isearch-exit' to quit without signaling."
846
  (interactive)
847
;;  (ding)  signal instead below, if quitting
Jim Blandy's avatar
Jim Blandy committed
848 849 850 851 852
  (discard-input)
  (if isearch-success
      ;; If search is successful, move back to starting point
      ;; and really do quit.
      (progn (goto-char isearch-opoint)
853
	     (setq isearch-success nil)
Richard M. Stallman's avatar
Richard M. Stallman committed
854
	     (isearch-done t)   ; exit isearch
855
	     (isearch-clean-overlays)
856
	     (signal 'quit nil))  ; and pass on quit signal
857 858 859 860
    ;; If search is failing, or has an incomplete regexp,
    ;; rub out until it is once more successful.
    (while (or (not isearch-success) isearch-invalid-regexp)
      (isearch-pop-state))
Jim Blandy's avatar
Jim Blandy committed
861 862 863 864 865 866 867 868 869 870
    (isearch-update)))

(defun isearch-repeat (direction)
  ;; Utility for isearch-repeat-forward and -backward.
  (if (eq isearch-forward (eq direction 'forward))
      ;; C-s in forward or C-r in reverse.
      (if (equal isearch-string "")
	  ;; If search string is empty, use last one.
	  (setq isearch-string
		(or (if isearch-regexp
871 872
			(car regexp-search-ring)
		      (car search-ring))
Jim Blandy's avatar
Jim Blandy committed
873 874
		    "")
		isearch-message
875
		(mapconcat 'isearch-text-char-description
Jim Blandy's avatar
Jim Blandy committed
876 877 878 879 880 881 882 883 884 885
			   isearch-string ""))
	;; If already have what to search for, repeat it.
	(or isearch-success
	    (progn 
	      (goto-char (if isearch-forward (point-min) (point-max)))
	      (setq isearch-wrapped t))))
    ;; C-s in reverse or C-r in forward, change direction.
    (setq isearch-forward (not isearch-forward)))

  (setq isearch-barrier (point)) ; For subsequent \| if regexp.
886 887 888

  (if (equal isearch-string "")
      (setq isearch-success t)
889 890
    (if (and isearch-success (equal (match-end 0) (match-beginning 0))
	     (not isearch-just-started))
Jim Blandy's avatar
Jim Blandy committed
891 892
	;; If repeating a search that found
	;; an empty string, ensure we advance.
893 894 895 896 897 898 899 900 901
	(if (if isearch-forward (eobp) (bobp))
	    ;; If there's nowhere to advance to, fail (and wrap next time).
	    (progn
	      (setq isearch-success nil)
	      (ding))
	  (forward-char (if isearch-forward 1 -1))
	  (isearch-search))
      (isearch-search)))

Jim Blandy's avatar
Jim Blandy committed
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919
  (isearch-push-state)
  (isearch-update))

(defun isearch-repeat-forward ()
  "Repeat incremental search forwards."
  (interactive)
  (isearch-repeat 'forward))

(defun isearch-repeat-backward ()
  "Repeat incremental search backwards."
  (interactive)
  (isearch-repeat 'backward))

(defun isearch-toggle-regexp ()
  "Toggle regexp searching on or off."
  ;; The status stack is left unchanged.
  (interactive)
  (setq isearch-regexp (not isearch-regexp))
920
  (if isearch-regexp (setq isearch-word nil))
Jim Blandy's avatar
Jim Blandy committed
921 922
  (isearch-update))

923 924 925 926 927
(defun isearch-toggle-case-fold ()
  "Toggle case folding in searching on or off."
  (interactive)
  (setq isearch-case-fold-search
	(if isearch-case-fold-search nil 'yes))
928 929 930 931 932
  (let ((message-log-max nil))
    (message "%s%s [case %ssensitive]"
	     (isearch-message-prefix nil nil isearch-nonincremental)
	     isearch-message
	     (if isearch-case-fold-search "in" "")))
933 934 935 936
  (setq isearch-adjusted t)
  (sit-for 1)
  (isearch-update))

Jim Blandy's avatar
Jim Blandy committed
937 938 939 940 941 942 943 944 945 946
(defun isearch-delete-char ()
  "Discard last input item and move point back.  
If no previous match was done, just beep."
  (interactive)
  (if (null (cdr isearch-cmds))
      (ding)
    (isearch-pop-state))
  (isearch-update))


947 948 949 950 951 952 953 954 955 956 957 958 959 960
(defun isearch-yank-string (string)
  "Pull STRING into search string."
  ;; Downcase the string if not supposed to case-fold yanked strings.
  (if (and isearch-case-fold-search
	   (eq 'not-yanks search-upper-case))
      (setq string (downcase string)))
  (if isearch-regexp (setq string (regexp-quote string)))
  (setq isearch-string (concat isearch-string string)
	isearch-message
	(concat isearch-message
		(mapconcat 'isearch-text-char-description
			   string ""))
	;; Don't move cursor in reverse search.
	isearch-yank-flag t)
Jim Blandy's avatar
Jim Blandy committed
961 962
  (isearch-search-and-update))

963 964 965
(defun isearch-yank-kill ()
  "Pull string from kill ring into search string."
  (interactive)
966 967 968
  (isearch-yank-string (current-kill 0)))

(defun isearch-yank-x-selection ()
969 970 971 972 973
  "Pull current X selection into search string.
Some users like to put this command on Mouse-2.
To do that, evaluate these expressions:
    (define-key isearch-mode-map [down-mouse-2] nil)
    (define-key isearch-mode-map [mouse-2] 'isearch-yank-x-selection)"
974 975
  (interactive)
  (isearch-yank-string (x-get-selection)))
Jim Blandy's avatar
Jim Blandy committed
976 977 978 979

(defun isearch-yank-word ()
  "Pull next word from buffer into search string."
  (interactive)
980 981 982 983 984
  (isearch-yank-string
   (save-excursion
     (and (not isearch-forward) isearch-other-end
	  (goto-char isearch-other-end))
     (buffer-substring (point) (progn (forward-word 1) (point))))))
Jim Blandy's avatar
Jim Blandy committed
985 986 987 988

(defun isearch-yank-line ()
  "Pull rest of line from buffer into search string."
  (interactive)
989 990 991 992 993
  (isearch-yank-string
   (save-excursion
     (and (not isearch-forward) isearch-other-end
	  (goto-char isearch-other-end))
     (buffer-substring (point) (line-end-position)))))
Jim Blandy's avatar
Jim Blandy committed
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010


(defun isearch-search-and-update ()
  ;; Do the search and update the display.
  (if (and (not isearch-success)
	   ;; unsuccessful regexp search may become
	   ;;  successful by addition of characters which
	   ;;  make isearch-string valid
	   (not isearch-regexp))
      nil
    ;; In reverse search, adding stuff at
    ;; the end may cause zero or many more chars to be
    ;; matched, in the string following point.
    ;; Allow all those possibilities without moving point as
    ;; long as the match does not extend past search origin.
    (if (and (not isearch-forward) (not isearch-adjusted)
	     (condition-case ()
1011 1012 1013
		 (let ((case-fold-search isearch-case-fold-search))
		   (looking-at (if isearch-regexp isearch-string
				 (regexp-quote isearch-string))))
Jim Blandy's avatar
Jim Blandy committed
1014
	       (error nil))
1015 1016 1017
	     (or isearch-yank-flag
		 (<= (match-end 0) 
		     (min isearch-opoint isearch-barrier))))
1018 1019 1020 1021 1022 1023 1024 1025
	(progn
	  (setq isearch-success t 
		isearch-invalid-regexp nil
		isearch-within-brackets nil
		isearch-other-end (match-end 0))
	  (if (and (eq isearch-case-fold-search t) search-upper-case)
	      (setq isearch-case-fold-search
		    (isearch-no-upper-case-p isearch-string isearch-regexp))))
Jim Blandy's avatar
Jim Blandy committed
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
      ;; Not regexp, not reverse, or no match at point.
      (if (and isearch-other-end (not isearch-adjusted))
	  (goto-char (if isearch-forward isearch-other-end
		       (min isearch-opoint 
			    isearch-barrier 
			    (1+ isearch-other-end)))))
      (isearch-search)
      ))
  (isearch-push-state)
  (if isearch-op-fun (funcall isearch-op-fun))
  (isearch-update))


;; *, ?, and | chars can make a regexp more liberal.
1040
;; They can make a regexp match sooner or make it succeed instead of failing.
Jim Blandy's avatar
Jim Blandy committed
1041 1042
;; So go back to place last successful search started
;; or to the last ^S/^R (barrier), whichever is nearer.
1043
;; + needs no special handling because the string must match at least once.
Jim Blandy's avatar
Jim Blandy committed
1044 1045 1046 1047 1048

(defun isearch-*-char ()
  "Handle * and ? specially in regexps."
  (interactive)
  (if isearch-regexp 
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
      (let ((idx (length isearch-string)))
	(while (and (> idx 0)
		    (eq (aref isearch-string (1- idx)) ?\\))
	  (setq idx (1- idx)))
	(when (= (mod (- (length isearch-string) idx) 2) 0)
	  (setq isearch-adjusted t)
	  ;; Get the isearch-other-end from before the last search.
	  ;; We want to start from there,
	  ;; so that we don't retreat farther than that.
	  ;; (car isearch-cmds) is after last search;
	  ;; (car (cdr isearch-cmds)) is from before it.
	  (let ((cs (nth 5 (car (cdr isearch-cmds)))))
	    (setq cs (or cs isearch-barrier))
	    (goto-char
	     (if isearch-forward
		 (max cs isearch-barrier)
	       (min cs isearch-barrier)))))))
1066
  (isearch-process-search-char (isearch-last-command-char)))
Jim Blandy's avatar
Jim Blandy committed
1067 1068 1069 1070 1071 1072 1073 1074 1075
  

(defun isearch-|-char ()
  "If in regexp search, jump to the barrier."
  (interactive)
  (if isearch-regexp
      (progn
	(setq isearch-adjusted t)
	(goto-char isearch-barrier)))
1076
  (isearch-process-search-char (isearch-last-command-char)))
Jim Blandy's avatar
Jim Blandy committed
1077 1078


1079
(defalias 'isearch-other-control-char 'isearch-other-meta-char)
Jim Blandy's avatar
Jim Blandy committed
1080 1081

(defun isearch-other-meta-char ()
1082
  "Exit the search normally and reread this key sequence.
Richard M. Stallman's avatar
Richard M. Stallman committed
1083 1084 1085
But only if `search-exit-option' is non-nil, the default.
If it is the symbol `edit', the search string is edited in the minibuffer
and the meta character is unread so that it applies to editing the string."