;;; isearch.el --- incremental search minor mode
-;; Copyright (C) 1992, 93, 94, 95, 96, 97, 1999, 2000, 2001
+;; Copyright (C) 1992, 93, 94, 95, 96, 97, 1999, 2000, 01, 2003, 2004
;; Free Software Foundation, Inc.
;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
;; 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.
;;; Code:
\f
-;;; Some additional options and constants.
+;; Some additional options and constants.
(defgroup isearch nil
"Incremental search minor mode."
:type 'boolean
:group 'isearch)
-(defcustom search-whitespace-regexp "\\s-+"
+(defcustom search-whitespace-regexp "\\(?:\\s-+\\)"
"*If non-nil, regular expression to match a sequence of whitespace chars.
This applies to regular expression incremental search.
You might want to use something like \"[ \\t\\r\\n]+\" instead.
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'.)"
+\(This applies when using `outline.el' and `hideshow.el'.)
+See also `reveal-mode' if you want overlays to automatically be opened
+whenever point is in one of them."
:type '(choice (const :tag "Match hidden text" t)
(const :tag "Open overlays" open)
(const :tag "Don't match hidden text" nil))
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."
- :type 'boolean
+Ordinarily the text becomes invisible again at the end of the search."
+ :type 'boolean
:group 'isearch)
(defcustom isearch-resume-enabled t
(defvar isearch-mode-end-hook nil
"Function(s) to call after terminating an incremental search.")
-;;; Search ring.
+;; Search ring.
(defvar search-ring nil
"List of search string sequences.")
:type 'boolean
:group 'isearch)
-;;; Define isearch-mode keymap.
+;; Define isearch-mode keymap.
(defvar isearch-mode-map
(let* ((i 0)
(while l
(set-char-table-default table (car l) 'isearch-printing-char)
(setq l (cdr l))))
- ;; Make function keys, etc, exit the search.
+ ;; Make function keys, etc, which aren't bound to a scrolling-function
+ ;; 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,
+ ;; 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 ?\ )
(error "Inconsistency in isearch.el"))
(define-key map "\e\e\e" 'isearch-cancel)
(define-key map [escape escape escape] 'isearch-cancel)
-
+
(define-key map "\C-q" 'isearch-quote-char)
(define-key map "\r" 'isearch-exit)
(define-key map "\t" 'isearch-printing-char)
(define-key map " " 'isearch-whitespace-chars)
(define-key map [?\S-\ ] 'isearch-whitespace-chars)
-
+
(define-key map "\C-w" 'isearch-yank-word-or-char)
(define-key map "\C-y" 'isearch-yank-line)
;; Nothing special for + because it matches at least once.
(define-key map "*" 'isearch-*-char)
(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)
+ ;; 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)
(define-key map "\M-n" 'isearch-ring-advance)
(define-key map "\M-p" 'isearch-ring-retreat)
(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-hidden nil) ; Non-nil if the string exists but is invisible.
+
+(defvar isearch-cmds nil
+ "Stack of search status sets.
+Each set is a list of the form:
+ (STRING MESSAGE POINT SUCCESS FORWARD OTHER-END WORD
+ INVALID-REGEXP WRAPPED BARRIER WITHIN-BRACKETS CASE-FOLD-SEARCH)")
-(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-adjusted nil)
(defvar isearch-slow-terminal-mode nil)
-;;; If t, using a small window.
+;; If t, using a small window.
(defvar isearch-small-window nil)
(defvar isearch-opoint 0)
-;;; The window configuration active at the beginning of the search.
+;; The window configuration active at the beginning of the search.
(defvar isearch-window-configuration nil)
;; Flag to indicate a yank occurred, so don't move the cursor.
(defvar isearch-yank-flag 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)
-;;; Is isearch-mode in a recursive edit for modal searching.
+;; Is isearch-mode in a recursive edit for modal searching.
(defvar isearch-recursive-edit nil)
-;;; Should isearch be terminated after doing one search?
+;; Should isearch be terminated after doing one search?
(defvar isearch-nonincremental nil)
;; New value of isearch-forward after isearch-edit-string.
(define-key global-map "\C-r" 'isearch-backward)
(define-key esc-map "\C-r" 'isearch-backward-regexp)
-;;; Entry points to isearch-mode.
+;; Entry points to isearch-mode.
(defun isearch-forward (&optional regexp-p no-recursive-edit)
"\
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'.
+The following non-printing keys are bound in `isearch-mode-map'.
Type \\[isearch-delete-char] to cancel characters from end of search string.
Type \\[isearch-exit] to exit, leaving point at location found.
Type \\[isearch-complete] to complete the search string using the search ring.
If an input method is turned on in the current buffer, that input
-method is also active while you are typing a characters to search. To
+method is also active while you are typing characters to search. To
toggle the input method, type \\[isearch-toggle-input-method]. It
also toggles the input method in the current buffer.
\\[isearch-toggle-specified-input-method], and specify an input method
you want to use.
-The above keys, bound in `isearch-mode-map', are often controlled by
+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 (depending on `search-exit-option').
;;(defvar 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.
;; 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)))))
+ (unless (memq (frame-live-p frame) '(nil t))
+ (unless (frame-visible-p frame)
+ (make-frame-visible frame))
+ (if minibuffer-auto-raise
+ (raise-frame frame))))
(setq isearch-mode " Isearch") ;; forward? regexp?
(force-mode-line-update)
(add-hook 'mouse-leave-buffer-hook 'isearch-done)
(add-hook 'kbd-macro-termination-hook 'isearch-done)
- ;; isearch-mode can be made modal (in the sense of not returning to
- ;; the calling function until searching is completed) by entering
+ ;; 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))
;; Some high level utilities. Others below.
(defun isearch-update ()
- ;; Called after each command to update the display.
+ ;; Called after each command to update the display.
(if (and (null unread-command-events)
(null executing-kbd-macro))
(progn
(if (not (input-pending-p))
(isearch-message))
(if (and isearch-slow-terminal-mode
- (not (or isearch-small-window
+ (not (or isearch-small-window
(pos-visible-in-window-p))))
(let ((found-point (point)))
(setq isearch-small-window t)
(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 regexp
(if (or (null regexp-search-ring)
(not (string= string (car regexp-search-ring))))
(progn
- (setq regexp-search-ring
- (cons string regexp-search-ring))
+ (push string regexp-search-ring)
(if (> (length regexp-search-ring) regexp-search-ring-max)
(setcdr (nthcdr (1- search-ring-max) regexp-search-ring)
nil))))
(if (or (null search-ring)
(not (string= string (car search-ring))))
(progn
- (setq search-ring (cons string search-ring))
+ (push string search-ring)
(if (> (length search-ring) search-ring-max)
(setcdr (nthcdr (1- search-ring-max) search-ring) nil))))))
-;;; Switching buffers should first terminate isearch-mode.
-;;; ;; For Emacs 19, the frame switch event is handled.
-;;; (defun isearch-switch-frame-handler ()
-;;; (interactive) ;; Is this necessary?
-;;; ;; First terminate isearch-mode.
-;;; (isearch-done)
-;;; (isearch-clean-overlays)
-;;; (handle-switch-frame (car (cdr last-command-char))))
+;; Switching buffers should first terminate isearch-mode.
+;; ;; For Emacs 19, the frame switch event is handled.
+;; (defun isearch-switch-frame-handler ()
+;; (interactive) ;; Is this necessary?
+;; ;; First terminate isearch-mode.
+;; (isearch-done)
+;; (isearch-clean-overlays)
+;; (handle-switch-frame (car (cdr last-command-char))))
\f
;; Commands active while inside of the isearch minor mode.
search and `search-nonincremental-instead' is non-nil, do a
nonincremental search instead via `isearch-edit-string'."
(interactive)
- (if (and search-nonincremental-instead
+ (if (and search-nonincremental-instead
(= 0 (length isearch-string)))
(let ((isearch-nonincremental t))
(isearch-edit-string)))
)
;; Actually terminate isearching until editing is done.
- ;; This is so that the user can do anything without failure,
+ ;; 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)
(isearch-message) ;; for read-char
(unwind-protect
- (let* (;; Why does following read-char echo?
+ (let* (;; Why does following read-char echo?
;;(echo-keystrokes 0) ;; not needed with above message
(e (let ((cursor-in-echo-area t))
(read-event)))
(mapconcat 'isearch-text-char-description
isearch-new-string "")))
;; Always resume isearching by restarting it.
- (isearch-mode isearch-forward
- isearch-regexp
- isearch-op-fun
+ (isearch-mode isearch-forward
+ isearch-regexp
+ isearch-op-fun
nil
isearch-word)
;; Reinvoke the pending search.
(isearch-search)
(isearch-update)
- (if isearch-nonincremental
+ (if isearch-nonincremental
(progn
;; (sit-for 1) ;; needed if isearch-done does: (message "")
(isearch-done))))
(or (if isearch-regexp
(car regexp-search-ring)
(car search-ring))
- "")
+ (error "No previous search string"))
isearch-message
(mapconcat 'isearch-text-char-description
isearch-string "")
(isearch-yank-string (x-get-selection)))
-(defun isearch-mouse-2 (click arg)
+(defun isearch-mouse-2 (click)
"Handle mouse-2 in Isearch mode.
For a click in the echo area, invoke `isearch-yank-x-selection'.
Otherwise invoke whatever mouse-2 is bound to outside of Isearch."
- (interactive "e\nP")
+ (interactive "e")
(let* ((w (posn-window (event-start click)))
(overriding-terminal-local-map nil)
(key (vector (event-basic-type click)))
- (binding (key-binding key)))
+ ;; FIXME: `key-binding' should accept an event as argument
+ ;; and do all the overlay/text-properties lookup etc...
+ (binding (with-current-buffer
+ (if (window-live-p w) (window-buffer w) (current-buffer))
+ (key-binding key))))
(if (and (window-minibuffer-p w)
(not (minibuffer-window-active-p w))) ; in echo area
(isearch-yank-x-selection)
- (when binding
- ;; Kluge to allow passing ARG to functions that support it,
- ;; like mouse-yank-at-click.
- (if (equal (cadr (interactive-form binding)) "e\nP")
- (funcall binding click arg)
- (funcall binding click))))))
+ (when (functionp binding)
+ (call-interactively binding)))))
(defun isearch-yank-internal (jumpform)
"Pull next character or word from buffer into search string."
(interactive)
(isearch-yank-internal
- (lambda ()
+ (lambda ()
(if (or (= (char-syntax (or (char-after) 0)) ?w)
(= (char-syntax (or (char-after (1+ (point))) 0)) ?w))
(forward-word 1)
(defun isearch-yank-line ()
"Pull rest of line from buffer into search string."
(interactive)
- (isearch-yank-internal (lambda () (line-end-position))))
+ (isearch-yank-internal 'line-end-position))
(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
+ (when (or isearch-success
+ ;; unsuccessful regexp search may become
+ ;; successful by addition of characters which
+ ;; make isearch-string valid
+ isearch-regexp
+ ;; If the string was found but was completely invisible,
+ ;; it might now be partly visible, so try again.
+ (prog1 isearch-hidden (setq isearch-hidden nil)))
;; In reverse search, adding stuff at
;; the end may cause zero or many more chars to be
;; matched, in the string following point.
(regexp-quote isearch-string))))
(error nil))
(or isearch-yank-flag
- (<= (match-end 0)
+ (<= (match-end 0)
(min isearch-opoint isearch-barrier))))
(progn
- (setq isearch-success t
+ (setq isearch-success t
isearch-invalid-regexp nil
isearch-within-brackets nil
isearch-other-end (match-end 0))
;; 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
+ (min isearch-opoint
+ isearch-barrier
(1+ isearch-other-end)))))
(isearch-search)
))
(isearch-update))
+(defun isearch-{-char ()
+ "Handle \{ specially in regexps."
+ (interactive)
+ (isearch-*-char t))
+
;; *, ?, and | chars can make a regexp more liberal.
;; 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."
+(defun isearch-*-char (&optional want-backslash)
+ "Handle * and ? specially in regexps.
+When WANT-BACKSLASH is non-nil, do special handling for \{."
(interactive)
- (if isearch-regexp
+ (if isearch-regexp
(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)
+ ;; * and ? are special when not preceded by \.
+ ;; { is special when it is preceded by \.
+ (when (= (mod (- (length isearch-string) idx) 2)
+ (if want-backslash 1 0))
(setq isearch-adjusted t)
;; Get the isearch-other-end from before the last search.
;; We want to start from there,
(max cs isearch-barrier)
(min cs isearch-barrier)))))))
(isearch-process-search-char last-command-char))
-
+
(defun isearch-|-char ()
"If in regexp search, jump to the barrier."
(goto-char isearch-barrier)))
(isearch-process-search-char last-command-char))
+(defun isearch-unread-key-sequence (keylist)
+ "Unread the given key-sequence KEYLIST.
+Scroll-bar or mode-line events are processed appropriately."
+ (cancel-kbd-macro-events)
+ (apply 'isearch-unread keylist)
+ ;; If the event was a scroll-bar or mode-line click, the event will have
+ ;; been prefixed by a symbol such as vertical-scroll-bar. We must remove
+ ;; it here, because this symbol will be attached to the event again next
+ ;; time it gets read by read-key-sequence.
+ ;;
+ ;; (Old comment from isearch-other-meta-char: "Note that we don't have to
+ ;; modify the event anymore in 21 because read_key_sequence no longer
+ ;; modifies events to produce fake prefix keys.")
+ (if (and (> (length keylist) 1)
+ (symbolp (car keylist))
+ (listp (cadr keylist))
+ (not (numberp (posn-point
+ (event-start (cadr keylist) )))))
+ (pop unread-command-events)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; scrolling within Isearch mode. Alan Mackenzie (acm@muc.de), 2003/2/24
+;;
+;; The idea here is that certain vertical scrolling commands (like C-l
+;; `recenter') should be usable WITHIN Isearch mode. For a command to be
+;; suitable, it must NOT alter the buffer, swap to another buffer or frame,
+;; tamper with isearch's state, or move point. It is unacceptable for the
+;; search string to be scrolled out of the current window. If a command
+;; attempts this, we scroll the text back again.
+;;
+;; We implement this feature with a property called `isearch-scroll'.
+;; If a command's symbol has the value t for this property it is a
+;; scrolling command. The feature needs to be enabled by setting the
+;; customizable variable `isearch-allow-scroll' to a non-nil value.
+;;
+;; The universal argument commands (e.g. C-u) in simple.el are marked
+;; as scrolling commands, and isearch.el has been amended to allow
+;; prefix arguments to be passed through to scrolling commands. Thus
+;; M-0 C-l will scroll point to the top of the window.
+;;
+;; Horizontal scrolling commands are currently not catered for.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Set the isearch-scroll property on some standard functions:
+;; Scroll-bar functions:
+(if (fboundp 'scroll-bar-toolkit-scroll)
+ (put 'scroll-bar-toolkit-scroll 'isearch-scroll t))
+(if (fboundp 'mac-handle-scroll-bar-event)
+ (put 'mac-handle-scroll-bar-event 'isearch-scroll t))
+(if (fboundp 'w32-handle-scroll-bar-event)
+ (put 'w32-handle-scroll-bar-event 'isearch-scroll t))
+
+;; Commands which scroll the window:
+(put 'recenter 'isearch-scroll t)
+(put 'reposition-window 'isearch-scroll t)
+(put 'scroll-up 'isearch-scroll t)
+(put 'scroll-down 'isearch-scroll t)
+
+;; Commands which act on the other window
+(put 'list-buffers 'isearch-scroll t)
+(put 'scroll-other-window 'isearch-scroll t)
+(put 'scroll-other-window-down 'isearch-scroll t)
+(put 'beginning-of-buffer-other-window 'isearch-scroll t)
+(put 'end-of-buffer-other-window 'isearch-scroll t)
+
+;; Commands which change the window layout
+(put 'delete-other-windows 'isearch-scroll t)
+(put 'balance-windows 'isearch-scroll t)
+(put 'split-window-vertically 'isearch-scroll t)
+(put 'enlarge-window 'isearch-scroll t)
+
+;; Universal argument commands
+(put 'universal-argument 'isearch-scroll t)
+(put 'negative-argument 'isearch-scroll t)
+(put 'digit-argument 'isearch-scroll t)
+
+(defcustom isearch-allow-scroll nil
+ "If non-nil, scrolling commands are allowed during incremental search."
+ :type 'boolean
+ :group 'isearch)
+
+(defun isearch-string-out-of-window (isearch-point)
+ "Test whether the search string is currently outside of the window.
+Return nil if it's completely visible, or if point is visible,
+together with as much of the search string as will fit; the symbol
+`above' if we need to scroll the text downwards; the symbol `below',
+if upwards."
+ (let ((w-start (window-start))
+ (w-end (window-end nil t))
+ (w-L1 (save-excursion (move-to-window-line 1) (point)))
+ (w-L-1 (save-excursion (move-to-window-line -1) (point)))
+ start end) ; start and end of search string in buffer
+ (if isearch-forward
+ (setq end isearch-point start (or isearch-other-end isearch-point))
+ (setq start isearch-point end (or isearch-other-end isearch-point)))
+ (cond ((or (and (>= start w-start) (<= end w-end))
+ (if isearch-forward
+ (and (>= isearch-point w-L-1) (< isearch-point w-end)) ; point on Line -1
+ (and (>= isearch-point w-start) (< isearch-point w-L1)))) ; point on Line 0
+ nil)
+ ((and (< start w-start)
+ (< isearch-point w-L-1))
+ 'above)
+ (t 'below))))
+
+(defun isearch-back-into-window (above isearch-point)
+ "Scroll the window to bring the search string back into view.
+Restore point to ISEARCH-POINT in the process. ABOVE is t when the
+search string is above the top of the window, nil when it is beneath
+the bottom."
+ (let (start end)
+ (if isearch-forward
+ (setq end isearch-point start (or isearch-other-end isearch-point))
+ (setq start isearch-point end (or isearch-other-end isearch-point)))
+ (if above
+ (progn
+ (goto-char start)
+ (recenter 0)
+ (when (>= isearch-point (window-end nil t))
+ (goto-char isearch-point)
+ (recenter -1)))
+ (goto-char end)
+ (recenter -1)
+ (when (< isearch-point (window-start))
+ (goto-char isearch-point)
+ (recenter 0))))
+ (goto-char isearch-point))
+
+(defun isearch-reread-key-sequence-naturally (keylist)
+ "Reread key sequence KEYLIST with Isearch mode's keymap deactivated.
+Return the key sequence as a string/vector."
+ (isearch-unread-key-sequence keylist)
+ (let (overriding-terminal-local-map)
+ (read-key-sequence nil))) ; This will go through function-key-map, if nec.
+
+(defun isearch-lookup-scroll-key (key-seq)
+ "If KEY-SEQ is bound to a scrolling command, return it as a symbol.
+Otherwise return nil."
+ (let* ((overriding-terminal-local-map nil)
+ (binding (key-binding key-seq)))
+ (and binding (symbolp binding) (commandp binding)
+ (eq (get binding 'isearch-scroll) t)
+ binding)))
(defalias 'isearch-other-control-char 'isearch-other-meta-char)
-(defun isearch-other-meta-char ()
- "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)
- (let* ((key (this-command-keys))
+(defun isearch-other-meta-char (&optional arg)
+ "Process a miscellaneous key sequence in Isearch mode.
+
+Try to convert the current key-sequence to something usable in Isearch
+mode, either by converting it with `function-key-map', downcasing a
+key with C-<upper case>, or finding a \"scrolling command\" bound to
+it. \(In the last case, we may have to read more events.) If so,
+either unread the converted sequence or execute the command.
+
+Otherwise, if `search-exit-option' is non-nil (the default) unread the
+key-sequence and exit the search normally. 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.
+
+ARG is the prefix argument. It will be transmitted through to the
+scrolling command or to the command whose key-sequence exits
+Isearch mode."
+ (interactive "P")
+ (let* ((key (if current-prefix-arg ; not nec the same as ARG
+ (substring (this-command-keys) universal-argument-num-events)
+ (this-command-keys)))
(main-event (aref key 0))
- (keylist (listify-key-sequence key)))
+ (keylist (listify-key-sequence key))
+ scroll-command isearch-point)
(cond ((and (= (length key) 1)
(let ((lookup (lookup-key function-key-map key)))
(not (or (null lookup) (integerp lookup)
((eq search-exit-option 'edit)
(apply 'isearch-unread keylist)
(isearch-edit-string))
+ ;; Handle a scrolling function.
+ ((and isearch-allow-scroll
+ (progn (setq key (isearch-reread-key-sequence-naturally keylist))
+ (setq keylist (listify-key-sequence key))
+ (setq main-event (aref key 0))
+ (setq scroll-command (isearch-lookup-scroll-key key))))
+ ;; From this point onwards, KEY, KEYLIST and MAIN-EVENT hold a
+ ;; complete key sequence, possibly as modified by function-key-map,
+ ;; not merely the one or two event fragment which invoked
+ ;; isearch-other-meta-char in the first place.
+ (setq isearch-point (point))
+ (setq prefix-arg arg)
+ (command-execute scroll-command)
+ (let ((ab-bel (isearch-string-out-of-window isearch-point)))
+ (if ab-bel
+ (isearch-back-into-window (eq ab-bel 'above) isearch-point)))
+ (isearch-update))
(search-exit-option
(let (window)
- (cancel-kbd-macro-events)
- (apply 'isearch-unread keylist)
-
- ;; Properly handle scroll-bar and mode-line clicks for
- ;; which a dummy prefix event was generated as (aref key
- ;; 0). Note that we don't have to modify the event
- ;; anymore in 21 because read_key_sequence no longer modifies
- ;; events to produce fake prefix keys.
- (when (and (> (length key) 1)
- (symbolp (aref key 0))
- (listp (aref key 1))
- (not (numberp (posn-point
- (event-start (aref key 1))))))
- (pop unread-command-events)
- (setq main-event (car unread-command-events)))
+ (isearch-unread-key-sequence keylist)
+ (setq main-event (car unread-command-events))
;; If we got a mouse click event, that event contains the
;; window clicked on. maybe it was read with the buffer
;; obviously wrong for the case that a down-mouse event
;; on another window invokes this function. The event
;; will contain the window clicked on and that window's
- ;; buffer is certainaly not always in Isearch mode.
+ ;; buffer is certainly not always in Isearch mode.
;;
;; Leave the code in, but check for current buffer not
;; being in Isearch mode for now, until someone tells
(isearch-done)
(isearch-clean-overlays))
(isearch-done)
- (isearch-clean-overlays))))
- (t;; otherwise nil
+ (isearch-clean-overlays)
+ (setq prefix-arg arg))))
+ (t;; otherwise nil
(isearch-process-search-string key key)))))
(defun isearch-quote-char ()
"Match all whitespace chars, if in regexp mode.
If you want to search for just a space, type \\<isearch-mode-map>\\[isearch-quote-char] SPC."
(interactive)
- (if isearch-regexp
+ (if isearch-regexp
(if (and search-whitespace-regexp (not isearch-within-brackets)
(not isearch-invalid-regexp))
(isearch-process-search-string search-whitespace-regexp " ")
(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)
+ (isearch-process-search-string
+ (char-to-string char)
(if (>= char ?\200)
(char-to-string char)
(isearch-text-char-description char))))
;; 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)))
+ (completion (try-completion isearch-string ring)))
(cond
((eq completion t)
;; isearch-string stays the same
(progn
(if completion-auto-help
(with-output-to-temp-buffer "*Isearch completions*"
- (display-completion-list
- (all-completions isearch-string alist))))
+ (display-completion-list
+ (all-completions isearch-string ring))))
t)
(and completion
(setq isearch-string completion))))
If there is no completion possible, say so and continue searching."
(interactive)
(if (isearch-complete1)
- (isearch-edit-string)
+ (progn (setq isearch-message
+ (mapconcat 'isearch-text-char-description
+ isearch-string ""))
+ (isearch-edit-string))
;; else
(sit-for 1)
(isearch-update)))
(defun isearch-complete-edit ()
"Same as `isearch-complete' except in the minibuffer."
(interactive)
- (setq isearch-string (buffer-string))
+ (setq isearch-string (field-string))
(if (isearch-complete1)
(progn
(delete-field)
(isearch-top-state))
(defun isearch-push-state ()
- (setq isearch-cmds
+ (setq isearch-cmds
(cons (list isearch-string isearch-message (point)
- isearch-success isearch-forward isearch-other-end
+ isearch-success isearch-forward isearch-other-end
isearch-word
isearch-invalid-regexp isearch-wrapped isearch-barrier
isearch-within-brackets isearch-case-fold-search)
(concat " [" current-input-method-title "]: ")
": ")
)))
- (concat (upcase (substring m 0 1)) (substring m 1))))
-
+ (propertize (concat (upcase (substring m 0 1)) (substring m 1))
+ 'face 'minibuffer-prompt)))
(defun isearch-message-suffix (&optional c-q-hack ellipsis)
(concat (if c-q-hack "^Q" "")
"")))
\f
-;;; Searching
+;; Searching
+
+(defvar isearch-search-fun-function nil "Override `isearch-function-fun'.")
+
+(defun isearch-search-fun ()
+ "Return the function to use for the search.
+Can be changed via `isearch-search-fun-function' for special needs."
+ (if isearch-search-fun-function
+ (funcall isearch-search-fun-function)
+ (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)))))
(defun isearch-search ()
;; Do the search with the current search string.
(while retry
(setq isearch-success
(funcall
- (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-search-fun)
isearch-string nil t))
;; Clear RETRY unless we matched some invisible text
;; and we aren't supposed to do that.
(quit (isearch-unread ?\C-g)
(setq isearch-success nil))
- (invalid-regexp
+ (invalid-regexp
(setq isearch-invalid-regexp (car (cdr lossage)))
(setq isearch-within-brackets (string-match "\\`Unmatched \\["
isearch-invalid-regexp))
(goto-char (nth 2 (car isearch-cmds)))))
-;;; Called when opening an overlay, and we are still in isearch.
+;; Called when opening an overlay, and we are still in isearch.
(defun isearch-open-overlay-temporary (ov)
- (if (not (null (overlay-get ov 'isearch-open-invisible-temporary)))
+ (if (not (null (overlay-get ov 'isearch-open-invisible-temporary)))
;; Some modes would want to open the overlays temporary during
;; isearch in their own way, they should set the
;; `isearch-open-invisible-temporary' to a function doing this.
(overlay-put ov 'intangible nil)))
-;;; This is called at the end of isearch. It will open the overlays
-;;; that contain the latest match. Obviously in case of a C-g the
-;;; point returns to the original location which surely is not contain
-;;; in any of these overlays, se we are safe in this case too.
+;; This is called at the end of isearch. It will open the overlays
+;; that contain the latest match. Obviously in case of a C-g the
+;; point returns to the original location which surely is not contain
+;; in any of these overlays, se we are safe in this case too.
(defun isearch-open-necessary-overlays (ov)
- (let ((inside-overlay (and (> (point) (overlay-start ov))
+ (let ((inside-overlay (and (> (point) (overlay-start ov))
(< (point) (overlay-end ov))))
;; If this exists it means that the overlay was opened using
;; this function, not by us tweaking the overlay properties.
(if fct-temp
(funcall fct-temp ov t)))))
-;;; This is called when exiting isearch. It closes the temporary
-;;; opened overlays, except the ones that contain the latest match.
+;; This is called when exiting isearch. It closes the temporary
+;; opened overlays, except the ones that contain the latest match.
(defun isearch-clean-overlays ()
(when isearch-opened-overlays
(mapc 'isearch-open-necessary-overlays isearch-opened-overlays)
(and (> end1 start0) (<= end1 end0))))
-;;; Verify if the current match is outside of each element of
-;;; `isearch-opened-overlays', if so close that overlay.
+;; Verify if the current match is outside of each element of
+;; `isearch-opened-overlays', if so close that overlay.
(defun isearch-close-unnecessary-overlays (begin end)
(let ((overlays isearch-opened-overlays))
(defun isearch-range-invisible (beg end)
"Return t if all the text from BEG to END is invisible."
- (and (/= beg end)
- ;; Check that invisibility runs up to END.
- (save-excursion
- (goto-char beg)
- (let (
- ;; can-be-opened keeps track if we can open some overlays.
- (can-be-opened (eq search-invisible 'open))
- ;; the list of overlays that could be opened
- (crt-overlays nil))
- (when (and can-be-opened isearch-hide-immediately)
- (isearch-close-unnecessary-overlays beg end))
- ;; If the following character is currently invisible,
- ;; skip all characters with that same `invisible' property value.
- ;; Do that over and over.
- (while (and (< (point) end)
- (let ((prop
- (get-char-property (point) 'invisible)))
- (if (eq buffer-invisibility-spec t)
- prop
- (or (memq prop buffer-invisibility-spec)
- (assq prop buffer-invisibility-spec)))))
- (if (get-text-property (point) 'invisible)
- (progn
- (goto-char (next-single-property-change (point) 'invisible
- nil end))
- ;; if text is hidden by an `invisible' text property
- ;; we cannot open it at all.
- (setq can-be-opened nil))
- (unless (null can-be-opened)
- (let ((overlays (overlays-at (point)))
- ov-list
- o
- invis-prop)
- (while overlays
- (setq o (car overlays)
- invis-prop (overlay-get o 'invisible))
- (if (if (eq buffer-invisibility-spec t)
- invis-prop
- (or (memq invis-prop buffer-invisibility-spec)
- (assq invis-prop buffer-invisibility-spec)))
- (if (overlay-get o 'isearch-open-invisible)
- (setq ov-list (cons o ov-list))
- ;; We found one overlay that cannot be
- ;; opened, that means the whole chunk
- ;; cannot be opened.
- (setq can-be-opened nil)))
- (setq overlays (cdr overlays)))
- (if can-be-opened
- ;; It makes sense to append to the open
- ;; overlays list only if we know that this is
- ;; t.
- (setq crt-overlays (append ov-list crt-overlays)))))
- (goto-char (next-overlay-change (point)))))
- ;; See if invisibility reaches up thru END.
- (if (>= (point) end)
- (if (and (not (null can-be-opened)) (consp crt-overlays))
- (progn
- (setq isearch-opened-overlays
- (append isearch-opened-overlays crt-overlays))
- (mapc 'isearch-open-overlay-temporary crt-overlays)
- nil)
- t))))))
+ (when (/= beg end)
+ ;; Check that invisibility runs up to END.
+ (save-excursion
+ (goto-char beg)
+ (let (;; can-be-opened keeps track if we can open some overlays.
+ (can-be-opened (eq search-invisible 'open))
+ ;; the list of overlays that could be opened
+ (crt-overlays nil))
+ (when (and can-be-opened isearch-hide-immediately)
+ (isearch-close-unnecessary-overlays beg end))
+ ;; If the following character is currently invisible,
+ ;; skip all characters with that same `invisible' property value.
+ ;; Do that over and over.
+ (while (and (< (point) end)
+ (let ((prop
+ (get-char-property (point) 'invisible)))
+ (if (eq buffer-invisibility-spec t)
+ prop
+ (or (memq prop buffer-invisibility-spec)
+ (assq prop buffer-invisibility-spec)))))
+ (if (get-text-property (point) 'invisible)
+ (progn
+ (goto-char (next-single-property-change (point) 'invisible
+ nil end))
+ ;; if text is hidden by an `invisible' text property
+ ;; we cannot open it at all.
+ (setq can-be-opened nil))
+ (when can-be-opened
+ (let ((overlays (overlays-at (point)))
+ ov-list
+ o
+ invis-prop)
+ (while overlays
+ (setq o (car overlays)
+ invis-prop (overlay-get o 'invisible))
+ (if (if (eq buffer-invisibility-spec t)
+ invis-prop
+ (or (memq invis-prop buffer-invisibility-spec)
+ (assq invis-prop buffer-invisibility-spec)))
+ (if (overlay-get o 'isearch-open-invisible)
+ (setq ov-list (cons o ov-list))
+ ;; We found one overlay that cannot be
+ ;; opened, that means the whole chunk
+ ;; cannot be opened.
+ (setq can-be-opened nil)))
+ (setq overlays (cdr overlays)))
+ (if can-be-opened
+ ;; It makes sense to append to the open
+ ;; overlays list only if we know that this is
+ ;; t.
+ (setq crt-overlays (append ov-list crt-overlays)))))
+ (goto-char (next-overlay-change (point)))))
+ ;; See if invisibility reaches up thru END.
+ (if (>= (point) end)
+ (if (and can-be-opened (consp crt-overlays))
+ (progn
+ (setq isearch-opened-overlays
+ (append isearch-opened-overlays crt-overlays))
+ (mapc 'isearch-open-overlay-temporary crt-overlays)
+ nil)
+ (setq isearch-hidden t)))))))
\f
-;;; Highlighting
+;; Highlighting
(defvar isearch-overlay nil)
(delete-overlay isearch-overlay)))
-;;; General utilities
+;; 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 preceded by `\\' (but not `\\\\')
since they have special meaning in a regexp."
- (let (quote-flag (i 0) (len (length string)) found)
+ (let (quote-flag (i 0) (len (length string)) found)
(while (and (not found) (< i len))
(let ((char (aref string i)))
(if (and regexp-flag (eq char ?\\))
(setq quote-flag (not quote-flag))
(if (and (not quote-flag) (not (eq char (downcase char))))
- (setq found t))))
+ (setq found t))
+ (setq quote-flag nil)))
(setq i (1+ i)))
(not found)))
(append char-or-events unread-command-events)))
\f
-;;; isearch-lazy-highlight feature
-;;; by Bob Glickstein <http://www.zanshin.com/~bobg/>
-
-;;; When active, *every* match for the current search string is
-;;; highlighted: the current one using the normal isearch match color
-;;; and all the others using `isearch-lazy-highlight-face'. The extra
-;;; highlighting makes it easier to anticipate where the cursor will
-;;; land each time you press C-s or C-r to repeat a pending search.
-;;; Highlighting of these additional matches happens in a deferred
-;;; fashion using "idle timers," so the cycles needed do not rob
-;;; isearch of its usual snappy response.
-
-;;; IMPLEMENTATION NOTE: This depends on some isearch internals.
-;;; Specifically:
-;;; - `isearch-update' is expected to be called (at least) every time
-;;; the search string or window-start changes;
-;;; - `isearch-string' is expected to contain the current search
-;;; string as entered by the user;
-;;; - the type of the current search is expected to be given by
-;;; `isearch-word' and `isearch-regexp';
-;;; - the direction of the current search is expected to be given by
-;;; `isearch-forward';
-;;; - the variable `isearch-invalid-regexp' is expected to be true
-;;; iff `isearch-string' is an invalid regexp.
-
-(require 'timer)
+;; isearch-lazy-highlight feature
+;; by Bob Glickstein <http://www.zanshin.com/~bobg/>
+
+;; When active, *every* match for the current search string is
+;; highlighted: the current one using the normal isearch match color
+;; and all the others using `isearch-lazy-highlight-face'. The extra
+;; highlighting makes it easier to anticipate where the cursor will
+;; land each time you press C-s or C-r to repeat a pending search.
+;; Highlighting of these additional matches happens in a deferred
+;; fashion using "idle timers," so the cycles needed do not rob
+;; isearch of its usual snappy response.
+
+;; IMPLEMENTATION NOTE: This depends on some isearch internals.
+;; Specifically:
+;; - `isearch-update' is expected to be called (at least) every time
+;; the search string or window-start changes;
+;; - `isearch-string' is expected to contain the current search
+;; string as entered by the user;
+;; - the type of the current search is expected to be given by
+;; `isearch-word' and `isearch-regexp';
+;; - the direction of the current search is expected to be given by
+;; `isearch-forward';
+;; - the variable `isearch-invalid-regexp' is expected to be true
+;; iff `isearch-string' is an invalid regexp.
(defgroup isearch-lazy-highlight nil
"Lazy highlighting feature for incremental search."
:group 'isearch)
(defface isearch
- '((((type tty pc) (class color))
- (:background "magenta4" :foreground "cyan1"))
- (((class color) (background light))
+ '((((class color) (min-colors 88) (background light))
;; The background must not be too dark, for that means
;; the character is hard to see when the cursor is there.
(:background "magenta2" :foreground "lightskyblue1"))
- (((class color) (background dark))
+ (((class color) (min-colors 88) (background dark))
(:background "palevioletred2" :foreground "brown4"))
+ (((class color) (min-colors 16))
+ (:background "magenta4" :foreground "cyan1"))
+ (((class color) (min-colors 8))
+ (:background "magenta4" :foreground "cyan1"))
(t (:inverse-video t)))
"Face for highlighting Isearch matches."
:group 'isearch-faces)
(defvar isearch 'isearch)
(defface isearch-lazy-highlight-face
- '((((type tty pc) (class color))
- (:background "turquoise3"))
- (((class color) (background light))
+ '((((class color) (min-colors 88) (background light))
(:background "paleturquoise"))
- (((class color) (background dark))
+ (((class color) (min-colors 88) (background dark))
(:background "paleturquoise4"))
+ (((class color) (min-colors 16))
+ (:background "turquoise3"))
+ (((class color) (min-colors 8))
+ (:background "turquoise3"))
(t (:underline t)))
"Face for lazy highlighting of Isearch matches other than the current one."
:group 'isearch-faces)
(defvar isearch-lazy-highlight-last-string nil)
(defvar isearch-lazy-highlight-window nil)
(defvar isearch-lazy-highlight-window-start nil)
+(defvar isearch-lazy-highlight-window-end nil)
(defvar isearch-lazy-highlight-case-fold-search nil)
(defvar isearch-lazy-highlight-regexp nil)
(not (eq isearch-lazy-highlight-regexp
isearch-regexp))
(not (= (window-start)
- isearch-lazy-highlight-window-start))))
+ isearch-lazy-highlight-window-start))
+ (not (= (window-end) ; Window may have been split/joined.
+ isearch-lazy-highlight-window-end))))
;; something important did indeed change
(isearch-lazy-highlight-cleanup t) ;kill old loop & remove overlays
(when (not isearch-invalid-regexp)
(setq isearch-lazy-highlight-window (selected-window)
isearch-lazy-highlight-window-start (window-start)
+ isearch-lazy-highlight-window-end (window-end)
isearch-lazy-highlight-start (point)
isearch-lazy-highlight-end (point)
isearch-lazy-highlight-last-string isearch-string
(defun isearch-lazy-highlight-search ()
"Search ahead for the next or previous match, for lazy highlighting.
Attempt to do the search exactly the way the pending isearch would."
- (let ((case-fold-search isearch-case-fold-search)
- (choices (cond (isearch-word
- '(word-search-forward . word-search-backward))
- (isearch-regexp
- '(re-search-forward . re-search-backward))
- (t
- '(search-forward . search-backward)))))
- (funcall (if isearch-forward
- (car choices)
- (cdr choices))
+ (let ((case-fold-search isearch-case-fold-search))
+ (funcall (isearch-search-fun)
isearch-string
(if isearch-forward
(if isearch-lazy-highlight-wrapped
isearch-message message
isearch-case-fold-search case-fold)
(isearch-search))
-
+
+;;; arch-tag: 74850515-f7d8-43a6-8a2c-ca90a4c1e675
;;; isearch.el ends here