-;; isearch-mode.el --- incremental search minor mode.
+;;; isearch.el --- incremental search minor mode.
+
+;; Copyright (C) 1992, 1993 Free Software Foundation, Inc.
;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
-;; Version: 1.2
-;; Last-Modified: 27 May 1992
-;; Copyright (C) 1992 Free Software Foundation, Inc.
+;; |$Date: 1993/07/08 22:33:57 $|$Revision: 1.45 $
-;; This file is part of GNU Emacs.
+;; This file is not yet part of GNU Emacs, but it is based almost
+;; entirely on isearch.el which is part of GNU Emacs.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY. No author or distributor
;; isearch-forward, etc, will then use isearch-mode instead of
;; isearch.
-;; (fset 'isearch 'isearch-mode)
+;; (defalias 'isearch 'isearch-mode)
;; (autoload 'isearch-mode "isearch-mode")
+;; 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).
+
+;; If any package you use invokes isearching non-interactively to get
+;; the modal behavior described above, you must use the redefinitions
+;; of isearch-forward, etc. found in this file instead of those in
+;; loaddefs.el. The simplest way to ensure this is to just load
+;; isearch-mode explicitly in your .emacs instead of using the above
+;; defalias and autoload.
+
+;; (load "isearch-mode")
+
;; The key bindings active within isearch-mode are defined below in
-;; `isearch-mode-map' and `isearch-mode-meta-map' which are given
-;; bindings close to the default characters of isearch.el for
-;; version 19. With `isearch-mode', however, you can bind
-;; multi-character keys and it should be easier to add new commands.
-
-;; Note to epoch and emacs version 19 users: isearch-mode should
-;; work even if you switch windows with the mouse. However, if
-;; you isearch in a buffer that is also displayed in another window,
-;; when you switch to that other window you will still be in
-;; isearch mode but not necessarily in the right state for it to work.
-;; So ... don't do it unless you are in an experimental mood.
-;; You can also experiment with the window-local-variable routines
-;; contained in this package but not yet used.
-;; Also, I am not sure what happens when you return to an isearching
-;; buffer; ideally, the echo area should redisplay the searching status.
-;; A select-window-hook might be useful.
+;; `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
+;; - Integrate the emacs 19 generalized command history.
+;; - Think about incorporating query-replace.
+;; - Hooks and options for failed search.
;;; Change Log:
-;;;====================================================================
-
-;;; $Header: /import/kaplan/kaplan/liberte/Isearch/RCS/isearch-mode.el,v 1.2 92/05/27 11:33:57 liberte Exp Locker: liberte $
-;;; $Log: isearch-mode.el,v $
-;;; Revision 1.2 92/05/27 11:33:57 liberte
-;;; Several new commands and features have been added. 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 searching is supported, using a recursive edit. If
-;;; isearching is started non-interactively by calling one of the
-;;; isearch commands (e.g. isearch-forward), it does not return
-;;; until the search is completed. You should still be able switch
-;;; buffers, so be careful not to get things confused.
+;;; 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.
;;; Code:
+\f
;;;=========================================================================
-;;; The following, defined in loaddefs.el, are still used with isearch-mode.
+;;; Emacs features
-;(defvar search-last-string ""
-; "Last string search for by a search command.
-;This does not include direct calls to the primitive search functions,
-;and does not include searches that are aborted.")
+;; isearch-mode takes advantage of the features provided by several
+;; different versions of emacs. Rather than testing the version of
+;; emacs, several constants are defined, one for each of the features.
+;; Each of the tests below must work on any version of emacs.
+;; (Perhaps provide and featurep could be used for this purpose.)
-;(defvar search-last-regexp ""
-; "Last string searched for by a regexp search command.
-;This does not include direct calls to the primitive search functions,
-;and does not include searches that are aborted.")
+(defconst isearch-gnu-emacs-events (fboundp 'set-frame-height)) ;; emacs 19
+(defconst isearch-pre-command-hook-exists (boundp 'pre-command-hook)) ;; lemacs
+(defconst isearch-event-data-type nil) ;; lemacs
-;(defconst search-exit-option t
-; "Non-nil means random control characters terminate incremental search.")
+(defconst search-exit-option t
+ "*Non-nil means random control characters terminate incremental search.")
-;(defvar search-slow-window-lines 1
-; "*Number of lines in slow search display windows.")
+(defvar search-slow-window-lines 1
+ "*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)
+and the value is minus the number of lines.")
-;(defconst search-slow-speed 1200
-; "*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
-;that the search has reached.")
+(defvar search-slow-speed 1200
+ "*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
+that the search has reached.")
;;;========================================================================
;;; Some additional options and constants.
-(defvar search-caps-disable-folding t
+(defvar search-upper-case 'not-yanks
"*If non-nil, upper case chars disable case fold searching.
-This does not yet apply to yanked strings, however.")
+That is, upper and lower case chars must match exactly.
+This applies no matter where the chars come from, but does not
+apply to chars in regexps that are prefixed with `\\'.
+If this value is `not-yanks', yanked text is always downcased.")
(defvar search-nonincremental-instead t
"*If non-nil, do a nonincremental search instead if exiting immediately.
-The default value of t reflects the default behavior of old
-isearch.")
+Actually, `isearch-edit-string' is called to let you enter the search
+string, and RET terminates editing and does a nonincremental search.")
(defconst search-whitespace-regexp "\\s-+"
"*If non-nil, regular expression to match a sequence of whitespace chars.
You might want to use something like \"[ \\t\\r\\n]+\" instead.")
+;; I removed the * from the doc string because highlighting is not
+;; currently a clean thing to do. Once highlighting is made clean,
+;; this feature can be re-enabled and advertised.
+(defvar search-highlight nil
+ "*Non-nil means incremental search highlights the current match.")
+
+(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.")
+
;;;==================================================================
;;; Search ring.
-;;; "regex" == "regexp". One should become the standard term.
(defvar search-ring nil
"List of search string sequences.")
-(defvar regex-search-ring nil ;; Is `regex' the new spelling?
+(defvar regexp-search-ring nil
"List of regular expression search string sequences.")
(defconst search-ring-max 16
"*Maximum length of search ring before oldest elements are thrown away.")
-(defconst regex-search-ring-max 16
- "*Maximum length of regex search ring before oldest elements are thrown away.")
+(defconst regexp-search-ring-max 16
+ "*Maximum length of regexp search ring before oldest elements are thrown away.")
(defvar search-ring-yank-pointer nil
- "The tail of the search ring whose car is the last thing searched for.")
-(defvar regex-search-ring-yank-pointer nil
- "The tail of the regular expression search ring whose car is the last
-thing searched for.")
+ "Index in `search-ring' of last string reused.
+nil if none yet.")
+(defvar regexp-search-ring-yank-pointer nil
+ "Index in `regexp-search-ring' of last string reused.
+nil if none yet.")
+
+(defvar search-ring-update nil
+ "*Non-nil if advancing or retreating in the search ring should cause search.
+Default value, nil, means edit the string instead.")
;;;====================================================
;;; Define isearch-mode keymap.
(defvar isearch-mode-map nil
"Keymap for isearch-mode.")
-(defvar isearch-mode-meta-map nil
- "Keymap for isearch-mode for keys with meta char prefix.")
-
-
-;; To handle meta char prefix keys, define another full keymap.
-;; The same must be done for any other prefix keys.
-;; It would be simpler to disable to global keymap, and/or
-;; have a default local key binding for any key not otherwise bound.
-(if isearch-mode-meta-map
- nil
- (setq isearch-mode-meta-map
- (list 'keymap (make-vector 128 'isearch-other-meta-char)))
- (define-key isearch-mode-meta-map "n" 'isearch-ring-advance)
- (define-key isearch-mode-meta-map "p" 'isearch-ring-retreat)
- (define-key isearch-mode-meta-map " " 'isearch-whitespace-chars)
-;for regexps
-
-;; (define-key isearch-mode-meta-map "?" nil) ; my help key is M-?
- )
-
-(if isearch-mode-map
- nil
- (let ((i 0)
-
- ;; Printing chars extend the selection by default.
- (array (make-vector 128 'isearch-printing-char)))
-
- ;; Non-printing chars by default suspend isearch mode transparently
- (while (< i ?\ )
- (aset array i 'isearch-other-control-char)
- (setq i (1+ i)))
-
- (setq i ?A)
- (while (<= i ?Z)
- (aset array i 'isearch-upper-case-char)
- (setq i (1+ i)))
-
- (setq isearch-mode-map (list 'keymap array))
-
- ;; You can reenable global keys by unbinding them locally.
-
- ;; For the help char this doesnt work quite as expected because
- ;; isearch-mode is not a major mode, and the echo area is not
- ;; restored after the help command.
- ;; Also, we should not assume that the help-command is on C-h.
- ;; If it is not, and the prefix is not the meta-char, we would
- ;; have to create another map for its prefix.
-; (define-key isearch-mode-map "\C-h" nil)
-
- ;; Several non-printing chars change the searching behavior.
- (define-key isearch-mode-map "\C-s" 'isearch-repeat-forward)
- (define-key isearch-mode-map "\C-r" 'isearch-repeat-backward)
- (define-key isearch-mode-map "\177" 'isearch-delete-char)
- (define-key isearch-mode-map "\C-g" 'isearch-quit)
+(or isearch-mode-map
+ (let* ((i 0)
+ (map (make-keymap)))
+ (or (vectorp (nth 1 map))
+ (error "The initialization of isearch-mode-map must be updated"))
+ ;; Give this map a vector 256 long, for dense binding
+ ;; of a larger range of ordinary characters.
+ (setcar (cdr map) (make-vector 256 nil))
+
+ ;; Make function keys, etc, exit the search.
+ (define-key map [t] 'isearch-other-control-char)
+ ;; Control chars, by default, end isearch mode transparently.
+ ;; 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.
+ (while (< i ?\ )
+ (define-key map (make-string 1 i) 'isearch-other-control-char)
+ (setq i (1+ i)))
+
+ ;; Printing chars extend the search string by default.
+ (setq i ?\ )
+ (while (< i (length (nth 1 map)))
+ (define-key map (vector i) 'isearch-printing-char)
+ (setq i (1+ i)))
+
+ ;; 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)
+ (define-key map "\C-q" 'isearch-quote-char)
- (define-key isearch-mode-map "\C-q" 'isearch-quote-char)
-
- ;; (define-key isearch-mode-map "\r" 'isearch-return-char)
- ;; For version 19, CR (C-m) terminates search and LFD (C-j) matches eol.
- (define-key isearch-mode-map "\r" 'isearch-exit)
- (define-key isearch-mode-map "\C-j" 'isearch-printing-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)
+ (define-key map "\C-w" 'isearch-yank-word)
+ (define-key map "\C-y" 'isearch-yank-line)
+
+ ;; Bind the ASCII-equivalent "function keys" explicitly
+ ;; if we bind their equivalents,
+ ;; since otherwise the default binding would override.
+ ;; We bind [escape] below.
+ (define-key map [tab] 'isearch-printing-char)
+ (define-key map [delete] 'isearch-delete-char)
+ (define-key map [backspace] 'isearch-delete-char)
+ (define-key map [return] 'isearch-exit)
+ (define-key map [newline] 'isearch-printing-char)
+
+ ;; 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)
+
+;;; 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)
+
+ ;; 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)
+
+ (define-key map "\M-n" 'isearch-ring-advance)
+ (define-key map "\M-p" 'isearch-ring-retreat)
+
+ (define-key map "\M-\t" 'isearch-complete)
+
+ ;; For emacs 19, switching frames should terminate isearch-mode
+ (if isearch-gnu-emacs-events
+ (define-key map [switch-frame] 'isearch-switch-frame-handler))
+
+ (setq isearch-mode-map map)
+ ))
- (define-key isearch-mode-map "\C-w" 'isearch-yank-word)
- (define-key isearch-mode-map "\C-y" 'isearch-yank-line)
+;; Some bindings you may want to put in your isearch-mode-hook.
+;; Suggest some alternates...
+;; (define-key isearch-mode-map "\C-t" 'isearch-toggle-regexp)
+;; (define-key isearch-mode-map "\C-^" 'isearch-edit-string)
- (define-key isearch-mode-map "\C-t" 'isearch-toggle-regexp)
- (define-key isearch-mode-map "\C-^" 'isearch-edit-string)
- ;; define keys for regexp chars * ? |
- (define-key isearch-mode-map "*" 'isearch-*-char)
- (define-key isearch-mode-map "?" 'isearch-*-char)
- (define-key isearch-mode-map "|" 'isearch-|-char)
+(defvar minibuffer-local-isearch-map nil
+ "Keymap for editing isearch strings in the minibuffer.")
- ;; Assumes meta-prefix-char is \e.
- ;; isearch-mode-meta-map must be a keymap before this.
- (define-key isearch-mode-map "\e" isearch-mode-meta-map)
- ))
+(or minibuffer-local-isearch-map
+ (let ((map (copy-keymap minibuffer-local-map)))
+ (define-key map "\r" 'isearch-nonincremental-exit-minibuffer)
+ (define-key map "\M-n" 'isearch-ring-advance-edit)
+ (define-key map "\M-p" 'isearch-ring-retreat-edit)
+ (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)
+ ))
;;;========================================================
;; Internal variables declared globally for byte-compiler.
-;; These are all made buffer-local during searching.
-
-(defvar isearch-cmds nil
- "Stack of search status sets.")
-(defvar isearch-string ""
- "The current search string.")
-(defvar isearch-message ""
- "The text-char-description version of isearch-string")
-(defvar isearch-success t)
-(defvar isearch-forward nil)
-(defvar isearch-other-end nil
- "Start of last match if forward, end if backward.")
-(defvar isearch-invalid-regexp nil)
-(defvar isearch-wrapped nil)
+;; 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.
+(defvar isearch-other-end nil) ; Start (end) of match if forward (backward).
+(defvar isearch-wrapped nil) ; Searching restarted from the top (bottom).
(defvar isearch-barrier 0)
-(defvar isearch-regexp nil)
-(defvar isearch-case-fold-search nil
- "Value of case-fold-search while actually searching.")
+(defvar isearch-case-fold-search nil) ; case-fold-search while searching.
(defvar isearch-adjusted nil)
(defvar isearch-slow-terminal-mode nil)
-(defvar isearch-small-window nil
- "If t, using a small window.")
-(defvar isearch-found-point nil
- "to restore point from a small window.")
-
-(defvar isearch-found-start nil
- "This is the window-start value found by the search.")
+;;; If t, using a small window.
+(defvar isearch-small-window nil)
(defvar isearch-opoint 0)
-(defvar isearch-window-configuration nil
- "The window configuration active at the beginning of the search.")
-(defvar isearch-old-local-map [])
+;;; The window configuration active at the beginning of the search.
+(defvar isearch-window-configuration nil)
+(defvar isearch-old-local-map nil)
-(defvar isearch-yank-flag nil
- "Flag to indicate a yank occurred, so don't move the cursor.")
+;; Flag to indicate a yank occurred, so don't move the cursor.
+(defvar isearch-yank-flag nil)
-(defvar isearch-op-fun nil
- "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'.")
+;;; 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)
-;; This is a global variable to avoid byte-compile warnings.
-(defvar isearch-last-command-char -1
- "Last command char.")
+;;; Is isearch-mode in a recursive edit for modal searching.
+(defvar isearch-recursive-edit nil)
-(defvar isearch-mode-hook nil
- "List of functions to call after starting up an incremental search.
-See `isearch-modal' for an example.
-Set with `(setq isearch-mode-hook (cons 'myhook isearch-mode-hook))
-where myhook can be a function name or lambda expression.")
+;;; 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)
-(defvar isearch-mode-end-hook nil
- "List of functions to call after terminating an incremental search.
-See `isearch-mode-hook' for more details.")
;;;==============================================================
;; Minor-mode-alist changes - kind of redundant with the
(nconc minor-mode-alist
(list '(isearch-mode isearch-mode))))
-(defvar isearch-mode nil)
+(defvar isearch-mode nil) ;; Name of the minor mode, if non-nil.
(make-variable-buffer-local 'isearch-mode)
+(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)
+
;;;===============================================================
;;; Entry points to isearch-mode.
-;;; These four functions should be moved to loaddefs.el
+;;; These four functions should replace those in loaddefs.el
+;;; An alternative is to defalias isearch-forward etc to isearch-mode,
+;;; and look at this-command to set the options accordingly.
-(defun isearch-forward ()
+(defun isearch-forward (&optional regexp-p no-recursive-edit)
"\
Do incremental search forward.
+With a prefix argument, do an incremental regular expression search instead.
+\\<isearch-mode-map>
As you type characters, they add to the search string and are found.
+The following non-printing keys are bound in `isearch-mode-map'.
-\\<isearch-mode-map>
-Type \\[isearch-delete-char] to cancel characters from end of search
-string.
+Type \\[isearch-delete-char] to cancel characters from end of search string.
Type \\[isearch-exit] to exit, leaving point at location found.
-Type \\[isearch-repeat-forward] to search again forward,
-\\[isearch-repeat-backward] to search again backward.
-Type \\[isearch-toggle-regexp] to toggle regular expression with normal searching.
-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, etc.
+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.
Type \\[isearch-quote-char] to quote control character to search for it.
-Type C-j to match end of line.
+\\[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.
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.
-Type \\[isearch-ring-retreat] to search for the previous item in the search ring.
+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.
+The above keys, bound in `isearch-mode-map', are often controlled by
+ options; do M-x apropos on search-.* to find them.
Other control and meta characters terminate the search
- and are then executed normally.
+ and are then executed normally (depending on `search-exit-option').
-\\[isearch-quit] while searching or when search has failed
- cancels input back to what has been found successfully.
-\\[isearch-quit] when search is successful aborts and moves point to starting point.
+If this function is called non-interactively, it does not return to
+the calling function until the search is done."
-All of these keys are bound in `isearch-mode-map' and
-`isearch-mode-meta-map'. If `isearch-forward' is called
-non-interactively, it does not return to the calling function until
-the search is done."
- (interactive)
- (if (interactive-p)
- (isearch-mode t)
- (isearch-modal t)))
+ (interactive "P\np")
+ (isearch-mode t (not (null regexp-p)) nil (not no-recursive-edit)))
-(defun isearch-forward-regexp ()
+(defun isearch-forward-regexp (&optional not-regexp no-recursive-edit)
"\
Do incremental search forward for regular expression.
+With a prefix argument, do a regular string search instead.
Like ordinary incremental search except that your input
is treated as a regexp. See \\[isearch-forward] for more info."
- (interactive)
- (if (interactive-p)
- (isearch-mode t t)
- (isearch-modal t t)))
+ (interactive "P\np")
+ (isearch-mode t (null not-regexp) nil (not no-recursive-edit)))
-(defun isearch-backward ()
+(defun isearch-backward (&optional regexp-p no-recursive-edit)
"\
Do incremental search backward.
+With a prefix argument, do a regular expression search instead.
See \\[isearch-forward] for more information."
- (interactive)
- (if (interactive-p)
- (isearch-mode nil)
- (isearch-modal nil)))
+ (interactive "P\np")
+ (isearch-mode nil (not (null regexp-p)) nil (not no-recursive-edit)))
-(defun isearch-backward-regexp ()
+(defun isearch-backward-regexp (&optional not-regexp no-recursive-edit)
"\
Do incremental search backward for regular expression.
+With a prefix argument, do a regular string search instead.
Like ordinary incremental search except that your input
is treated as a regexp. See \\[isearch-forward] for more info."
+ (interactive "P\np")
+ (isearch-mode nil (null not-regexp) nil (not no-recursive-edit)))
+
+
+(defun isearch-mode-help ()
(interactive)
- (if (interactive-p)
- (isearch-mode nil t)
- (isearch-modal nil t)))
-
-
-(defun isearch-modal (forward &optional regexp op-fun)
- ;; As an example of using the hooks, 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.
- ;; This is used if the above functions are called non-interactively.
- (let ((isearch-mode-hook
- (cons (function (lambda () (recursive-edit)))
- isearch-mode-hook))
- (isearch-mode-end-hook
- (cons (function (lambda () (exit-recursive-edit)))
- isearch-mode-end-hook)))
- (isearch-mode forward regexp op-fun)))
+ (describe-function 'isearch-forward)
+ (isearch-update))
\f
;;;==================================================================
;; isearch-mode only sets up incremental search for the minor mode.
;; All the work is done by the isearch-mode commands.
-(defun isearch-mode (forward &optional regexp op-fun)
+;; Not used yet:
+;;(defconst isearch-commands '(isearch-forward isearch-backward
+;; 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)
"Start isearch minor mode. Called by isearch-forward, etc."
- ;; Make buffer-local variables for isearching.
- ;; We really need window-local variables.
- (mapcar
- 'make-local-variable
- '(isearch-forward
- isearch-regexp isearch-string isearch-message
- isearch-case-fold-search
- isearch-cmds isearch-success isearch-wrapped
- isearch-barrier isearch-adjusted isearch-invalid-regexp
- isearch-slow-terminal-mode isearch-other-end isearch-small-window
- isearch-found-point isearch-found-start isearch-opoint
- isearch-window-configuration isearch-old-local-map))
;; Initialize global vars.
(setq isearch-forward forward
isearch-regexp regexp
+ isearch-word word-p
isearch-op-fun op-fun
isearch-case-fold-search case-fold-search
isearch-string ""
isearch-adjusted nil
isearch-yank-flag nil
isearch-invalid-regexp nil
+ ;; Use (baud-rate) for now, for sake of other versions.
isearch-slow-terminal-mode (and (<= (baud-rate) search-slow-speed)
(> (window-height)
(* 4 search-slow-window-lines)))
isearch-other-end nil
isearch-small-window nil
- isearch-found-point nil
- isearch-found-start nil
isearch-opoint (point)
- isearch-window-configuration (current-window-configuration)
isearch-old-local-map (current-local-map)
-
-;; inhibit-quit t
- )
+ search-ring-yank-pointer nil
+ regexp-search-ring-yank-pointer nil)
+ (if isearch-slow-terminal-mode
+ (setq isearch-window-configuration (current-window-configuration)))
+
+;; This was for Lucid Emacs. But now that we have pre-command-hook,
+;; it causes trouble.
+;; (if isearch-pre-command-hook-exists
+;; (add-hook 'pre-command-hook 'isearch-pre-command-hook))
(setq isearch-mode " Isearch") ;; forward? regexp?
(set-buffer-modified-p (buffer-modified-p)) ; update modeline
+ ;; It is ugly to show region highlighting while the search
+ ;; is going on. And we don't want the mark active at the end either.
+ (setq deactivate-mark t)
+
(isearch-push-state)
(use-local-map isearch-mode-map)
(isearch-update)
(run-hooks 'isearch-mode-hook)
+
+ ;; 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.
+ (if recursive-edit
+ (let ((isearch-recursive-edit t))
+ (recursive-edit)))
)
(defun isearch-update ()
;; Called after each command to update the display.
- (or unread-command-char
+ (if (if isearch-event-data-type
+ (null unread-command-event)
+ (if isearch-gnu-emacs-events
+ (null unread-command-events)
+ (< unread-command-char 0)))
(progn
(if (not (input-pending-p))
(isearch-message))
(if (and isearch-slow-terminal-mode
(not (or isearch-small-window
(pos-visible-in-window-p))))
- (progn
+ (let ((found-point (point)))
(setq isearch-small-window t)
- (setq isearch-found-point (point))
(move-to-window-line 0)
(let ((window-min-height 1))
(split-window nil (if (< search-slow-window-lines 0)
(window-hscroll))
(set-window-hscroll (selected-window) 0))
(other-window 1))
- (goto-char isearch-found-point)))))
+ (goto-char found-point)))
+ (if isearch-other-end
+ (if (< isearch-other-end (point)) ; isearch-forward?
+ (isearch-highlight isearch-other-end (point))
+ (isearch-highlight (point) isearch-other-end)))
+ ))
(setq ;; quit-flag nil not for isearch-mode
isearch-adjusted nil
isearch-yank-flag nil)
)
-(defun isearch-done ()
+(defun isearch-done (&optional nopush)
;; Called by all commands that terminate isearch-mode.
+ ;; If NOPUSH is non-nil, we don't push the string on the search ring.
(use-local-map isearch-old-local-map)
- (setq isearch-found-start (window-start (selected-window)))
- (setq isearch-found-point (point))
- (set-window-configuration isearch-window-configuration)
+ ;; (setq pre-command-hook isearch-old-pre-command-hook) ; for lemacs
+ (isearch-dehighlight t)
+ (let ((found-start (window-start (selected-window)))
+ (found-point (point)))
+ (if isearch-window-configuration
+ (set-window-configuration isearch-window-configuration))
+
+ ;; If there was movement, mark the starting position.
+ ;; Maybe should test difference between and set mark iff > threshold.
+ (if (/= (point) isearch-opoint)
+ (progn
+ (push-mark isearch-opoint t)
+ (deactivate-mark)
+ (or executing-macro (> (minibuffer-depth) 0)
+ (message "Mark saved where search started")))
+ ;; (message "") why is this needed?
+ )
+ (if isearch-small-window
+ (goto-char found-point)
+ ;; Exiting the save-window-excursion clobbers window-start; restore it.
+ (set-window-start (selected-window) found-start t)))
+
+ (setq isearch-mode nil)
+ (set-buffer-modified-p (buffer-modified-p)) ;; update modeline
- (if (> (length isearch-string) 0)
+ (if (and (> (length isearch-string) 0) (not nopush))
;; Update the ring data.
(if isearch-regexp
- (if (not (setq regex-search-ring-yank-pointer
- (memq isearch-string regex-search-ring)))
+ (if (or (null regexp-search-ring)
+ (not (string= isearch-string (car regexp-search-ring))))
(progn
- (setq regex-search-ring (cons isearch-string regex-search-ring)
- regex-search-ring-yank-pointer regex-search-ring)
- (if (> (length regex-search-ring) regex-search-ring-max)
- (setcdr (nthcdr (1- search-ring-max) regex-search-ring)
+ (setq regexp-search-ring
+ (cons isearch-string regexp-search-ring))
+ (if (> (length regexp-search-ring) regexp-search-ring-max)
+ (setcdr (nthcdr (1- search-ring-max) regexp-search-ring)
nil))))
- (if (not (setq search-ring-yank-pointer
- (memq isearch-string search-ring)))
+ (if (or (null search-ring)
+ (not (string= isearch-string (car search-ring))))
(progn
- (setq search-ring (cons isearch-string search-ring)
- search-ring-yank-pointer search-ring)
+ (setq search-ring (cons isearch-string search-ring))
(if (> (length search-ring) search-ring-max)
(setcdr (nthcdr (1- search-ring-max) search-ring) nil))))))
- ;; If there was movement, mark the starting position.
- ;; Maybe should test difference between and set mark iff > threshold.
- (if (/= (point) isearch-opoint)
- (push-mark isearch-opoint)
- (message ""))
- (if isearch-small-window
- (goto-char isearch-found-point)
- ;; Exiting the save-window-excursion clobbers window-start; restore it.
- (set-window-start (selected-window) isearch-found-start t))
-
- ;; Kill buffer-local variables for isearching
- (mapcar
- 'kill-local-variable
- '(isearch-forward
- isearch-regexp isearch-string isearch-message
- isearch-case-fold-search
- isearch-cmds isearch-success isearch-wrapped
- isearch-barrier isearch-adjusted isearch-invalid-regexp
- isearch-slow-terminal-mode isearch-other-end isearch-small-window
- isearch-found-point isearch-found-start isearch-opoint
- isearch-window-configuration isearch-old-local-map))
-
- (setq isearch-mode nil)
- (set-buffer-modified-p (buffer-modified-p))
(run-hooks 'isearch-mode-end-hook)
- )
+ (if isearch-recursive-edit (exit-recursive-edit)))
+
+;;;=======================================================
+;;; Switching buffers should first terminate isearch-mode.
+;;; This is done quite differently for each variant of emacs.
+;;; 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)
+ (handle-switch-frame (car (cdr (isearch-last-command-char)))))
+
+;;;========================================================
\f
;;;====================================================
"Exit search normally.
However, if this is the first command after starting incremental
search and `search-nonincremental-instead' is non-nil, do a
-nonincremental search instead."
-
+nonincremental search instead via `isearch-edit-string'."
(interactive)
(if (and search-nonincremental-instead
(= 0 (length isearch-string)))
- (nonincremental-search isearch-forward isearch-regexp))
+ (let ((isearch-nonincremental t))
+ (isearch-edit-string)))
(isearch-done))
(defun isearch-edit-string ()
- "Edit the search string in the minibuffer and return to incremental search."
- ;; This doesnt back up the search point.
+ "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.
+\\[isearch-backward-exit-minibuffer] to resume isearching backward.
+\\[isearch-ring-advance-edit] to replace the search string with the next item in the search ring.
+\\[isearch-ring-retreat-edit] to replace the search string with the previous item in the search ring.
+\\[isearch-complete-edit] to complete the search string using the search ring.
+
+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.
+ ;; Editing doesn't back up the search point. Should it?
(interactive)
- (setq isearch-string (read-string (isearch-message-prefix) isearch-string)
- isearch-message (mapconcat 'text-char-description
- isearch-string ""))
- (isearch-push-state)
- (isearch-search)
- (isearch-update))
+ (condition-case err
+ (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-other-end isearch-other-end)
+ (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)
+ (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))
+ (if isearch-event-data-type
+ (allocate-event) (read-char))))
+ ;; Binding minibuffer-history-symbol to nil is a work-around
+ ;; for some incompatibility with gmhist.
+ (minibuffer-history-symbol))
+ ;; 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
+ (char-to-string
+ (if isearch-event-data-type
+ (or (event-to-character (next-command-event e)) 0)
+ e))))
+ (setq isearch-word t ;; so message-prefix is right
+ isearch-new-word t)
+ (isearch-unread e))
+ (setq cursor-in-echo-area nil)
+ (setq isearch-new-string
+ (let (junk-ring)
+ (read-from-minibuffer (isearch-message-prefix)
+ isearch-string
+ minibuffer-local-isearch-map nil
+ 'junk-ring))
+ isearch-new-message (mapconcat 'text-char-description
+ isearch-new-string "")))
+ ;; Always resume isearching by restarting it.
+ (isearch-mode isearch-forward
+ isearch-regexp
+ isearch-op-fun
+ isearch-recursive-edit
+ 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 (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.
+ )
+
+ ;; Reinvoke the pending search.
+ (isearch-push-state)
+ (isearch-search)
+ (isearch-update)
+ (if isearch-nonincremental
+ (progn
+ ;; (sit-for 1) ;; needed if isearch-done does: (message "")
+ (isearch-done))))
+
+ (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))
+
+(defun isearch-reverse-exit-minibuffer ()
+ (interactive)
+ (setq isearch-new-forward nil)
+ (exit-minibuffer))
-(defun isearch-quit ()
- "Quit incremental search mode if searching is successful.
-Otherwise, revert to previous successful search and continue searching."
+(defun isearch-abort ()
+ "Abort incremental search mode if searching is successful, signalling quit.
+Otherwise, revert to previous successful search and continue searching.
+Use `isearch-exit' to quit without signalling."
(interactive)
- (ding)
+;; (ding) signal instead below, if quitting
(discard-input)
(if isearch-success
;; If search is successful, move back to starting point
;; and really do quit.
(progn (goto-char isearch-opoint)
- (isearch-done)) ; exit and quit
- ;; If search is failing, rub out until it is once more
- ;; successful.
+ (isearch-done t) ; exit isearch
+ (signal 'quit nil)) ; and pass on quit signal
+ ;; If search is failing, rub out until it is once more successful.
(while (not isearch-success) (isearch-pop-state))
(isearch-update)))
(if (equal isearch-string "")
;; If search string is empty, use last one.
(setq isearch-string
-;; (if isearch-regexp
-;; search-last-regexp search-last-string)
(or (if isearch-regexp
- (if regex-search-ring-yank-pointer
- (car regex-search-ring-yank-pointer)
- (car regex-search-ring))
- (if search-ring-yank-pointer
- (car search-ring-yank-pointer)
- (car search-ring)))
+ (car regexp-search-ring)
+ (car search-ring))
"")
isearch-message
- (mapconcat 'text-char-description
+ (mapconcat 'isearch-text-char-description
isearch-string ""))
;; If already have what to search for, repeat it.
(or isearch-success
;; The status stack is left unchanged.
(interactive)
(setq isearch-regexp (not isearch-regexp))
+ (if isearch-regexp (setq isearch-word nil))
(isearch-update))
(defun isearch-delete-char ()
(defun isearch-yank (chunk)
;; Helper for isearch-yank-word and isearch-yank-line
- (let ((word (save-excursion
- (and (not isearch-forward) isearch-other-end
- (goto-char isearch-other-end))
- (buffer-substring
- (point)
- (save-excursion
- (cond
- ((eq chunk 'word)
- (forward-word 1))
- ((eq chunk 'line)
- (end-of-line)))
- (point))))))
- (if isearch-regexp (setq word (regexp-quote word)))
- (setq isearch-string (concat isearch-string word)
+ (let ((string (save-excursion
+ (and (not isearch-forward) isearch-other-end
+ (goto-char isearch-other-end))
+ (buffer-substring
+ (point)
+ (save-excursion
+ (cond
+ ((eq chunk 'word)
+ (forward-word 1))
+ ((eq chunk 'line)
+ (end-of-line)))
+ (point))))))
+ ;; 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 'text-char-description
- word ""))
+ (mapconcat 'isearch-text-char-description
+ string ""))
;; Don't move cursor in reverse search.
isearch-yank-flag t))
(isearch-search-and-update))
;; *, ?, and | chars can make a regexp more liberal.
-;; They can make a regexp match sooner
-;; or make it succeed instead of failing.
+;; They can make a regexp match sooner or make it succeed instead of failing.
;; So go back to place last successful search started
;; or to the last ^S/^R (barrier), whichever is nearer.
+;; + needs no special handling because the string must match at least once.
(defun isearch-*-char ()
"Handle * and ? specially in regexps."
(if isearch-forward
(max cs isearch-barrier)
(min cs isearch-barrier))))))
- (isearch-process-search-char last-command-char))
+ (isearch-process-search-char (isearch-last-command-char)))
-
(defun isearch-|-char ()
"If in regexp search, jump to the barrier."
(interactive)
(progn
(setq isearch-adjusted t)
(goto-char isearch-barrier)))
- (isearch-process-search-char last-command-char))
+ (isearch-process-search-char (isearch-last-command-char)))
-
-(defun isearch-other-control-char ()
- "Any other control char => unread it and exit the search normally.
-But only if `search-exit-option' is non-nil."
- (interactive)
- (if search-exit-option
- (progn
- (setq unread-command-char last-command-char)
- (isearch-done))
- ;; otherwise
- (isearch-search-and-update)))
-
+(defalias 'isearch-other-control-char 'isearch-other-meta-char)
(defun isearch-other-meta-char ()
- "Any other meta char => exit the search normally and reexecute the whole key.
-But only if `search-exit-option' is non-nil."
- ;; This will probably work in place of isearch-other-control-char too,
- ;; but here we use unwind-protect and command-execute since it is
- ;; a multi-char key we would want to unread.
+ "Exit the search normally and reread this key sequence.
+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."
(interactive)
- (if search-exit-option
- (unwind-protect
- (isearch-done) ;; this exits recursive edit
- ;; Reexecute the key.
- (command-execute (this-command-keys)))
- ;; otherwise
- (isearch-search-and-update)))
-
+ (cond ((eq search-exit-option 'edit)
+ (let ((key (this-command-keys)))
+ (apply 'isearch-unread (listify-key-sequence key)))
+ (isearch-edit-string))
+ (search-exit-option
+ (let ((key (this-command-keys))
+ (index 0)
+ window)
+ (apply 'isearch-unread (listify-key-sequence key))
+ ;; Properly handle scroll-bar and mode-line clicks
+ ;; for which a dummy prefix event was generated as (aref key 0).
+ (and (> (length key) 1)
+ (symbolp (aref key 0))
+ (listp (aref key 1))
+ (consp (posn-point (event-start (aref key 1))))
+ (setq index 1))
+ ;; If we got a mouse click, maybe it was read with the buffer
+ ;; it was clicked on. If so, that buffer, not the current one,
+ ;; is in isearch mode. So end the search in that buffer.
+ (if (and (listp (aref key index))
+ (setq window (posn-window (event-start (aref key index))))
+ (windowp window))
+ (save-excursion
+ (set-buffer (window-buffer window))
+ (isearch-done))
+ (isearch-done))))
+ (t;; otherwise nil
+ (isearch-process-search-string (this-command-keys)
+ (this-command-keys)))))
(defun isearch-quote-char ()
"Quote special characters for incremental search."
(interactive)
(isearch-process-search-char (read-quoted-char (isearch-message t))))
-
(defun isearch-return-char ()
"Convert return into newline for incremental search.
Obsolete."
(interactive)
(isearch-process-search-char ?\n))
-
(defun isearch-printing-char ()
- "Any other printing character => add it to the search string and search."
- (interactive)
- (isearch-process-search-char last-command-char))
-
-
-(defun isearch-upper-case-char ()
- "Any upper case char => turn off case fold search for remainder of search."
- ;; This feature only applies to interactively entered chars,
- ;; but not yanked chars, repeat default searches, or search ring searches.
- ;; Support for these should be easy to add.
+ "Add this ordinary printing character to the search string and search."
(interactive)
- (if search-caps-disable-folding
- (setq isearch-case-fold-search nil))
- (isearch-printing-char))
+ (isearch-process-search-char (isearch-last-command-char)))
(defun isearch-whitespace-chars ()
- "Match all whitespace chars, if in regexp mode."
+ "Match all whitespace chars, if in regexp mode.
+If you want to search for just a space, type C-q SPC."
(interactive)
- (if (and isearch-regexp search-whitespace-regexp)
- (isearch-process-search-string search-whitespace-regexp " ")
- (isearch-other-meta-char)))
+ (if isearch-regexp
+ (if search-whitespace-regexp
+ (isearch-process-search-string search-whitespace-regexp " ")
+ (isearch-printing-char))
+ (progn
+ ;; This way of doing word search doesn't correctly extend current search.
+ ;; (setq isearch-word t)
+ ;; (setq isearch-adjusted t)
+ ;; (goto-char isearch-barrier)
+ (isearch-printing-char))))
(defun isearch-process-search-char (char)
;; Append the char to the search string, update the message and re-search.
- (isearch-process-search-string (char-to-string char)
-
- (text-char-description char)))
+ (isearch-process-search-string
+ (isearch-char-to-string char)
+ (isearch-text-char-description char)))
(defun isearch-process-search-string (string message)
(setq isearch-string (concat isearch-string string)
;;===========================================================
;; Search Ring
-(defun isearch-ring-adjust (advance)
- ;; helper for isearch-ring-advance and isearch-ring-retreat
- (if (cdr isearch-cmds)
- (isearch-pop-state))
- (let* ((ring (if isearch-regexp regex-search-ring search-ring))
+(defun isearch-ring-adjust1 (advance)
+ ;; Helper for isearch-ring-adjust
+ (let* ((ring (if isearch-regexp regexp-search-ring search-ring))
(length (length ring))
(yank-pointer-name (if isearch-regexp
- 'regex-search-ring-yank-pointer
+ 'regexp-search-ring-yank-pointer
'search-ring-yank-pointer))
(yank-pointer (eval yank-pointer-name)))
(if (zerop length)
()
(set yank-pointer-name
(setq yank-pointer
- (nthcdr (% (+ (- length (length yank-pointer))
- (if advance (1- length) 1))
- length) ring)))
- (setq isearch-string (car yank-pointer)
- isearch-message (mapconcat 'text-char-description
- isearch-string ""))))
+ (% (+ (or yank-pointer 0)
+ (if advance (1- length) 1))
+ length)))
+ (setq isearch-string (nth yank-pointer ring)
+ isearch-message (mapconcat 'isearch-text-char-description
+ isearch-string "")))))
+
+(defun isearch-ring-adjust (advance)
+ ;; Helper for isearch-ring-advance and isearch-ring-retreat
+ (if (cdr isearch-cmds) ;; is there more than one thing on stack?
+ (isearch-pop-state))
+ (isearch-ring-adjust1 advance)
(isearch-push-state)
- (isearch-search)
- (isearch-update))
+ (if search-ring-update
+ (progn
+ (isearch-search)
+ (isearch-update))
+ (isearch-edit-string)
+ ))
(defun isearch-ring-advance ()
"Advance to the next search string in the ring."
+ ;; This could be more general to handle a prefix arg, but who would use it.
(interactive)
(isearch-ring-adjust 'advance))
(interactive)
(isearch-ring-adjust nil))
-\f
-;;;=============================================================
-;; Window-local variables
-;; (not used yet - and maybe never)
-
-(defvar window-local-variable-alist nil
- "An alist of windows associated with window local variables and values.
-The cdr of each item is another alist of variables and values.")
-
-(defvar last-local-window nil)
-(defvar last-window-local-vars nil)
-
-(defun kill-window-local-variables ()
- "Remove the old variable list, if any."
- (setq window-local-variable-alist
- (delq window-local-variable-alist
- (assq (selected-window)
- window-local-variable-alist))))
-
-;; Assume that window-local variables are not buffer-local
-;; so we can delay storing until absolutely necessary.
-
-(defun store-window-local-variables (&rest vars-and-vals)
- "Store the window local variables for selected window."
- (setq last-local-window (selected-window))
- (setq last-window-local-vars vars-and-vals))
-
+(defun isearch-ring-advance-edit (n)
+ "Insert the next element of the search history into the minibuffer."
+ (interactive "p")
+ (let* ((yank-pointer-name (if isearch-regexp
+ 'regexp-search-ring-yank-pointer
+ 'search-ring-yank-pointer))
+ (yank-pointer (eval yank-pointer-name))
+ (ring (if isearch-regexp regexp-search-ring search-ring))
+ (length (length ring)))
+ (if (zerop length)
+ ()
+ (set yank-pointer-name
+ (setq yank-pointer
+ (% (+ (or yank-pointer 0)
+ ;; Add LENGTH here to ensure a positive result.
+ length
+ (% (- n) length))
+ length)))
+
+ (erase-buffer)
+ (insert (nth yank-pointer ring))
+ (goto-char (point-max)))))
+
+(defun isearch-ring-retreat-edit (n)
+ "Inserts the previous element of the search history into the minibuffer."
+ (interactive "p")
+ (isearch-ring-advance-edit (- n)))
+
+;;(defun isearch-ring-adjust-edit (advance)
+;; "Use the next or previous search string in the ring while in minibuffer."
+;; (isearch-ring-adjust1 advance)
+;; (erase-buffer)
+;; (insert isearch-string))
+
+;;(defun isearch-ring-advance-edit ()
+;; (interactive)
+;; (isearch-ring-adjust-edit 'advance))
+
+;;(defun isearch-ring-retreat-edit ()
+;; "Retreat to the previous search string in the ring while in the minibuffer."
+;; (interactive)
+;; (isearch-ring-adjust-edit nil))
+
+
+(defun isearch-complete1 ()
+ ;; Helper for isearch-complete and isearch-complete-edit
+ ;; Return t if completion OK, nil if no completion exists.
+ (let* ((ring (if isearch-regexp regexp-search-ring search-ring))
+ (alist (mapcar (function (lambda (string) (list string))) ring))
+ (completion-ignore-case case-fold-search)
+ (completion (try-completion isearch-string alist)))
+ (cond
+ ((eq completion t)
+ ;; isearch-string stays the same
+ t)
+ ((or completion ; not nil, must be a string
+ (= 0 (length isearch-string))) ; shouldnt have to say this
+ (if (equal completion isearch-string) ;; no extension?
+ (if completion-auto-help
+ (with-output-to-temp-buffer "*Isearch completions*"
+ (display-completion-list
+ (all-completions isearch-string alist))))
+ (setq isearch-string completion))
+ t)
+ (t
+ (message "No completion") ; waits a second if in minibuffer
+ nil))))
+
+(defun isearch-complete ()
+ "Complete the search string from the strings on the search ring.
+The completed string is then editable in the minibuffer.
+If there is no completion possible, say so and continue searching."
+ (interactive)
+ (if (isearch-complete1)
+ (isearch-edit-string)
+ ;; else
+ (sit-for 1)
+ (isearch-update)))
-(defun fetch-window-local-variables ()
- "Fetch the window local variables for selected window.
-Does nothing if the last store was for the same window."
- (if (not (eq (selected-window) last-local-window))
+(defun isearch-complete-edit ()
+ "Same as `isearch-complete' except in the minibuffer."
+ (interactive)
+ (setq isearch-string (buffer-string))
+ (if (isearch-complete1)
(progn
- ;; First store the previous values.
- (setq window-local-variable-alist
- (cons (cons last-local-window
- last-window-local-vars)
- (delq window-local-variable-alist
- (assq last-local-window
- window-local-variable-alist))))
- ;; Now fetch the values for the selected-window.
- (setq last-local-window (selected-window))
- (setq last-window-local-vars
- (cdr (assq last-local-window window-local-variable-alist)))
- (let ((vars-and-vals last-window-local-vars))
- (while vars-and-vals
- (set (car vars-and-vals) (car (cdr vars-and-vals)))
- (setq vars-and-vals (cdr (cdr vars-and-vals))))))))
-
+ (erase-buffer)
+ (insert isearch-string))))
\f
;;;==============================================================
;; The search status stack (and isearch window-local variables, not used).
+;; Need a structure for this.
(defun isearch-top-state ()
-;; (fetch-window-local-variables)
(let ((cmd (car isearch-cmds)))
(setq isearch-string (car cmd)
isearch-message (car (cdr cmd))
isearch-success (nth 3 cmd)
isearch-forward (nth 4 cmd)
isearch-other-end (nth 5 cmd)
- isearch-invalid-regexp (nth 6 cmd)
- isearch-wrapped (nth 7 cmd)
- isearch-barrier (nth 8 cmd))
+ isearch-word (nth 6 cmd)
+ isearch-invalid-regexp (nth 7 cmd)
+ isearch-wrapped (nth 8 cmd)
+ isearch-barrier (nth 9 cmd))
(goto-char (car (cdr (cdr cmd))))))
(defun isearch-pop-state ()
-;; (fetch-window-local-variables)
(setq isearch-cmds (cdr isearch-cmds))
(isearch-top-state)
)
(setq isearch-cmds
(cons (list isearch-string isearch-message (point)
isearch-success isearch-forward isearch-other-end
+ isearch-word
isearch-invalid-regexp isearch-wrapped isearch-barrier)
isearch-cmds)))
-(defun isearch-store-variables ()
- (store-window-local-variables
- 'isearch-cmds isearch-cmds
- 'isearch-regexp isearch-regexp
- 'isearch-adjusted isearch-adjusted
- 'isearch-slow-terminal-mode isearch-slow-terminal-mode
- 'isearch-small-window isearch-small-window
- 'isearch-found-point isearch-found-point
- 'isearch-found-start isearch-found-start
- 'isearch-opoint isearch-opoint
- 'isearch-window-configuration isearch-window-configuration
- 'isearch-old-local-map isearch-old-local-map
- ))
-
\f
;;;==================================================================
;; Message string
;; Generate and print the message string.
(let ((cursor-in-echo-area ellipsis)
(m (concat
- (isearch-message-prefix c-q-hack ellipsis)
+ (isearch-message-prefix c-q-hack ellipsis isearch-nonincremental)
isearch-message
(isearch-message-suffix c-q-hack ellipsis)
)))
(if c-q-hack m (message "%s" m))))
-(defun isearch-message-prefix (&optional c-q-hack ellipsis)
+(defun isearch-message-prefix (&optional c-q-hack ellipsis nonincremental)
;; If about to search, and previous search regexp was invalid,
;; check that it still is. If it is valid now,
;; let the message we display while searching say that it is valid.
(or isearch-success (setq ellipsis nil))
(let ((m (concat (if isearch-success "" "failing ")
(if isearch-wrapped "wrapped ")
+ (if isearch-word "word " "")
(if isearch-regexp "regexp " "")
- "I-search"
+ (if nonincremental "search" "I-search")
(if isearch-forward ": " " backward: ")
)))
(aset m 0 (upcase (aref m 0)))
(defun isearch-search ()
;; Do the search with the current search string.
(isearch-message nil t)
+ (if (and isearch-case-fold-search search-upper-case)
+ (setq isearch-case-fold-search
+ (isearch-no-upper-case-p isearch-string isearch-regexp)))
(condition-case lossage
(let ((inhibit-quit nil)
(case-fold-search isearch-case-fold-search))
(if isearch-regexp (setq isearch-invalid-regexp nil))
(setq isearch-success
(funcall
- (if isearch-regexp
- (if isearch-forward 're-search-forward 're-search-backward)
- (if isearch-forward 'search-forward 'search-backward))
+ (cond (isearch-word
+ (if isearch-forward
+ 'word-search-forward 'word-search-backward))
+ (isearch-regexp
+ (if isearch-forward
+ 're-search-forward 're-search-backward))
+ (t
+ (if isearch-forward 'search-forward 'search-backward)))
isearch-string nil t))
(if isearch-success
(setq isearch-other-end
(if isearch-forward (match-beginning 0) (match-end 0)))))
- (quit (setq unread-command-char ?\C-g)
+ (quit (isearch-unread ?\C-g)
(setq isearch-success nil))
(invalid-regexp
(if (string-match
"\\`Premature \\|\\`Unmatched \\|\\`Invalid "
isearch-invalid-regexp)
- (setq isearch-invalid-regexp "incomplete input"))))
+ (setq isearch-invalid-regexp "incomplete input")))
+ (error
+ ;; stack overflow in regexp search.
+ (setq isearch-invalid-regexp (car (cdr lossage)))))
(if isearch-success
nil
(ding))
(goto-char (nth 2 (car isearch-cmds)))))
-;;;=================================================
-;; This is called from incremental-search
-;; if the first input character is the exit character.
-;; We store the search string in `isearch-string'
-;; which has been bound already by `isearch-search'
-;; so that, when we exit, it is copied into `search-last-string'.
+\f
+;;;========================================================
+;;; Highlighting
+
+(defvar isearch-overlay nil)
-(defun nonincremental-search (forward regexp)
- ;; This may be broken. Anyway, it could be replaced by the
- ;; isearch-edit-string command instead.
- (setq isearch-forward forward
- isearch-regexp regexp)
- (let (char function
- inhibit-quit
- (cursor-in-echo-area t))
- ;; Prompt assuming not word search,
- (setq isearch-message
-
- (if isearch-regexp
-
- (if isearch-forward "Regexp search: "
- "Regexp search backward: ")
- (if isearch-forward "Search: " "Search backward: ")))
- (message "%s" isearch-message)
- ;; Read 1 char and switch to word search if it is ^W.
- (setq char (read-char))
- (if (eq char search-yank-word-char)
- (setq isearch-message (if isearch-forward "Word search: "
-
- "Word search backward: "))
- ;; Otherwise let that 1 char be part of the search string.
- (setq unread-command-char char))
- (setq function
- (if (eq char search-yank-word-char)
- (if isearch-forward 'word-search-forward 'word-search-backward)
- (if isearch-regexp
- (if isearch-forward 're-search-forward 're-search-backward)
- (if isearch-forward 'search-forward 'search-backward))))
- ;; Read the search string with corrected prompt.
- (setq isearch-string (read-string isearch-message isearch-string))
- ;; Empty means use default.
- (if (= 0 (length isearch-string))
- (setq isearch-string search-last-string)
- ;; Set last search string now so it is set even if we fail.
- (setq search-last-string isearch-string))
- ;; Since we used the minibuffer, we should be available for redo.
- (setq command-history
-
- (cons (list function isearch-string) command-history))
- ;; Go ahead and search.
- (let ((case-fold-search isearch-case-fold-search))
- (funcall function isearch-string))))
+(defun isearch-highlight (beg end)
+ (if (null search-highlight)
+ nil
+ (or isearch-overlay (setq isearch-overlay (make-overlay beg end)))
+ (move-overlay isearch-overlay beg end (current-buffer))
+ (overlay-put isearch-overlay 'face
+ (if (internal-find-face 'isearch nil)
+ 'isearch 'region))))
+
+(defun isearch-dehighlight (totally)
+ (if isearch-overlay
+ (delete-overlay isearch-overlay)))
+
+;;;===========================================================
+;;; General utilities
+
+
+(defun isearch-no-upper-case-p (string regexp-flag)
+ "Return t if there are no upper case chars in STRING.
+If REGEXP-FLAG is non-nil, disregard letters preceeded by `\\' (but not `\\\\')
+since they have special meaning in a regexp."
+ (let ((case-fold-search nil))
+ (not (string-match (if regexp-flag "\\(^\\|\\\\\\\\\\|[^\\]\\)[A-Z]"
+ "[A-Z]")
+ string))))
+
+
+;;;=================================================
+;; Portability functions to support various Emacs versions.
+
+;; To quiet the byte-compiler.
+(defvar unread-command-event)
+(defvar unread-command-events)
+(defvar last-command-event)
+
+(defun isearch-char-to-string (c)
+ (if (integerp c)
+ (make-string 1 c)
+ (if (and (symbolp c) (get c 'ascii-character))
+ (make-string 1 (get c 'ascii-character))
+ (make-string 1 (event-to-character c)))))
+
+(defun isearch-text-char-description (c)
+ (isearch-char-to-string c))
+
+(defun isearch-unread (&rest char-or-events)
+ ;; General function to unread characters or events.
+ (if isearch-gnu-emacs-events
+ (setq unread-command-events
+ (append char-or-events unread-command-events))
+ (let ((char (if (cdr char-or-events)
+ (progn
+ (while (cdr char-or-events)
+ (setq char-or-events (cdr char-or-events)))
+ (+ 128 (car char-or-events)))
+ (car char-or-events))))
+ (if isearch-event-data-type
+ (setq unread-command-event char)
+ (setq unread-command-char char)))))
+
+(defun isearch-last-command-char ()
+ ;; General function to return the last command character.
+ (if isearch-event-data-type
+ last-command-event
+ last-command-char))
+
+;;; isearch.el ends here