X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/0c382083b6b550c26fad8ac7f59b1ba09663e728..ce69a8443a7adc386235cb1b5eba3189dfe89d4e:/lisp/isearch.el diff --git a/lisp/isearch.el b/lisp/isearch.el index ebe2e8fa00..0bfda880d9 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -1,8 +1,6 @@ ;;; isearch.el --- incremental search minor mode -;; Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, -;; 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 -;; Free Software Foundation, Inc. +;; Copyright (C) 1992-1997, 1999-2012 Free Software Foundation, Inc. ;; Author: Daniel LaLiberte ;; Maintainer: FSF @@ -59,6 +57,7 @@ ;;; Code: +(eval-when-compile (require 'cl-lib)) ;; Some additional options and constants. @@ -104,7 +103,7 @@ in Isearch mode is always downcased." :group 'isearch) (defcustom search-nonincremental-instead t - "If non-nil, do a nonincremental search instead if exiting immediately. + "If non-nil, do a nonincremental search instead of exiting immediately. Actually, `isearch-edit-string' is called to let you enter the search string, and RET terminates editing and does a nonincremental search." :type 'boolean @@ -112,17 +111,24 @@ string, and RET terminates editing and does a nonincremental search." (defcustom search-whitespace-regexp (purecopy "\\s-+") "If non-nil, regular expression to match a sequence of whitespace chars. -This applies to regular expression incremental search. -When you put a space or spaces in the incremental regexp, it stands for -this, unless it is inside of a regexp construct such as [...] or *, + or ?. +When you enter a space or spaces in the incremental search, it +will match any sequence matched by this regexp. As an exception, +spaces are treated normally in regexp incremental search if they +occur in a regexp construct like [...] or *, + or ?. + +If the value is a string, it applies to both ordinary and +regexp incremental search. If the value is nil, or +`isearch-lax-whitespace' is nil for ordinary incremental search, or +`isearch-regexp-lax-whitespace' is nil for regexp incremental search, +then each space you type matches literally, against one space. + You might want to use something like \"[ \\t\\r\\n]+\" instead. In the Customization buffer, that is `[' followed by a space, -a tab, a carriage return (control-M), a newline, and `]+'. - -When this is nil, each space you type matches literally, against one space." - :type '(choice (const :tag "Find Spaces Literally" nil) +a tab, a carriage return (control-M), a newline, and `]+'." + :type '(choice (const :tag "Match Spaces Literally" nil) regexp) - :group 'isearch) + :group 'isearch + :version "24.3") (defcustom search-invisible 'open "If t incremental search can match hidden text. @@ -415,13 +421,6 @@ This is like `describe-bindings', but displays only Isearch keys." ;; 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, - ;; the binding for t does not affect characters. - ;; We use a dense keymap to save space. - (while (< i ?\s) - (define-key map (make-string 1 i) 'isearch-other-control-char) - (setq i (1+ i))) ;; Single-byte printing chars extend the search string by default. (setq i ?\s) @@ -436,8 +435,8 @@ This is like `describe-bindings', but displays only Isearch keys." ;; 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 [escape] meta-map) + (define-key meta-map [t] 'isearch-other-meta-char)) ;; Several non-printing chars change the searching behavior. (define-key map "\C-s" 'isearch-repeat-forward) @@ -466,7 +465,8 @@ This is like `describe-bindings', but displays only Isearch keys." (define-key map "\C-w" 'isearch-yank-word-or-char) (define-key map "\M-\C-w" 'isearch-del-char) (define-key map "\M-\C-y" 'isearch-yank-char) - (define-key map "\C-y" 'isearch-yank-line) + (define-key map "\C-y" 'isearch-yank-kill) + (define-key map "\M-s\C-e" 'isearch-yank-line) (define-key map (char-to-string help-char) isearch-help-map) (define-key map [help] isearch-help-map) @@ -474,7 +474,7 @@ This is like `describe-bindings', but displays only Isearch keys." (define-key map "\M-n" 'isearch-ring-advance) (define-key map "\M-p" 'isearch-ring-retreat) - (define-key map "\M-y" 'isearch-yank-kill) + (define-key map "\M-y" 'isearch-yank-pop) (define-key map "\M-\t" 'isearch-complete) @@ -502,14 +502,24 @@ 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) + (define-key map "\M-sc" 'isearch-toggle-case-fold) (define-key map "\M-sr" 'isearch-toggle-regexp) (define-key map "\M-sw" 'isearch-toggle-word) + (define-key map "\M-s_" 'isearch-toggle-symbol) + (define-key map "\M-s " 'isearch-toggle-lax-whitespace) (define-key map [?\M-%] 'isearch-query-replace) (define-key map [?\C-\M-%] 'isearch-query-replace-regexp) (define-key map "\M-so" 'isearch-occur) (define-key map "\M-shr" 'isearch-highlight-regexp) + ;; The key translations defined in the C-x 8 prefix should insert + ;; characters into 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-other-control-char) + map) "Keymap for `isearch-mode'.") @@ -531,8 +541,29 @@ This is like `describe-bindings', but displays only Isearch keys." (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-word nil + "Regexp-based search mode for words/symbols. +If t, do incremental search for a sequence of words, ignoring punctuation. +If the value is a function (e.g. `isearch-symbol-regexp'), it is called to +convert the search string to a regexp used by regexp search functions. +The property `isearch-message-prefix' put on this function specifies the +prefix string displayed in the search message.") + +(defvar isearch-lax-whitespace t + "If non-nil, a space will match a sequence of whitespace chars. +When you enter a space or spaces in ordinary incremental search, it +will match any sequence matched by the regexp defined by the variable +`search-whitespace-regexp'. If the value is nil, each space you type +matches literally, against one space. You can toggle the value of this +variable by the command `isearch-toggle-lax-whitespace'.") + +(defvar isearch-regexp-lax-whitespace nil + "If non-nil, a space will match a sequence of whitespace chars. +When you enter a space or spaces in regexp incremental search, it +will match any sequence matched by the regexp defined by the variable +`search-whitespace-regexp'. If the value is nil, each space you type +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. @@ -543,14 +574,15 @@ Each set is a vector of the form: (defvar isearch-string "") ; The current search string. (defvar isearch-message "") ; text-char-description version of isearch-string -(defvar isearch-message-prefix-add nil) ; Additonal text for the message prefix -(defvar isearch-message-suffix-add nil) ; Additonal text for the message suffix +(defvar isearch-message-prefix-add nil) ; Additional text for the message prefix +(defvar isearch-message-suffix-add nil) ; Additional text for the message suffix (defvar isearch-success t) ; Searching is currently successful. (defvar isearch-error nil) ; Error message for failed search. (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-barrier 0 + "Recorded minimum/maximal point for the current search.") (defvar isearch-just-started nil) (defvar isearch-start-hscroll 0) ; hscroll when starting the search. @@ -592,6 +624,9 @@ Each set is a vector of the form: ;; Accumulate here the overlays opened during searching. (defvar isearch-opened-overlays nil) +;; Non-nil if the string exists but is invisible. +(defvar isearch-hidden nil) + ;; The value of input-method-function when isearch is invoked. (defvar isearch-input-method-function nil) @@ -614,6 +649,7 @@ Each set is a vector of the form: (define-key global-map "\C-r" 'isearch-backward) (define-key esc-map "\C-r" 'isearch-backward-regexp) (define-key search-map "w" 'isearch-forward-word) +(define-key search-map "_" 'isearch-forward-symbol) ;; Entry points to isearch-mode. @@ -638,6 +674,8 @@ Type \\[isearch-yank-char] to yank char from buffer onto end of search\ Type \\[isearch-yank-line] to yank rest of line onto end of search string\ and search for it. Type \\[isearch-yank-kill] to yank the last string of killed text. +Type \\[isearch-yank-pop] to replace string just yanked into search prompt + with string killed before it. Type \\[isearch-quote-char] to quote control character to search for it. \\[isearch-abort] while searching or when search has failed cancels input\ back to what has @@ -651,6 +689,13 @@ If you try to exit with the search string still empty, it invokes Type \\[isearch-toggle-case-fold] to toggle search case-sensitivity. Type \\[isearch-toggle-regexp] to toggle regular-expression mode. Type \\[isearch-toggle-word] to toggle word mode. +Type \\[isearch-toggle-symbol] to toggle symbol mode. + +Type \\[isearch-toggle-lax-whitespace] to toggle whitespace matching. +In incremental searches, a space or spaces normally matches any whitespace +defined by the variable `search-whitespace-regexp'; see also the variables +`isearch-lax-whitespace' and `isearch-regexp-lax-whitespace'. + Type \\[isearch-edit-string] to edit the search string in the minibuffer. Also supported is a search ring of the previous 16 search strings. @@ -695,22 +740,20 @@ the calling function until the search is done." (isearch-mode t (not (null regexp-p)) nil (not no-recursive-edit))) (defun isearch-forward-regexp (&optional not-regexp no-recursive-edit) - "\ -Do incremental search forward for regular expression. + "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 the command `isearch-forward' for more information. -In regexp incremental searches, a space or spaces normally matches -any whitespace (the variable `search-whitespace-regexp' controls -precisely what that means). If you want to search for a literal space -and nothing else, enter C-q SPC." +In incremental searches, a space or spaces normally matches any +whitespace defined by the variable `search-whitespace-regexp'. +To search for a literal space and nothing else, enter C-q SPC. +To toggle whitespace matching, use `isearch-toggle-lax-whitespace'." (interactive "P\np") (isearch-mode t (null not-regexp) nil (not no-recursive-edit))) (defun isearch-forward-word (&optional not-word no-recursive-edit) - "\ -Do incremental search forward for a sequence of words. + "Do incremental search forward for a sequence of words. With a prefix argument, do a regular string search instead. Like ordinary incremental search except that your input is treated as a sequence of words without regard to how the words are separated. @@ -718,17 +761,24 @@ See the command `isearch-forward' for more information." (interactive "P\np") (isearch-mode t nil nil (not no-recursive-edit) (null not-word))) +(defun isearch-forward-symbol (&optional not-symbol no-recursive-edit) + "Do incremental search forward for a symbol. +The prefix argument is currently unused. +Like ordinary incremental search except that your input is treated +as a symbol surrounded by symbol boundary constructs \\_< and \\_>. +See the command `isearch-forward' for more information." + (interactive "P\np") + (isearch-mode t nil nil (not no-recursive-edit) 'isearch-symbol-regexp)) + (defun isearch-backward (&optional regexp-p no-recursive-edit) - "\ -Do incremental search backward. + "Do incremental search backward. With a prefix argument, do a regular expression search instead. See the command `isearch-forward' for more information." (interactive "P\np") (isearch-mode nil (not (null regexp-p)) nil (not no-recursive-edit))) (defun isearch-backward-regexp (&optional not-regexp no-recursive-edit) - "\ -Do incremental search backward for regular expression. + "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 the command `isearch-forward' for more information." @@ -745,14 +795,14 @@ as a regexp. See the command `isearch-forward' for more information." ;; "List of commands for which isearch-mode does not recursive-edit.") -(defun isearch-mode (forward &optional regexp op-fun recursive-edit word-p) +(defun isearch-mode (forward &optional regexp op-fun recursive-edit word) "Start Isearch minor mode. It is called by the function `isearch-forward' and other related functions." ;; Initialize global vars. (setq isearch-forward forward isearch-regexp regexp - isearch-word word-p + isearch-word word isearch-op-fun op-fun isearch-last-case-fold-search isearch-case-fold-search isearch-case-fold-search case-fold-search @@ -833,7 +883,8 @@ It is called by the function `isearch-forward' and other related functions." ;; Some high level utilities. Others below. (defun isearch-update () - ;; Called after each command to update the display. + "This is called after every isearch command to update the display. +The last thing it does is to run `isearch-update-post-hook'." (if (and (null unread-command-events) (null executing-kbd-macro)) (progn @@ -869,8 +920,7 @@ It is called by the function `isearch-forward' and other related functions." (if (< isearch-other-end (point)) ; isearch-forward? (isearch-highlight isearch-other-end (point)) (isearch-highlight (point) isearch-other-end)) - (isearch-dehighlight)) - )) + (isearch-dehighlight)))) (setq ;; quit-flag nil not for isearch-mode isearch-adjusted nil isearch-yank-flag nil) @@ -933,9 +983,10 @@ NOPUSH is t and EDIT is t." (before (if (bobp) nil (get-text-property (1- (point)) 'intangible)))) (when (and before after (eq before after)) - (if isearch-forward - (goto-char (next-single-property-change (point) 'intangible)) - (goto-char (previous-single-property-change (point) 'intangible))))) + (goto-char + (if isearch-forward + (next-single-property-change (point) 'intangible) + (previous-single-property-change (point) 'intangible))))) (if (and (> (length isearch-string) 0) (not nopush)) ;; Update the ring data. @@ -950,7 +1001,7 @@ NOPUSH is t and EDIT is t." (or (and transient-mark-mode mark-active) (progn (push-mark isearch-opoint t) - (or executing-kbd-macro (> (minibuffer-depth) 0) + (or executing-kbd-macro (> (minibuffer-depth) 0) edit (message "Mark saved where search started"))))) (and (not edit) isearch-recursive-edit (exit-recursive-edit))) @@ -975,73 +1026,58 @@ REGEXP if non-nil says use the regexp search ring." ;; The search status structure and stack. -(defsubst isearch-string-state (frame) - "Return the search string in FRAME." - (aref frame 0)) -(defsubst isearch-message-state (frame) - "Return the search string to display to the user in FRAME." - (aref frame 1)) -(defsubst isearch-point-state (frame) - "Return the point in FRAME." - (aref frame 2)) -(defsubst isearch-success-state (frame) - "Return the success flag in FRAME." - (aref frame 3)) -(defsubst isearch-forward-state (frame) - "Return the searching-forward flag in FRAME." - (aref frame 4)) -(defsubst isearch-other-end-state (frame) - "Return the other end of the match in FRAME." - (aref frame 5)) -(defsubst isearch-word-state (frame) - "Return the search-by-word flag in FRAME." - (aref frame 6)) -(defsubst isearch-error-state (frame) - "Return the regexp error message in FRAME, or nil if its regexp is valid." - (aref frame 7)) -(defsubst isearch-wrapped-state (frame) - "Return the search-wrapped flag in FRAME." - (aref frame 8)) -(defsubst isearch-barrier-state (frame) - "Return the barrier value in FRAME." - (aref frame 9)) -(defsubst isearch-case-fold-search-state (frame) - "Return the case-folding flag in FRAME." - (aref frame 10)) -(defsubst isearch-pop-fun-state (frame) - "Return the function restoring the mode-specific Isearch state in FRAME." - (aref frame 11)) - -(defun isearch-top-state () - (let ((cmd (car isearch-cmds))) - (setq isearch-string (isearch-string-state cmd) - isearch-message (isearch-message-state cmd) - isearch-success (isearch-success-state cmd) - isearch-forward (isearch-forward-state cmd) - isearch-other-end (isearch-other-end-state cmd) - isearch-word (isearch-word-state cmd) - isearch-error (isearch-error-state cmd) - isearch-wrapped (isearch-wrapped-state cmd) - isearch-barrier (isearch-barrier-state cmd) - isearch-case-fold-search (isearch-case-fold-search-state cmd)) - (if (functionp (isearch-pop-fun-state cmd)) - (funcall (isearch-pop-fun-state cmd) cmd)) - (goto-char (isearch-point-state cmd)))) +(cl-defstruct (isearch--state + (:constructor nil) + (:copier nil) + (:constructor isearch--get-state + (&aux + (string isearch-string) + (message isearch-message) + (point (point)) + (success isearch-success) + (forward isearch-forward) + (other-end isearch-other-end) + (word isearch-word) + (error isearch-error) + (wrapped isearch-wrapped) + (barrier isearch-barrier) + (case-fold-search isearch-case-fold-search) + (pop-fun (if isearch-push-state-function + (funcall isearch-push-state-function)))))) + (string :read-only t) + (message :read-only t) + (point :read-only t) + (success :read-only t) + (forward :read-only t) + (other-end :read-only t) + (word :read-only t) + (error :read-only t) + (wrapped :read-only t) + (barrier :read-only t) + (case-fold-search :read-only t) + (pop-fun :read-only t)) + +(defun isearch--set-state (cmd) + (setq isearch-string (isearch--state-string cmd) + isearch-message (isearch--state-message cmd) + isearch-success (isearch--state-success cmd) + isearch-forward (isearch--state-forward cmd) + isearch-other-end (isearch--state-other-end cmd) + isearch-word (isearch--state-word cmd) + isearch-error (isearch--state-error cmd) + isearch-wrapped (isearch--state-wrapped cmd) + isearch-barrier (isearch--state-barrier cmd) + isearch-case-fold-search (isearch--state-case-fold-search cmd)) + (if (functionp (isearch--state-pop-fun cmd)) + (funcall (isearch--state-pop-fun cmd) cmd)) + (goto-char (isearch--state-point cmd))) (defun isearch-pop-state () (setq isearch-cmds (cdr isearch-cmds)) - (isearch-top-state)) + (isearch--set-state (car isearch-cmds))) (defun isearch-push-state () - (setq isearch-cmds - (cons (vector isearch-string isearch-message (point) - isearch-success isearch-forward isearch-other-end - isearch-word - isearch-error isearch-wrapped isearch-barrier - isearch-case-fold-search - (if isearch-push-state-function - (funcall isearch-push-state-function))) - isearch-cmds))) + (push (isearch--get-state) isearch-cmds)) ;; Commands active while inside of the isearch minor mode. @@ -1059,6 +1095,26 @@ 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 `isearch-message', otherwise `isearch-string'." + (let ((cmds isearch-cmds) + (curr-msg (if msg isearch-message isearch-string)) + succ-msg) + (when (or (not isearch-success) isearch-error) + (while (or (not (isearch--state-success (car cmds))) + (isearch--state-error (car cmds))) + (pop cmds)) + (setq succ-msg (and cmds (if msg (isearch--state-message (car cmds)) + (isearch--state-string (car cmds))))) + (if (and (stringp succ-msg) + (< (length succ-msg) (length curr-msg)) + (equal succ-msg + (substring curr-msg 0 (length succ-msg)))) + (length succ-msg) + 0)))) (defun isearch-edit-string () "Edit the search string in the minibuffer. @@ -1068,9 +1124,7 @@ The following additional command keys are active while editing. \\[isearch-nonincremental-exit-minibuffer] to do one nonincremental search. \\[isearch-forward-exit-minibuffer] to resume isearching forward. \\[isearch-reverse-exit-minibuffer] to resume isearching backward. -\\[isearch-complete-edit] to complete the search string using the search ring. -\\ -If first char entered is \\[isearch-yank-word-or-char], then do word search instead." +\\[isearch-complete-edit] to complete the search string using the search ring." ;; This code is very hairy for several reasons, explained in the code. ;; Mainly, isearch-mode must be terminated while editing and then restarted. @@ -1078,7 +1132,7 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst ;; this could be simplified greatly. ;; Editing doesn't back up the search point. Should it? (interactive) - (condition-case err + (condition-case nil (progn (let ((isearch-nonincremental isearch-nonincremental) @@ -1090,6 +1144,7 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst (isearch-new-message isearch-message) (isearch-new-forward isearch-forward) (isearch-new-word isearch-word) + (isearch-new-case-fold isearch-case-fold-search) (isearch-regexp isearch-regexp) (isearch-op-fun isearch-op-fun) @@ -1113,6 +1168,14 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst ;; Save current configuration so we can restore it here. (isearch-window-configuration (current-window-configuration)) + ;; This could protect the index of the search rings, + ;; but we can't reliably count the number of typed M-p + ;; in `read-from-minibuffer' to adjust the index accordingly. + ;; So when the following is commented out, `isearch-mode' + ;; below resets the index to the predictable value nil. + ;; (search-ring-yank-pointer search-ring-yank-pointer) + ;; (regexp-search-ring-yank-pointer regexp-search-ring-yank-pointer) + ;; Temporarily restore `minibuffer-message-timeout'. (minibuffer-message-timeout isearch-original-minibuffer-message-timeout) @@ -1123,7 +1186,7 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst ;; 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 + (condition-case nil (isearch-done t t) (exit nil)) ; was recursive editing @@ -1133,13 +1196,18 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst (unwind-protect (let* ((message-log-max nil) + ;; Don't add a new search string to the search ring here + ;; in `read-from-minibuffer'. It should be added only + ;; by `isearch-update-ring' called from `isearch-done'. + (history-add-new-input nil) ;; Binding minibuffer-history-symbol to nil is a work-around ;; for some incompatibility with gmhist. (minibuffer-history-symbol)) (setq isearch-new-string (read-from-minibuffer - (isearch-message-prefix nil nil isearch-nonincremental) - isearch-string + (isearch-message-prefix nil isearch-nonincremental) + (cons isearch-string (1+ (or (isearch-fail-pos) + (length isearch-string)))) minibuffer-local-isearch-map nil (if isearch-regexp (cons 'regexp-search-ring @@ -1169,22 +1237,21 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst (setq isearch-string isearch-new-string isearch-message isearch-new-message isearch-forward isearch-new-forward - isearch-word isearch-new-word)) + isearch-word isearch-new-word + isearch-case-fold-search isearch-new-case-fold)) ;; Empty isearch-string means use default. - (if (= 0 (length isearch-string)) - (setq isearch-string (or (car (if isearch-regexp - regexp-search-ring - search-ring)) - "") - - isearch-message - (mapconcat 'isearch-text-char-description - isearch-string "")) - ;; 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. - )) + (when (= 0 (length isearch-string)) + (setq isearch-string (or (car (if isearch-regexp + regexp-search-ring + search-ring)) + "") + + isearch-message + (mapconcat 'isearch-text-char-description + isearch-string "")) + ;; After taking the last element, adjust ring to previous one. + (isearch-ring-adjust1 nil))) ;; This used to push the state as of before this C-s, but it adds ;; an inconsistent state where part of variables are from the @@ -1231,22 +1298,22 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst ;; For defined push-state function, restore the first state. ;; This calls pop-state function and restores original point. (let ((isearch-cmds (last isearch-cmds))) - (isearch-top-state)) + (isearch--set-state (car isearch-cmds))) (goto-char isearch-opoint)) - (isearch-done t) ; exit isearch + (isearch-done t) ; Exit isearch.. (isearch-clean-overlays) - (signal 'quit nil)) ; and pass on quit signal + (signal 'quit nil)) ; ..and pass on quit signal. (defun isearch-abort () "Abort incremental search mode if searching is successful, signaling quit. Otherwise, revert to previous successful search and continue searching. Use `isearch-exit' to quit without signaling." (interactive) -;; (ding) signal instead below, if quitting + ;; (ding) signal instead below, if quitting (discard-input) - (if isearch-success - ;; If search is successful, move back to starting point - ;; and really do quit. + (if (and isearch-success (not isearch-error)) + ;; If search is successful and has no incomplete regexp, + ;; move back to starting point and really do quit. (progn (setq isearch-success nil) (isearch-cancel)) @@ -1265,13 +1332,13 @@ Use `isearch-exit' to quit without signaling." (if (null (if isearch-regexp regexp-search-ring search-ring)) (setq isearch-error "No previous search string") (setq isearch-string - (if isearch-regexp - (car regexp-search-ring) - (car search-ring)) + (car (if isearch-regexp regexp-search-ring search-ring)) isearch-message (mapconcat 'isearch-text-char-description isearch-string "") - isearch-case-fold-search isearch-last-case-fold-search)) + isearch-case-fold-search isearch-last-case-fold-search) + ;; After taking the last element, adjust ring to previous one. + (isearch-ring-adjust1 nil)) ;; If already have what to search for, repeat it. (or isearch-success (progn @@ -1326,9 +1393,42 @@ Use `isearch-exit' to quit without signaling." (defun isearch-toggle-word () "Toggle word searching on or off." + ;; The status stack is left unchanged. (interactive) (setq isearch-word (not isearch-word)) + (if isearch-word (setq isearch-regexp nil)) + (setq isearch-success t isearch-adjusted t) + (isearch-update)) + +(defun isearch-toggle-symbol () + "Toggle symbol searching on or off." + (interactive) + (setq isearch-word (unless (eq isearch-word 'isearch-symbol-regexp) + 'isearch-symbol-regexp)) + (if isearch-word (setq isearch-regexp nil)) + (setq isearch-success t isearch-adjusted t) + (isearch-update)) + +(defun isearch-toggle-lax-whitespace () + "Toggle whitespace matching in searching on or off. +In ordinary search, toggles the value of the variable +`isearch-lax-whitespace'. In regexp search, toggles the +value of the variable `isearch-regexp-lax-whitespace'." + (interactive) + (if isearch-regexp + (setq isearch-regexp-lax-whitespace (not isearch-regexp-lax-whitespace)) + (setq isearch-lax-whitespace (not isearch-lax-whitespace))) + (let ((message-log-max nil)) + (message "%s%s [%s]" + (isearch-message-prefix nil isearch-nonincremental) + isearch-message + (if (if isearch-regexp + isearch-regexp-lax-whitespace + isearch-lax-whitespace) + "match spaces loosely" + "match spaces literally"))) (setq isearch-success t isearch-adjusted t) + (sit-for 1) (isearch-update)) (defun isearch-toggle-case-fold () @@ -1338,19 +1438,139 @@ Use `isearch-exit' to quit without signaling." (if isearch-case-fold-search nil 'yes)) (let ((message-log-max nil)) (message "%s%s [case %ssensitive]" - (isearch-message-prefix nil nil isearch-nonincremental) + (isearch-message-prefix nil isearch-nonincremental) isearch-message (if isearch-case-fold-search "in" ""))) (setq isearch-success t isearch-adjusted t) (sit-for 1) (isearch-update)) + +;; Word search + +(defun word-search-regexp (string &optional lax) + "Return a regexp which matches words, ignoring punctuation. +Given STRING, a string of words separated by word delimiters, +compute a regexp that matches those exact words separated by +arbitrary punctuation. If LAX is non-nil, the end of the string +need not match a word boundary unless it ends in whitespace. + +Used in `word-search-forward', `word-search-backward', +`word-search-forward-lax', `word-search-backward-lax'." + (if (string-match-p "^\\W*$" string) + "" + (concat + "\\b" + (mapconcat 'identity (split-string string "\\W+" t) "\\W+") + (if (or (not lax) (string-match-p "\\W$" string)) "\\b")))) + +(defun word-search-backward (string &optional bound noerror count) + "Search backward from point for STRING, ignoring differences in punctuation. +Set point to the beginning of the occurrence found, and return point. +An optional second argument bounds the search; it is a buffer position. +The match found must not extend before that position. +Optional third argument, if t, means if fail just return nil (no error). + If not nil and not t, move to limit of search and return nil. +Optional fourth argument is repeat count--search for successive occurrences. + +Relies on the function `word-search-regexp' to convert a sequence +of words in STRING to a regexp used to search words without regard +to punctuation." + (interactive "sWord search backward: ") + (re-search-backward (word-search-regexp string nil) bound noerror count)) + +(defun word-search-forward (string &optional bound noerror count) + "Search forward from point for STRING, ignoring differences in punctuation. +Set point to the end of the occurrence found, and return point. +An optional second argument bounds the search; it is a buffer position. +The match found must not extend after that position. +Optional third argument, if t, means if fail just return nil (no error). + If not nil and not t, move to limit of search and return nil. +Optional fourth argument is repeat count--search for successive occurrences. + +Relies on the function `word-search-regexp' to convert a sequence +of words in STRING to a regexp used to search words without regard +to punctuation." + (interactive "sWord search: ") + (re-search-forward (word-search-regexp string nil) bound noerror count)) + +(defun word-search-backward-lax (string &optional bound noerror count) + "Search backward from point for STRING, ignoring differences in punctuation. +Set point to the beginning of the occurrence found, and return point. + +Unlike `word-search-backward', the end of STRING need not match a word +boundary, unless STRING ends in whitespace. + +An optional second argument bounds the search; it is a buffer position. +The match found must not extend before that position. +Optional third argument, if t, means if fail just return nil (no error). + If not nil and not t, move to limit of search and return nil. +Optional fourth argument is repeat count--search for successive occurrences. + +Relies on the function `word-search-regexp' to convert a sequence +of words in STRING to a regexp used to search words without regard +to punctuation." + (interactive "sWord search backward: ") + (re-search-backward (word-search-regexp string t) bound noerror count)) + +(defun word-search-forward-lax (string &optional bound noerror count) + "Search forward from point for STRING, ignoring differences in punctuation. +Set point to the end of the occurrence found, and return point. + +Unlike `word-search-forward', the end of STRING need not match a word +boundary, unless STRING ends in whitespace. + +An optional second argument bounds the search; it is a buffer position. +The match found must not extend after that position. +Optional third argument, if t, means if fail just return nil (no error). + If not nil and not t, move to limit of search and return nil. +Optional fourth argument is repeat count--search for successive occurrences. + +Relies on the function `word-search-regexp' to convert a sequence +of words in STRING to a regexp used to search words without regard +to punctuation." + (interactive "sWord search: ") + (re-search-forward (word-search-regexp string t) bound noerror count)) + +;; Symbol search + +(defun isearch-symbol-regexp (string &optional lax) + "Return a regexp which matches STRING as a symbol. +Creates a regexp where STRING is surrounded by symbol delimiters \\_< and \\_>. +If LAX is non-nil, the end of the string need not match a symbol boundary." + (concat "\\_<" (regexp-quote string) (unless lax "\\_>"))) + +(put 'isearch-symbol-regexp 'isearch-message-prefix "symbol ") + +;; Search with lax whitespace + +(defun search-forward-lax-whitespace (string &optional bound noerror count) + "Search forward for STRING, matching a sequence of whitespace chars." + (let ((search-spaces-regexp search-whitespace-regexp)) + (re-search-forward (regexp-quote string) bound noerror count))) + +(defun search-backward-lax-whitespace (string &optional bound noerror count) + "Search backward for STRING, matching a sequence of whitespace chars." + (let ((search-spaces-regexp search-whitespace-regexp)) + (re-search-backward (regexp-quote string) bound noerror count))) + +(defun re-search-forward-lax-whitespace (regexp &optional bound noerror count) + "Search forward for REGEXP, matching a sequence of whitespace chars." + (let ((search-spaces-regexp search-whitespace-regexp)) + (re-search-forward regexp bound noerror count))) + +(defun re-search-backward-lax-whitespace (regexp &optional bound noerror count) + "Search backward for REGEXP, matching a sequence of whitespace chars." + (let ((search-spaces-regexp search-whitespace-regexp)) + (re-search-backward regexp bound noerror count))) + + (defun isearch-query-replace (&optional delimited 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 -is possible only when `isearch-allow-scroll' is non-nil, and it don't -always provides the correct matches for `query-replace', so the preferred +is possible only when `isearch-allow-scroll' is non-nil, and it doesn't +always provide the correct matches for `query-replace', so the preferred way to run word replacements from Isearch is `M-s w ... M-%'." (interactive (list current-prefix-arg)) @@ -1360,6 +1580,10 @@ way to run word replacements from Isearch is `M-s w ... M-%'." ;; set `search-upper-case' to nil to not call ;; `isearch-no-upper-case-p' in `perform-replace' (search-upper-case nil) + (replace-lax-whitespace + isearch-lax-whitespace) + (replace-regexp-lax-whitespace + isearch-regexp-lax-whitespace) ;; 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. @@ -1397,25 +1621,49 @@ See `isearch-query-replace' for more information." (isearch-query-replace delimited t)) (defun isearch-occur (regexp &optional nlines) - "Run `occur' with regexp to search from the current search string. -Interactively, REGEXP is the current search regexp or a quoted search -string. NLINES has the same meaning as in `occur'." + "Run `occur' using the last search string as the regexp. +Interactively, REGEXP is constructed using the search string from the +last search command. NLINES has the same meaning as in `occur'. + +If the last search command was a word search, REGEXP is computed from +the search words, ignoring punctuation. If the last search +command was a regular expression search, REGEXP is the regular +expression used in that search. If the last search command searched +for a literal string, REGEXP is constructed by quoting all the special +characters in that string." (interactive - (list - (cond - (isearch-word (concat "\\b" (replace-regexp-in-string - "\\W+" "\\W+" - (replace-regexp-in-string - "^\\W+\\|\\W+$" "" isearch-string) - nil t) - "\\b")) - (isearch-regexp isearch-string) - (t (regexp-quote isearch-string))) - (if current-prefix-arg (prefix-numeric-value current-prefix-arg)))) + (let* ((perform-collect (consp current-prefix-arg)) + (regexp (cond + ((functionp isearch-word) + (funcall isearch-word isearch-string)) + (isearch-word (word-search-regexp isearch-string)) + (isearch-regexp isearch-string) + (t (regexp-quote isearch-string))))) + (list regexp + (if perform-collect + ;; Perform collect operation + (if (zerop (regexp-opt-depth regexp)) + ;; No subexpression so collect the entire match. + "\\&" + ;; Get the regexp for collection pattern. + (isearch-done nil t) + (isearch-clean-overlays) + (let ((default (car occur-collect-regexp-history))) + (read-regexp + (format "Regexp to collect (default %s): " default) + default 'occur-collect-regexp-history))) + ;; Otherwise normal occur takes numerical prefix argument. + (when current-prefix-arg + (prefix-numeric-value current-prefix-arg)))))) (let ((case-fold-search isearch-case-fold-search) - ;; set `search-upper-case' to nil to not call - ;; `isearch-no-upper-case-p' in `occur-1' - (search-upper-case nil)) + ;; Set `search-upper-case' to nil to not call + ;; `isearch-no-upper-case-p' in `occur-1'. + (search-upper-case nil) + (search-spaces-regexp + (if (if isearch-regexp + isearch-regexp-lax-whitespace + isearch-lax-whitespace) + search-whitespace-regexp))) (occur regexp nlines))) (declare-function hi-lock-read-face-name "hi-lock" ()) @@ -1497,10 +1745,25 @@ If search string is empty, just beep." (interactive) (isearch-yank-string (current-kill 0))) +(defun isearch-yank-pop () + "Replace just-yanked search string with previously killed string." + (interactive) + (if (not (memq last-command '(isearch-yank-kill isearch-yank-pop))) + ;; Fall back on `isearch-yank-kill' for the benefits of people + ;; who are used to the old behavior of `M-y' in isearch mode. In + ;; future, this fallback may be changed if we ever change + ;; `yank-pop' to do something like the kill-ring-browser. + (isearch-yank-kill) + (isearch-pop-state) + (isearch-yank-string (current-kill 1)))) + (defun isearch-yank-x-selection () "Pull current X selection into search string." (interactive) - (isearch-yank-string (x-get-selection))) + (isearch-yank-string (x-get-selection)) + ;; If `x-get-selection' returned the text from the active region, + ;; then it "used" the mark which we should hence deactivate. + (when select-active-regions (deactivate-mark))) (defun isearch-mouse-2 (click) @@ -1591,8 +1854,12 @@ Subword is used when `subword-mode' is activated. " (if (and (eq case-fold-search t) search-upper-case) (setq case-fold-search (isearch-no-upper-case-p isearch-string isearch-regexp))) - (looking-at (if isearch-regexp isearch-string - (regexp-quote isearch-string)))) + (looking-at (cond + ((functionp isearch-word) + (funcall isearch-word isearch-string t)) + (isearch-word (word-search-regexp isearch-string t)) + (isearch-regexp isearch-string) + (t (regexp-quote isearch-string))))) (error nil)) (or isearch-yank-flag (<= (match-end 0) @@ -1647,7 +1914,7 @@ to the barrier." ;; We have to check 2 stack frames because the last might be ;; invalid just because of a backslash. (or (not isearch-error) - (not (isearch-error-state (cadr isearch-cmds))) + (not (isearch--state-error (cadr isearch-cmds))) allow-invalid)) (if to-barrier (progn (goto-char isearch-barrier) @@ -1662,8 +1929,8 @@ to the barrier." ;; Also skip over postfix operators -- though horrid, ;; 'ab?\{5,6\}+\{1,2\}*' is perfectly valid. (while (and previous - (or (isearch-error-state frame) - (let* ((string (isearch-string-state frame)) + (or (isearch--state-error frame) + (let* ((string (isearch--state-string frame)) (lchar (aref string (1- (length string))))) ;; The operators aren't always operators; check ;; backslashes. This doesn't handle the case of @@ -1671,7 +1938,7 @@ to the barrier." ;; being special, but then we should fall back to ;; the barrier anyway because it's all optional. (if (isearch-backslash - (isearch-string-state (car previous))) + (isearch--state-string (car previous))) (eq lchar ?\}) (memq lchar '(?* ?? ?+)))))) (setq stack previous previous (cdr previous) frame (car stack))) @@ -1681,7 +1948,7 @@ to the barrier." ;; what matched before that. (let ((last-other-end (or (and (car previous) - (isearch-other-end-state (car previous))) + (isearch--state-other-end (car previous))) isearch-barrier))) (goto-char (if isearch-forward (max last-other-end isearch-barrier) @@ -1755,9 +2022,13 @@ Scroll-bar or mode-line events are processed appropriately." ;; Commands which change the window layout (put 'delete-other-windows 'isearch-scroll t) (put 'balance-windows 'isearch-scroll t) +(put 'split-window-right 'isearch-scroll t) +(put 'split-window-below 'isearch-scroll t) +(put 'enlarge-window 'isearch-scroll t) + +;; Aliases for split-window-* (put 'split-window-vertically 'isearch-scroll t) (put 'split-window-horizontally 'isearch-scroll t) -(put 'enlarge-window 'isearch-scroll t) ;; Universal argument commands (put 'universal-argument 'isearch-scroll t) @@ -1820,7 +2091,7 @@ the bottom." (goto-char isearch-point)) (defun isearch-reread-key-sequence-naturally (keylist) - "Reread key sequence KEYLIST with Isearch mode's keymap deactivated. + "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) @@ -1875,9 +2146,11 @@ Isearch mode." (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))) + (listify-key-sequence + (lookup-key local-function-key-map key))) (while keylist (setq key (car keylist)) ;; If KEY is a printing char, we handle it here @@ -1886,10 +2159,14 @@ Isearch mode." (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))))) ( @@ -1912,8 +2189,10 @@ Isearch mode." 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. @@ -1942,6 +2221,7 @@ Isearch mode." (isearch-edit-string)) (search-exit-option (let (window) + (setq prefix-arg arg) (isearch-unread-key-sequence keylist) (setq main-event (car unread-command-events)) @@ -1984,7 +2264,7 @@ Isearch mode." ;; Assume character codes 0200 - 0377 stand for characters in some ;; single-byte character set, and convert them to Emacs ;; characters. - (if (and isearch-regexp (= char ?\s)) + (if (and isearch-regexp isearch-regexp-lax-whitespace (= char ?\s)) (if (subregexp-context-p isearch-string (length isearch-string)) (isearch-process-search-string "[ ]" " ") (isearch-process-search-char char)) @@ -2040,7 +2320,7 @@ Isearch mode." () (set yank-pointer-name (setq yank-pointer - (mod (+ (or yank-pointer 0) + (mod (+ (or yank-pointer (if advance 0 -1)) (if advance -1 1)) length))) (setq isearch-string (nth yank-pointer ring) @@ -2126,33 +2406,22 @@ If there is no completion possible, say so and continue searching." ;; Generate and print the message string. (let ((cursor-in-echo-area ellipsis) (m isearch-message) - (cmds isearch-cmds) - succ-msg) - (when (or (not isearch-success) isearch-error) - ;; Highlight failed part - (while (or (not (isearch-success-state (car cmds))) - (isearch-error-state (car cmds))) - (pop cmds)) - (setq succ-msg (and cmds (isearch-message-state (car cmds))) - m (copy-sequence m)) - (add-text-properties - (if (and (stringp succ-msg) - (< (length succ-msg) (length m)) - (equal succ-msg (substring m 0 (length succ-msg)))) - (length succ-msg) - 0) - (length m) '(face isearch-fail) m) + (fail-pos (isearch-fail-pos t))) + ;; Highlight failed part + (when fail-pos + (setq m (copy-sequence m)) + (add-text-properties fail-pos (length m) '(face isearch-fail) m) ;; Highlight failed trailing whitespace (when (string-match " +$" m) (add-text-properties (match-beginning 0) (match-end 0) '(face trailing-whitespace) m))) (setq m (concat - (isearch-message-prefix c-q-hack ellipsis isearch-nonincremental) + (isearch-message-prefix ellipsis isearch-nonincremental) m - (isearch-message-suffix c-q-hack ellipsis))) + (isearch-message-suffix c-q-hack))) (if c-q-hack m (let ((message-log-max nil)) (message "%s" m))))) -(defun isearch-message-prefix (&optional c-q-hack ellipsis nonincremental) +(defun isearch-message-prefix (&optional 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. @@ -2172,20 +2441,28 @@ If there is no completion possible, say so and continue searching." (< (point) isearch-opoint))) "over") (if isearch-wrapped "wrapped ") - (if isearch-word "word " "") + (if isearch-word + (or (and (symbolp isearch-word) + (get isearch-word 'isearch-message-prefix)) + "word ") + "") (if isearch-regexp "regexp " "") (if multi-isearch-next-buffer-current-function "multi " "") (or isearch-message-prefix-add "") (if nonincremental "search" "I-search") (if isearch-forward "" " backward") (if current-input-method - (concat " [" current-input-method-title "]: ") + ;; Input methods for RTL languages use RTL + ;; characters for their title, and that messes + ;; up the display of search text after the prompt. + (bidi-string-mark-left-to-right + (concat " [" current-input-method-title "]: ")) ": ") ))) (propertize (concat (upcase (substring m 0 1)) (substring m 1)) 'face 'minibuffer-prompt))) -(defun isearch-message-suffix (&optional c-q-hack ellipsis) +(defun isearch-message-suffix (&optional c-q-hack) (concat (if c-q-hack "^Q" "") (if isearch-error (concat " [" isearch-error "]") @@ -2195,31 +2472,51 @@ If there is no completion possible, say so and continue searching." ;; Searching -(defvar isearch-search-fun-function nil - "Override `isearch-search-fun'. -This function should return the search function for Isearch to use. -It will call this function with three arguments -as if it were `search-forward'.") +(defvar isearch-search-fun-function 'isearch-search-fun-default + "Non-default value overrides the behavior of `isearch-search-fun-default'. +This variable's value should be a function, which will be called +with no arguments, and should return a function that takes three +arguments: STRING, BOUND, and NOERROR. + +This returned function will be used by `isearch-search-string' to +search for the first occurrence of STRING or its translation.") (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 + (funcall (or isearch-search-fun-function 'isearch-search-fun-default))) + +(defun isearch-search-fun-default () + "Return default functions to use for the search." + (cond + (isearch-word + (lambda (string &optional bound noerror count) ;; Use lax versions to not fail at the end of the word while ;; the user adds and removes characters in the search string ;; (or when using nonincremental word isearch) - (if (or isearch-nonincremental - (eq (length isearch-string) - (length (isearch-string-state (car isearch-cmds))))) - (if isearch-forward 'word-search-forward 'word-search-backward) - (if isearch-forward 'word-search-forward-lax 'word-search-backward-lax))) - (isearch-regexp - (if isearch-forward 're-search-forward 're-search-backward)) - (t - (if isearch-forward 'search-forward 'search-backward))))) + (let ((lax (not (or isearch-nonincremental + (eq (length isearch-string) + (length (isearch--state-string + (car isearch-cmds)))))))) + (funcall + (if isearch-forward #'re-search-forward #'re-search-backward) + (if (functionp isearch-word) + (funcall isearch-word string lax) + (word-search-regexp string lax)) + bound noerror count)))) + ((and isearch-regexp isearch-regexp-lax-whitespace + search-whitespace-regexp) + (if isearch-forward + 're-search-forward-lax-whitespace + 're-search-backward-lax-whitespace)) + (isearch-regexp + (if isearch-forward 're-search-forward 're-search-backward)) + ((and isearch-lax-whitespace search-whitespace-regexp) + (if isearch-forward + 'search-forward-lax-whitespace + 'search-backward-lax-whitespace)) + (t + (if isearch-forward 'search-forward 'search-backward)))) (defun isearch-search-string (string bound noerror) "Search for the first occurrence of STRING or its translation. @@ -2275,11 +2572,11 @@ update the match data, and return point." (isearch-no-upper-case-p isearch-string isearch-regexp))) (condition-case lossage (let ((inhibit-point-motion-hooks + ;; FIXME: equality comparisons on functions is asking for trouble. (and (eq isearch-filter-predicate 'isearch-filter-visible) search-invisible)) (inhibit-quit nil) (case-fold-search isearch-case-fold-search) - (search-spaces-regexp search-whitespace-regexp) (retry t)) (setq isearch-error nil) (while retry @@ -2319,11 +2616,12 @@ update the match data, and return point." (if isearch-success nil ;; Ding if failed this time after succeeding last time. - (and (isearch-success-state (car isearch-cmds)) + (and (isearch--state-success (car isearch-cmds)) (ding)) - (if (functionp (isearch-pop-fun-state (car isearch-cmds))) - (funcall (isearch-pop-fun-state (car isearch-cmds)) (car isearch-cmds))) - (goto-char (isearch-point-state (car isearch-cmds))))) + (if (functionp (isearch--state-pop-fun (car isearch-cmds))) + (funcall (isearch--state-pop-fun (car isearch-cmds)) + (car isearch-cmds))) + (goto-char (isearch--state-point (car isearch-cmds))))) ;; Called when opening an overlay, and we are still in isearch. @@ -2420,14 +2718,8 @@ update the match data, and return point." ;; 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) + (while (and (< (point) end) (invisible-p (point))) + (if (invisible-p (get-text-property (point) 'invisible)) (progn (goto-char (next-single-property-change (point) 'invisible nil end)) @@ -2442,10 +2734,7 @@ update the match data, and return point." (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 (invisible-p invis-prop) (if (overlay-get o 'isearch-open-invisible) (setq ov-list (cons o ov-list)) ;; We found one overlay that cannot be @@ -2579,8 +2868,11 @@ since they have special meaning in a regexp." (defvar isearch-lazy-highlight-window-end nil) (defvar isearch-lazy-highlight-case-fold-search nil) (defvar isearch-lazy-highlight-regexp nil) -(defvar isearch-lazy-highlight-space-regexp nil) +(defvar isearch-lazy-highlight-lax-whitespace nil) +(defvar isearch-lazy-highlight-regexp-lax-whitespace nil) +(defvar isearch-lazy-highlight-word nil) (defvar isearch-lazy-highlight-forward nil) +(defvar isearch-lazy-highlight-error nil) (defun lazy-highlight-cleanup (&optional force) "Stop lazy highlighting and remove extra highlighting from current buffer. @@ -2617,32 +2909,46 @@ by other Emacs features." isearch-case-fold-search)) (not (eq isearch-lazy-highlight-regexp isearch-regexp)) + (not (eq isearch-lazy-highlight-word + isearch-word)) + (not (eq isearch-lazy-highlight-lax-whitespace + isearch-lax-whitespace)) + (not (eq isearch-lazy-highlight-regexp-lax-whitespace + isearch-regexp-lax-whitespace)) (not (= (window-start) isearch-lazy-highlight-window-start)) (not (= (window-end) ; Window may have been split/joined. isearch-lazy-highlight-window-end)) (not (eq isearch-forward - isearch-lazy-highlight-forward)))) + isearch-lazy-highlight-forward)) + ;; In case we are recovering from an error. + (not (equal isearch-error + isearch-lazy-highlight-error)))) ;; something important did indeed change (lazy-highlight-cleanup t) ;kill old loop & remove overlays - (when (not isearch-error) - (setq isearch-lazy-highlight-start-limit beg - isearch-lazy-highlight-end-limit end) - (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 - isearch-lazy-highlight-case-fold-search isearch-case-fold-search - isearch-lazy-highlight-regexp isearch-regexp - isearch-lazy-highlight-wrapped nil - isearch-lazy-highlight-space-regexp search-whitespace-regexp - isearch-lazy-highlight-forward isearch-forward) + (setq isearch-lazy-highlight-error isearch-error) + ;; It used to check for `(not isearch-error)' here, but actually + ;; lazy-highlighting might find matches to highlight even when + ;; `isearch-error' is non-nil. (Bug#9918) + (setq isearch-lazy-highlight-start-limit beg + isearch-lazy-highlight-end-limit end) + (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-wrapped nil + isearch-lazy-highlight-last-string isearch-string + isearch-lazy-highlight-case-fold-search isearch-case-fold-search + isearch-lazy-highlight-regexp isearch-regexp + isearch-lazy-highlight-lax-whitespace isearch-lax-whitespace + isearch-lazy-highlight-regexp-lax-whitespace isearch-regexp-lax-whitespace + isearch-lazy-highlight-word isearch-word + isearch-lazy-highlight-forward isearch-forward) (unless (equal isearch-string "") (setq isearch-lazy-highlight-timer (run-with-idle-timer lazy-highlight-initial-delay nil - 'isearch-lazy-highlight-update)))))) + 'isearch-lazy-highlight-update))))) (defun isearch-lazy-highlight-search () "Search ahead for the next or previous match, for lazy highlighting. @@ -2650,11 +2956,15 @@ Attempt to do the search exactly the way the pending Isearch would." (condition-case nil (let ((case-fold-search isearch-lazy-highlight-case-fold-search) (isearch-regexp isearch-lazy-highlight-regexp) - (search-spaces-regexp isearch-lazy-highlight-space-regexp) + (isearch-word isearch-lazy-highlight-word) + (isearch-lax-whitespace + isearch-lazy-highlight-lax-whitespace) + (isearch-regexp-lax-whitespace + isearch-lazy-highlight-regexp-lax-whitespace) + (isearch-forward isearch-lazy-highlight-forward) (search-invisible nil) ; don't match invisible text (retry t) (success nil) - (isearch-forward isearch-lazy-highlight-forward) (bound (if isearch-lazy-highlight-forward (min (or isearch-lazy-highlight-end-limit (point-max)) (if isearch-lazy-highlight-wrapped @@ -2762,5 +3072,4 @@ CASE-FOLD non-nil means the search was case-insensitive." (isearch-search) (isearch-update)) -;; arch-tag: 74850515-f7d8-43a6-8a2c-ca90a4c1e675 ;;; isearch.el ends here