X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/41306318777a942420bc4feadbfacf662ea179dc..3fbc3eff379c61aa301dc5dbd14f6f77b6a103f5:/lisp/isearch.el diff --git a/lisp/isearch.el b/lisp/isearch.el index 131ab5893d..20dabdc5b6 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -1,9 +1,9 @@ ;;; isearch.el --- incremental search minor mode -;; Copyright (C) 1992-1997, 1999-2013 Free Software Foundation, Inc. +;; Copyright (C) 1992-1997, 1999-2014 Free Software Foundation, Inc. ;; Author: Daniel LaLiberte -;; Maintainer: FSF +;; Maintainer: emacs-devel@gnu.org ;; Keywords: matching ;; Package: emacs @@ -131,12 +131,18 @@ a tab, a carriage return (control-M), a newline, and `]+'." :version "24.3") (defcustom search-invisible 'open - "If t incremental search can match hidden text. + "If t incremental search/query-replace can match hidden text. A nil value means don't match invisible text. When 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'.) + +To temporarily change the value for an active incremental search, +use \\\\[isearch-toggle-invisible]. + +See also the related option `isearch-hide-immediately'. + 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) @@ -147,9 +153,9 @@ whenever point is in one of them." (defcustom isearch-hide-immediately t "If non-nil, re-hide an invisible match right away. This variable makes a difference when `search-invisible' is set to `open'. -It means that after search makes some invisible text visible -to show the match, it makes the text invisible again when the match moves. -Ordinarily the text becomes invisible again at the end of the search." +If nil then do not re-hide opened invisible text when the match moves. +Whatever the value, all opened invisible text is hidden again after exiting +the search." :type 'boolean :group 'isearch) @@ -188,7 +194,7 @@ or to the end of the buffer for a backward search.") to the search status stack.") (defvar isearch-filter-predicate #'isearch-filter-visible - "Predicate that filter the search hits that would normally be available. + "Predicate that filters the search hits that would normally be available. Search hits that dissatisfy the predicate are skipped. The function has two arguments: the positions of start and end of text matched by the search. If this function returns nil, continue searching without @@ -349,7 +355,6 @@ A value of nil means highlight all matches." (defvar isearch-help-map (let ((map (make-sparse-keymap))) - (define-key map [t] 'isearch-other-control-char) (define-key map (char-to-string help-char) 'isearch-help-for-help) (define-key map [help] 'isearch-help-for-help) (define-key map [f1] 'isearch-help-for-help) @@ -423,9 +428,6 @@ This is like `describe-bindings', but displays only Isearch keys." ;; Make all multibyte characters search for themselves. (set-char-table-range (nth 1 map) (cons #x100 (max-char)) 'isearch-printing-char) - ;; Make function keys, etc, which aren't bound to a scrolling-function - ;; exit the search. - (define-key map [t] 'isearch-other-control-char) ;; Single-byte printing chars extend the search string by default. (setq i ?\s) @@ -439,9 +441,7 @@ This is like `describe-bindings', but displays only Isearch keys." ;; 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 meta-map [t] 'isearch-other-meta-char)) + (define-key map (char-to-string meta-prefix-char) meta-map)) ;; Several non-printing chars change the searching behavior. (define-key map "\C-s" 'isearch-repeat-forward) @@ -452,17 +452,18 @@ This is like `describe-bindings', but displays only Isearch keys." (define-key map "\M-\C-s" 'isearch-repeat-forward) (define-key map "\M-\C-r" 'isearch-repeat-backward) (define-key map "\177" 'isearch-delete-char) + (define-key map [backspace] 'isearch-delete-char) (define-key map "\C-g" 'isearch-abort) ;; This assumes \e is the meta-prefix-char. (or (= ?\e meta-prefix-char) (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 [return] 'isearch-exit) (define-key map "\C-j" 'isearch-printing-char) (define-key map "\t" 'isearch-printing-char) (define-key map [?\S-\ ] 'isearch-printing-char) @@ -507,6 +508,11 @@ This is like `describe-bindings', but displays only Isearch keys." (define-key map "\M-r" 'isearch-toggle-regexp) (define-key map "\M-e" 'isearch-edit-string) + (put 'isearch-toggle-case-fold :advertised-binding "\M-sc") + (put 'isearch-toggle-regexp :advertised-binding "\M-sr") + (put 'isearch-edit-string :advertised-binding "\M-se") + + (define-key map "\M-se" 'isearch-edit-string) (define-key map "\M-sc" 'isearch-toggle-case-fold) (define-key map "\M-si" 'isearch-toggle-invisible) (define-key map "\M-sr" 'isearch-toggle-regexp) @@ -521,9 +527,6 @@ This is like `describe-bindings', but displays only Isearch keys." ;; The key translations defined in the C-x 8 prefix should add ;; characters to the search string. See iso-transl.el. - (define-key map "\C-x" nil) - (define-key map [?\C-x t] 'isearch-other-control-char) - (define-key map "\C-x8" nil) (define-key map "\C-x8\r" 'isearch-char-by-name) map) @@ -572,8 +575,8 @@ matches literally, against one space. You can toggle the value of this variable by the command `isearch-toggle-lax-whitespace'.") (defvar isearch-cmds nil - "Stack of search status sets. -Each set is a vector of the form: + "Stack of search status elements. +Each element is an `isearch--state' struct where the slots are [STRING MESSAGE POINT SUCCESS FORWARD OTHER-END WORD INVALID-REGEXP WRAPPED BARRIER WITHIN-BRACKETS CASE-FOLD-SEARCH]") @@ -645,6 +648,8 @@ Each set is a vector of the form: ;; isearch is invoked. (defvar isearch-input-method-local-p nil) +(defvar isearch--saved-overriding-local-map nil) + ;; Minor-mode-alist changes - kind of redundant with the ;; echo area, but if isearching in multiple windows, it can be useful. @@ -912,6 +917,9 @@ convert the search string to a regexp used by regexp search functions." (setq overriding-terminal-local-map isearch-mode-map) (run-hooks 'isearch-mode-hook) + ;; Remember the initial map possibly modified + ;; by external packages in isearch-mode-hook. (Bug#16035) + (setq isearch--saved-overriding-local-map overriding-terminal-local-map) ;; Pushing the initial state used to be before running isearch-mode-hook, ;; but a hook might set `isearch-push-state-function' used in @@ -920,6 +928,8 @@ convert the search string to a regexp used by regexp search functions." (isearch-update) + (add-hook 'pre-command-hook 'isearch-pre-command-hook) + (add-hook 'post-command-hook 'isearch-post-command-hook) (add-hook 'mouse-leave-buffer-hook 'isearch-done) (add-hook 'kbd-macro-termination-hook 'isearch-done) @@ -998,6 +1008,8 @@ NOPUSH is t and EDIT is t." (unless (equal (car command-history) command) (setq command-history (cons command command-history))))) + (remove-hook 'pre-command-hook 'isearch-pre-command-hook) + (remove-hook 'post-command-hook 'isearch-post-command-hook) (remove-hook 'mouse-leave-buffer-hook 'isearch-done) (remove-hook 'kbd-macro-termination-hook 'isearch-done) (setq isearch-lazy-highlight-start nil) @@ -1147,8 +1159,6 @@ nonincremental search instead via `isearch-edit-string'." (isearch-done) (isearch-clean-overlays)) -(defvar minibuffer-history-symbol) ;; from external package gmhist.el - (defun isearch-fail-pos (&optional msg) "Return position of first mismatch in search string, or nil if none. If MSG is non-nil, use variable `isearch-message', otherwise `isearch-string'." @@ -1301,6 +1311,8 @@ You can update the global isearch variables by setting new values to (isearch-abort) ;; outside of let to restore outside global values ))) +(defvar minibuffer-history-symbol) ;; from external package gmhist.el + (defun isearch-edit-string () "Edit the search string in the minibuffer. The following additional command keys are active while editing. @@ -1668,10 +1680,11 @@ the beginning or the end of the string need not match a symbol boundary." (re-search-backward regexp bound noerror count))) -(defun isearch-query-replace (&optional delimited regexp-flag) +(defun isearch-query-replace (&optional arg regexp-flag) "Start `query-replace' with string to replace from last search string. -The arg DELIMITED (prefix arg if interactive), if non-nil, means replace -only matches surrounded by word boundaries. Note that using the prefix arg +The ARG (prefix arg if interactive), if non-nil, means replace +only matches surrounded by word boundaries. A negative prefix +arg means replace backward. Note that using the prefix arg is possible only when `isearch-allow-scroll' is non-nil or `isearch-allow-prefix' is non-nil, and it doesn't always provide the correct matches for `query-replace', so the preferred way to run word @@ -1689,6 +1702,8 @@ replacements from Isearch is `M-s w ... M-%'." isearch-lax-whitespace) (replace-regexp-lax-whitespace isearch-regexp-lax-whitespace) + (delimited (and arg (not (eq arg '-)))) + (backward (and arg (eq arg '-))) ;; Set `isearch-recursive-edit' to nil to prevent calling ;; `exit-recursive-edit' in `isearch-done' that terminates ;; the execution of this command when it is non-nil. @@ -1697,9 +1712,13 @@ replacements from Isearch is `M-s w ... M-%'." (isearch-done nil t) (isearch-clean-overlays) (if (and isearch-other-end - (< isearch-other-end (point)) + (if backward + (> isearch-other-end (point)) + (< isearch-other-end (point))) (not (and transient-mark-mode mark-active - (< (mark) (point))))) + (if backward + (> (mark) (point)) + (< (mark) (point)))))) (goto-char isearch-other-end)) (set query-replace-from-history-variable (cons isearch-string @@ -1719,19 +1738,21 @@ replacements from Isearch is `M-s w ... M-%'." " word")) "") (if isearch-regexp " regexp" "") + (if backward " backward" "") (if (and transient-mark-mode mark-active) " in region" "")) isearch-regexp) t isearch-regexp (or delimited isearch-word) nil nil (if (and transient-mark-mode mark-active) (region-beginning)) - (if (and transient-mark-mode mark-active) (region-end)))) + (if (and transient-mark-mode mark-active) (region-end)) + backward)) (and isearch-recursive-edit (exit-recursive-edit))) -(defun isearch-query-replace-regexp (&optional delimited) +(defun isearch-query-replace-regexp (&optional arg) "Start `query-replace-regexp' with string to replace from last search string. See `isearch-query-replace' for more information." (interactive (list current-prefix-arg)) - (isearch-query-replace delimited t)) + (isearch-query-replace arg t)) (defun isearch-occur (regexp &optional nlines) "Run `occur' using the last search string as the regexp. @@ -1933,7 +1954,8 @@ or it might return the position of the end of the line." (forward-char arg))) (defun isearch-yank-char (&optional arg) - "Pull next character from buffer into search string." + "Pull next character from buffer into search string. +If optional ARG is non-nil, pull in the next ARG characters." (interactive "p") (isearch-yank-internal (lambda () (forward-char arg) (point)))) @@ -1952,12 +1974,14 @@ Subword is used when `subword-mode' is activated. " (forward-char 1)) (point)))) (defun isearch-yank-word (&optional arg) - "Pull next word from buffer into search string." + "Pull next word from buffer into search string. +If optional ARG is non-nil, pull in the next ARG words." (interactive "p") (isearch-yank-internal (lambda () (forward-word arg) (point)))) (defun isearch-yank-line (&optional arg) - "Pull rest of line from buffer into search string." + "Pull rest of line from buffer into search string. +If optional ARG is non-nil, yank the next ARG lines." (interactive "p") (isearch-yank-internal (lambda () (let ((inhibit-field-text-motion t)) @@ -2100,26 +2124,6 @@ to the barrier." (min last-other-end isearch-barrier))) (setq isearch-adjusted t))))))) -(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 ;; @@ -2244,204 +2248,68 @@ the bottom." (recenter 0)))) (goto-char isearch-point)) -(defun isearch-reread-key-sequence-naturally (keylist) - "Reread key sequence KEYLIST with an inactive Isearch-mode keymap. -Return the key sequence as a string/vector." - (isearch-unread-key-sequence keylist) - (let (overriding-terminal-local-map) - ;; This will go through function-key-map, if nec. - ;; The arg DONT-DOWNCASE-LAST prevents premature shift-translation. - (read-key-sequence nil nil t))) - -(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) - (or (eq (get binding 'isearch-scroll) t) - (eq (get binding 'scroll-command) t)) - binding))) - -(defalias 'isearch-other-control-char 'isearch-other-meta-char) - -(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-, 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)) - scroll-command isearch-point) - (cond ((and (= (length key) 1) - (let ((lookup (lookup-key local-function-key-map key))) - (not (or (null lookup) (integerp lookup) - (keymapp lookup))))) - ;; Handle a function key that translates into something else. - ;; If the key has a global definition too, - ;; exit and unread the key itself, so its global definition runs. - ;; Otherwise, unread the translation, - ;; so that the translated key takes effect within isearch. - (cancel-kbd-macro-events) - (if (lookup-key global-map key) - (progn - (isearch-done) - (setq prefix-arg arg) - (apply 'isearch-unread keylist)) - (setq keylist - (listify-key-sequence - (lookup-key local-function-key-map key))) - (while keylist - (setq key (car keylist)) - ;; Handle an undefined shifted printing character - ;; by downshifting it if that makes it printing. - ;; (As read-key-sequence would normally do, - ;; if we didn't have a default definition.) - (if (and (integerp key) - (memq 'shift (event-modifiers key)) - (>= key (+ ?\s (- ?\S-a ?a))) - (/= key (+ 127 (- ?\S-a ?a))) - (< key (+ 256 (- ?\S-a ?a)))) - (setq key (- key (- ?\S-a ?a)))) - ;; If KEY is a printing char, we handle it here - ;; directly to avoid the input method and keyboard - ;; coding system translating it. - (if (and (integerp key) - (>= key ?\s) (/= key 127) (< key 256)) - (progn - ;; Ensure that the processed char is recorded in - ;; the keyboard macro, if any (Bug#4894) - (store-kbd-macro-event key) - (isearch-process-search-char key) - (setq keylist (cdr keylist))) - ;; As the remaining keys in KEYLIST can't be handled - ;; here, we must reread them. - (setq prefix-arg arg) - (apply 'isearch-unread keylist) - (setq keylist nil))))) - ( - ;; Handle an undefined shifted control character - ;; by downshifting it if that makes it defined. - ;; (As read-key-sequence would normally do, - ;; if we didn't have a default definition.) - (let ((mods (event-modifiers main-event))) - (and (integerp main-event) - (memq 'shift mods) - (memq 'control mods) - (not (memq (lookup-key isearch-mode-map - (let ((copy (copy-sequence key))) - (aset copy 0 - (- main-event - (- ?\C-\S-a ?\C-a))) - copy) - nil) - '(nil - isearch-other-control-char))))) - (setcar keylist (- main-event (- ?\C-\S-a ?\C-a))) - (cancel-kbd-macro-events) - (setq prefix-arg arg) - (apply 'isearch-unread keylist)) - ((eq search-exit-option 'edit) - (setq prefix-arg arg) - (apply 'isearch-unread keylist) - (isearch-edit-string)) - ;; Handle a scrolling function or prefix argument. - ((progn - (setq key (isearch-reread-key-sequence-naturally keylist) - keylist (listify-key-sequence key) - main-event (aref key 0)) - (or (and isearch-allow-scroll - (setq scroll-command (isearch-lookup-scroll-key key))) - (and isearch-allow-prefix - (let (overriding-terminal-local-map) - (setq scroll-command (key-binding key)) - (memq scroll-command - '(universal-argument - negative-argument digit-argument)))))) - ;; 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) - (goto-char isearch-point))) - (isearch-update)) - ;; A mouse click on the isearch message starts editing the search string - ((and (eq (car-safe main-event) 'down-mouse-1) - (window-minibuffer-p (posn-window (event-start main-event)))) - ;; Swallow the up-event. - (read-event) - (isearch-edit-string)) - (search-exit-option - (let (window) - (setq prefix-arg arg) - (isearch-unread-key-sequence keylist) - (setq main-event (car unread-command-events)) - - ;; Don't store special commands in the keyboard macro. - (let (overriding-terminal-local-map) - (when (memq (key-binding key) - '(kmacro-start-macro - kmacro-end-macro kmacro-end-and-call-macro)) - (cancel-kbd-macro-events))) - - ;; If we got a mouse click event, that event contains the - ;; window clicked on. 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. - - ;; ??? I have no idea what this if checks for, but it's - ;; 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 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 - ;; what it's really supposed to do. - ;; - ;; --gerd 2001-08-10. - - (if (and (not isearch-mode) - (listp main-event) - (setq window (posn-window (event-start main-event))) - (windowp window) - (or (> (minibuffer-depth) 0) - (not (window-minibuffer-p window)))) - (with-current-buffer (window-buffer window) - (isearch-done) - (isearch-clean-overlays)) - (isearch-done) - (isearch-clean-overlays) - (setq prefix-arg arg)))) - (t;; otherwise nil - (isearch-process-search-string key key))))) +(defvar isearch-pre-scroll-point nil) + +(defun isearch-pre-command-hook () + "Decide whether to exit Isearch mode before executing the command. +Don't exit Isearch if the key sequence that invoked this command +is bound in `isearch-mode-map', or if the invoked command is +a prefix argument command (when `isearch-allow-prefix' is non-nil), +or it is a scrolling command (when `isearch-allow-scroll' is non-nil). +Otherwise, exit Isearch (when `search-exit-option' is non-nil) +before the command is executed globally with terminated Isearch." + (let* ((key (this-single-command-keys)) + (main-event (aref key 0))) + (cond + ;; Don't exit Isearch if we're in the middle of some + ;; `set-transient-map' thingy like `universal-argument--mode'. + ((not (eq overriding-terminal-local-map isearch--saved-overriding-local-map))) + ;; Don't exit Isearch for isearch key bindings. + ((commandp (lookup-key isearch-mode-map key nil))) + ;; Optionally edit the search string instead of exiting. + ((eq search-exit-option 'edit) + (setq this-command 'isearch-edit-string)) + ;; Handle a scrolling function or prefix argument. + ((or (and isearch-allow-prefix + (memq this-command '(universal-argument + digit-argument negative-argument))) + (and isearch-allow-scroll + (symbolp this-command) + (or (eq (get this-command 'isearch-scroll) t) + (eq (get this-command 'scroll-command) t)))) + (when isearch-allow-scroll + (setq isearch-pre-scroll-point (point)))) + ;; A mouse click on the isearch message starts editing the search string. + ((and (eq (car-safe main-event) 'down-mouse-1) + (window-minibuffer-p (posn-window (event-start main-event)))) + ;; Swallow the up-event. + (read-event) + (setq this-command 'isearch-edit-string)) + ;; Other characters terminate the search and are then executed normally. + (search-exit-option + (isearch-done) + (isearch-clean-overlays)) + ;; If search-exit-option is nil, run the command without exiting Isearch. + (t + (isearch-process-search-string key key))))) + +(defun isearch-post-command-hook () + (when isearch-pre-scroll-point + (let ((ab-bel (isearch-string-out-of-window isearch-pre-scroll-point))) + (if ab-bel + (isearch-back-into-window (eq ab-bel 'above) isearch-pre-scroll-point) + (goto-char isearch-pre-scroll-point))) + (setq isearch-pre-scroll-point nil) + (isearch-update))) (defun isearch-quote-char (&optional count) "Quote special characters for incremental search. With argument, add COUNT copies of the character." (interactive "p") (let ((char (read-quoted-char (isearch-message t)))) + (unless (characterp char) + (user-error "%s is not a valid character" + (key-description (vector char)))) ;; Assume character codes 0200 - 0377 stand for characters in some ;; single-byte character set, and convert them to Emacs ;; characters.