X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/758710cb94511217f61909dbb48708a29503f44b..8fc29035f39226e4c9154132fa57d57559ee4c22:/lisp/isearch.el diff --git a/lisp/isearch.el b/lisp/isearch.el index 750ed129b7..c343472767 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -9,10 +9,10 @@ ;; This file is part of GNU Emacs. -;; GNU Emacs is free software; you can redistribute it and/or modify +;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 3, or (at your option) -;; any later version. +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -20,9 +20,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. +;; along with GNU Emacs. If not, see . ;;; Commentary: @@ -178,6 +176,12 @@ or to the end of the buffer for a backward search.") "Function to save a function restoring the mode-specific isearch state to the search status stack.") +(defvar isearch-success-function 'isearch-success-function-default + "Function to report whether the new search match is considered successful. +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 stopping at this match.") + ;; Search ring. (defvar search-ring nil @@ -321,6 +325,73 @@ A value of nil means highlight all matches." (define-obsolete-variable-alias 'isearch-lazy-highlight-face 'lazy-highlight-face "22.1") + +;; Define isearch help map. + +(defvar isearch-help-map + (let ((i 0) + (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) + (define-key map "?" 'isearch-help-for-help) + (define-key map "b" 'isearch-describe-bindings) + (define-key map "k" 'isearch-describe-key) + (define-key map "m" 'isearch-describe-mode) + (define-key map "q" 'help-quit) + map) + "Keymap for characters following the Help key for isearch mode.") + +(eval-when-compile (require 'help-macro)) + +(make-help-screen isearch-help-for-help-internal + "Type a help option: [bkm] or ?" + "You have typed %THIS-KEY%, the help character. Type a Help option: +\(Type \\\\[help-quit] to exit the Help command.) + +b Display all isearch key bindings. +k KEYS Display full documentation of isearch key sequence. +m Display documentation of isearch mode. + +You can't type here other help keys available in the global help map, +but outise of this help window when you type them in isearch mode, +they exit isearch mode before displaying global help." + isearch-help-map) + +(defun isearch-help-for-help () + "Display isearch help menu." + (interactive) + (let (same-window-buffer-names same-window-regexps) + (isearch-help-for-help-internal)) + (isearch-update)) + +(defun isearch-describe-bindings () + "Show a list of all keys defined in isearch mode, and their definitions. +This is like `describe-bindings', but displays only isearch keys." + (interactive) + (let (same-window-buffer-names same-window-regexps) + (with-help-window "*Help*" + (with-current-buffer standard-output + (princ "Isearch Mode Bindings:\n") + (princ (substitute-command-keys "\\{isearch-mode-map}")))))) + +(defun isearch-describe-key () + "Display documentation of the function invoked by isearch key." + (interactive) + (let (same-window-buffer-names same-window-regexps) + (call-interactively 'describe-key)) + (isearch-update)) + +(defun isearch-describe-mode () + "Display documentation of isearch mode." + (interactive) + (let (same-window-buffer-names same-window-regexps) + (describe-function 'isearch-forward)) + (isearch-update)) + +(defalias 'isearch-mode-help 'isearch-describe-mode) + ;; Define isearch-mode keymap. @@ -388,9 +459,7 @@ A value of nil means highlight all matches." (define-key map "\M-\C-y" 'isearch-yank-char) (define-key map "\C-y" 'isearch-yank-line) - ;; 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 "\C-h" isearch-help-map) (define-key map "\M-n" 'isearch-ring-advance) (define-key map "\M-p" 'isearch-ring-retreat) @@ -422,9 +491,13 @@ A value of nil means highlight all matches." (define-key map "\M-r" 'isearch-toggle-regexp) (define-key map "\M-e" 'isearch-edit-string) + (define-key map "\M-sr" 'isearch-toggle-regexp) + (define-key map "\M-sw" 'isearch-toggle-word) + (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) map) "Keymap for `isearch-mode'.") @@ -436,6 +509,7 @@ A value of nil means highlight all matches." (define-key map "\M-\t" 'isearch-complete-edit) (define-key map "\C-s" 'isearch-forward-exit-minibuffer) (define-key map "\C-r" 'isearch-reverse-exit-minibuffer) + (define-key map "\C-w" 'isearch-edit-string-set-word) (define-key map "\C-f" 'isearch-yank-char-in-minibuffer) (define-key map [right] 'isearch-yank-char-in-minibuffer) map) @@ -459,6 +533,9 @@ 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-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). @@ -526,6 +603,7 @@ Each set is a vector of the form: (define-key esc-map "\C-s" 'isearch-forward-regexp) (define-key global-map "\C-r" 'isearch-backward) (define-key esc-map "\C-r" 'isearch-backward-regexp) +(define-key search-map "w" 'isearch-forward-word) ;; Entry points to isearch-mode. @@ -560,13 +638,9 @@ Type \\[isearch-quote-char] to quote control character to search for it. If you try to exit with the search string still empty, it invokes nonincremental search. -Type \\[isearch-query-replace] to start `query-replace' with string to\ - replace from last search string. -Type \\[isearch-query-replace-regexp] to start `query-replace-regexp'\ - with string to replace from last search string. - 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-edit-string] to edit the search string in the minibuffer. Also supported is a search ring of the previous 16 search strings. @@ -575,6 +649,19 @@ Type \\[isearch-ring-retreat] to search for the previous item in the search\ ring. Type \\[isearch-complete] to complete the search string using the search ring. +Type \\[isearch-query-replace] to run `query-replace' with string to\ + replace from last search string. +Type \\[isearch-query-replace-regexp] to run `query-replace-regexp'\ + with the last search string. +Type \\[isearch-occur] to run `occur' that shows\ + the last search string. +Type \\[isearch-highlight-regexp] to run `highlight-regexp'\ + that highlights the last search string. + +Type \\[isearch-describe-bindings] to display all isearch key bindings. +Type \\[isearch-describe-key] to display documentation of isearch key. +Type \\[isearch-describe-mode] to display documentation of isearch mode. + If an input method is turned on in the current buffer, that input method is also active while you are typing characters to search. To toggle the input method, type \\[isearch-toggle-input-method]. It @@ -600,8 +687,8 @@ the calling function until the search is done." "\ Do incremental search forward for regular expression. With a prefix argument, do a regular string search instead. -Like ordinary incremental search except that your input -is treated as a regexp. See \\[isearch-forward] for more info. +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 @@ -610,11 +697,21 @@ and nothing else, enter C-q SPC." (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. +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. +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-backward (&optional regexp-p no-recursive-edit) "\ Do incremental search backward. With a prefix argument, do a regular expression search instead. -See \\[isearch-forward] for more information." +See the command `isearch-forward' for more information." (interactive "P\np") (isearch-mode nil (not (null regexp-p)) nil (not no-recursive-edit))) @@ -622,17 +719,11 @@ See \\[isearch-forward] for more information." "\ Do incremental search backward for regular expression. With a prefix argument, do a regular string search instead. -Like ordinary incremental search except that your input -is treated as a regexp. See \\[isearch-forward] for more info." +Like ordinary incremental search except that your input is treated +as a regexp. See the command `isearch-forward' for more information." (interactive "P\np") (isearch-mode nil (null not-regexp) nil (not no-recursive-edit))) - -(defun isearch-mode-help () - (interactive) - (describe-function 'isearch-forward) - (isearch-update)) - ;; isearch-mode only sets up incremental search for the minor mode. ;; All the work is done by the isearch-mode commands. @@ -644,9 +735,8 @@ is treated as a regexp. See \\[isearch-forward] for more info." (defun isearch-mode (forward &optional regexp op-fun recursive-edit word-p) - "Start isearch minor mode. Called by `isearch-forward', etc. - -\\{isearch-mode-map}" + "Start isearch minor mode. +It is called by the function `isearch-forward' and other related functions." ;; Initialize global vars. (setq isearch-forward forward @@ -1025,37 +1115,21 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst ;; that can change their values. (setq old-point (point) old-other-end isearch-other-end) - (isearch-message) ;; for read-char (unwind-protect - (let* (;; Why does following read-char echo? - ;;(echo-keystrokes 0) ;; not needed with above message - (e (let ((cursor-in-echo-area t)) - (read-event))) + (let* ((message-log-max nil) ;; Binding minibuffer-history-symbol to nil is a work-around ;; for some incompatibility with gmhist. - (minibuffer-history-symbol) - (message-log-max nil)) - ;; If the first character the user types when we prompt them - ;; for a string is the yank-word character, then go into - ;; word-search mode. Otherwise unread that character and - ;; read a key the normal way. - ;; Word search does not apply (yet) to regexp searches, - ;; no check is made here. - (message "%s" (isearch-message-prefix nil nil t)) - (if (memq (lookup-key isearch-mode-map (vector e)) - '(isearch-yank-word - isearch-yank-word-or-char)) - (setq isearch-word t;; so message-prefix is right - isearch-new-word t) - (cancel-kbd-macro-events) - (isearch-unread e)) - (setq cursor-in-echo-area nil) + (minibuffer-history-symbol)) (setq isearch-new-string (read-from-minibuffer (isearch-message-prefix nil nil isearch-nonincremental) isearch-string minibuffer-local-isearch-map nil - (if isearch-regexp 'regexp-search-ring 'search-ring) + (if isearch-regexp + (cons 'regexp-search-ring + (1+ (or regexp-search-ring-yank-pointer -1))) + (cons 'search-ring + (1+ (or search-ring-yank-pointer -1)))) nil t) isearch-new-message (mapconcat 'isearch-text-char-description @@ -1096,12 +1170,15 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst ;; Only the string actually used should be saved. )) - ;; Push the state as of before this C-s. - (isearch-push-state) + ;; 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 + ;; previous search (e.g. `isearch-success'), and part of variables + ;; are just entered from the minibuffer (e.g. `isearch-string'). + ;; (isearch-push-state) ;; Reinvoke the pending search. (isearch-search) - (isearch-push-state) + (isearch-push-state) ; this pushes the correct state (isearch-update) (if isearch-nonincremental (progn @@ -1116,6 +1193,15 @@ If first char entered is \\[isearch-yank-word-or-char], then do word search inst (isearch-abort) ;; outside of let to restore outside global values ))) +;; Obsolete usage of `C-s M-e C-w'. Remove after 23.1. +(defvar isearch-new-word) +(defun isearch-edit-string-set-word () + "Do word search after exiting `isearch-edit-string'." + (interactive) + (message "This feature is obsolete since 23.1; use `M-s w' instead.") + (setq isearch-word t isearch-new-word t)) + + (defun isearch-nonincremental-exit-minibuffer () (interactive) (setq isearch-nonincremental t) @@ -1229,6 +1315,13 @@ Use `isearch-exit' to quit without signaling." (setq isearch-success t isearch-adjusted t) (isearch-update)) +(defun isearch-toggle-word () + "Toggle word searching on or off." + (interactive) + (setq isearch-word (not isearch-word)) + (setq isearch-success t isearch-adjusted t) + (isearch-update)) + (defun isearch-toggle-case-fold () "Toggle case folding in searching on or off." (interactive) @@ -1243,16 +1336,27 @@ Use `isearch-exit' to quit without signaling." (sit-for 1) (isearch-update)) -(defun isearch-query-replace (&optional regexp-flag) - "Start `query-replace' with string to replace from last search string." - (interactive) +(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 +way to run word replacements from Isearch is `M-s w ... M-%'." + (interactive + (list current-prefix-arg)) (barf-if-buffer-read-only) (if regexp-flag (setq isearch-regexp t)) (let ((case-fold-search isearch-case-fold-search) ;; set `search-upper-case' to nil to not call ;; `isearch-no-upper-case-p' in `perform-replace' - (search-upper-case nil)) - (isearch-done) + (search-upper-case nil) + ;; 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. + ;; We call `exit-recursive-edit' explicitly at the end below. + (isearch-recursive-edit nil)) + (isearch-done nil t) (isearch-clean-overlays) (if (and isearch-other-end (< isearch-other-end (point)) @@ -1266,16 +1370,22 @@ Use `isearch-exit' to quit without signaling." isearch-string (query-replace-read-to isearch-string - (if isearch-regexp "Query replace regexp" "Query replace") + (concat "Query replace" + (if (or delimited isearch-word) " word" "") + (if isearch-regexp " regexp" "") + (if (and transient-mark-mode mark-active) " in region" "")) isearch-regexp) - t isearch-regexp isearch-word nil nil + 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)))) + (and isearch-recursive-edit (exit-recursive-edit))) -(defun isearch-query-replace-regexp () - "Start `query-replace-regexp' with string to replace from last search string." - (interactive) - (isearch-query-replace t)) +(defun isearch-query-replace-regexp (&optional delimited) + "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)) (defun isearch-occur (regexp &optional nlines) "Run `occur' with regexp to search from the current search string. @@ -1283,7 +1393,10 @@ Interactively, REGEXP is the current search regexp or a quoted search string. NLINES has the same meaning as in `occur'." (interactive (list - (if isearch-regexp isearch-string (regexp-quote isearch-string)) + (cond + (isearch-word (concat "\\b" (regexp-quote isearch-string) "\\b")) + (isearch-regexp isearch-string) + (t (regexp-quote isearch-string))) (if 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 @@ -1291,6 +1404,43 @@ string. NLINES has the same meaning as in `occur'." (search-upper-case nil)) (occur regexp nlines))) +(declare-function hi-lock-regexp-okay "hi-lock" (regexp)) +(declare-function hi-lock-read-face-name "hi-lock" ()) + +(defun isearch-highlight-regexp () + "Run `highlight-regexp' with regexp from the current search string. +It exits Isearch mode and calls `hi-lock-face-buffer' with its regexp +argument from the last search regexp or a quoted search string, +and reads its face argument using `hi-lock-read-face-name'." + (interactive) + (let ( + ;; 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. + ;; We call `exit-recursive-edit' explicitly at the end below. + (isearch-recursive-edit nil)) + (isearch-done nil t) + (isearch-clean-overlays)) + (require 'hi-lock nil t) + (let ((string (cond (isearch-regexp isearch-string) + ((if (and (eq isearch-case-fold-search t) + search-upper-case) + (isearch-no-upper-case-p + isearch-string isearch-regexp) + isearch-case-fold-search) + ;; Turn isearch-string into a case-insensitive + ;; regexp. + (mapconcat + (lambda (c) + (let ((s (string c))) + (if (string-match "[[:alpha:]]" s) + (format "[%s%s]" (upcase s) (downcase s)) + (regexp-quote s)))) + isearch-string "")) + (t (regexp-quote isearch-string))))) + (hi-lock-face-buffer string (hi-lock-read-face-name))) + (and isearch-recursive-edit (exit-recursive-edit))) + (defun isearch-delete-char () "Discard last input item and move point back. @@ -1573,13 +1723,12 @@ Scroll-bar or mode-line events are processed appropriately." ;; 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 'recenter-top-bottom 'isearch-scroll t) (put 'reposition-window 'isearch-scroll t) (put 'scroll-up 'isearch-scroll t) (put 'scroll-down 'isearch-scroll t) @@ -1834,7 +1983,7 @@ Isearch mode." "Convert return into newline for incremental search." (interactive) (isearch-process-search-char ?\n)) -(make-obsolete 'isearch-return-char 'isearch-printing-char) +(make-obsolete 'isearch-return-char 'isearch-printing-char "19.7") (defun isearch-printing-char () "Add this ordinary printing character to the search string and search." @@ -1895,10 +2044,12 @@ Isearch mode." (if search-ring-update (progn (isearch-search) + (isearch-push-state) (isearch-update)) - (isearch-edit-string) - ) - (isearch-push-state)) + ;; Otherwise, edit the search string instead. Note that there is + ;; no need to push the search state after isearch-edit-string here + ;; since isearch-edit-string already pushes its state + (isearch-edit-string))) (defun isearch-ring-advance () "Advance to the next search string in the ring." @@ -1975,9 +2126,13 @@ If there is no completion possible, say so and continue searching." (pop cmds)) (setq succ-msg (and cmds (isearch-message-state (car cmds))) m (copy-sequence m)) - (when (and (stringp succ-msg) (< (length succ-msg) (length m))) - (add-text-properties (length succ-msg) (length m) - '(face isearch-fail) 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) ;; Highlight failed trailing whitespace (when (string-match " +$" m) (add-text-properties (match-beginning 0) (match-end 0) @@ -2010,6 +2165,8 @@ If there is no completion possible, say so and continue searching." (if isearch-wrapped "wrapped ") (if isearch-word "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 @@ -2023,7 +2180,8 @@ If there is no completion possible, say so and continue searching." (concat (if c-q-hack "^Q" "") (if isearch-error (concat " [" isearch-error "]") - ""))) + "") + (or isearch-message-suffix-add ""))) ;; Searching @@ -2041,7 +2199,12 @@ Can be changed via `isearch-search-fun-function' for special needs." (funcall isearch-search-fun-function) (cond (isearch-word - (if isearch-forward 'word-search-forward 'word-search-backward)) + ;; Use lax versions to not fail at the end of the word while the user + ;; adds and removes characters in the search string + (if (not (eq (length isearch-string) + (length (isearch-string-state (car isearch-cmds))))) + (if isearch-forward 'word-search-forward-lax 'word-search-backward-lax) + (if isearch-forward 'word-search-forward 'word-search-backward))) (isearch-regexp (if isearch-forward 're-search-forward 're-search-backward)) (t @@ -2056,13 +2219,15 @@ Can be changed via `isearch-search-fun-function' for special needs." pos1 pos2) (setq pos1 (save-excursion (funcall func string bound noerror))) (if (and (char-table-p translation-table-for-input) - (> (string-bytes string) len)) - (let (translated match-data) - (dotimes (i len) - (let ((x (aref translation-table-for-input (aref string i)))) - (when x - (or translated (setq translated (copy-sequence string))) - (aset translated i x)))) + (multibyte-string-p string) + ;; Minor optimization. + (string-match-p "[^[:ascii:]]" string)) + (let ((translated + (apply 'string + (mapcar (lambda (c) + (or (aref translation-table-for-input c) c)) + string))) + match-data) (when translated (save-match-data (save-excursion @@ -2076,9 +2241,9 @@ Can be changed via `isearch-search-fun-function' for special needs." (when pos1 ;; When using multiple buffers isearch, switch to the new buffer here, ;; because `save-excursion' above doesn't allow doing it inside funcall. - (if (and isearch-buffers-next-buffer-function - (buffer-live-p isearch-buffers-current-buffer)) - (switch-to-buffer isearch-buffers-current-buffer)) + (if (and multi-isearch-next-buffer-current-function + (buffer-live-p multi-isearch-current-buffer)) + (switch-to-buffer multi-isearch-current-buffer)) (goto-char pos1)) pos1)) @@ -2091,7 +2256,9 @@ Can be changed via `isearch-search-fun-function' for special needs." (setq isearch-case-fold-search (isearch-no-upper-case-p isearch-string isearch-regexp))) (condition-case lossage - (let ((inhibit-point-motion-hooks search-invisible) + (let ((inhibit-point-motion-hooks + (and (eq isearch-success-function 'isearch-success-function-default) + search-invisible)) (inhibit-quit nil) (case-fold-search isearch-case-fold-search) (search-spaces-regexp search-whitespace-regexp) @@ -2102,12 +2269,11 @@ Can be changed via `isearch-search-fun-function' for special needs." (isearch-search-string isearch-string nil t)) ;; Clear RETRY unless we matched some invisible text ;; and we aren't supposed to do that. - (if (or (eq search-invisible t) - (not isearch-success) + (if (or (not isearch-success) (bobp) (eobp) (= (match-beginning 0) (match-end 0)) - (not (isearch-range-invisible - (match-beginning 0) (match-end 0)))) + (funcall isearch-success-function + (match-beginning 0) (match-end 0))) (setq retry nil))) (setq isearch-just-started nil) (if isearch-success @@ -2285,6 +2451,13 @@ Can be changed via `isearch-search-fun-function' for special needs." nil) (setq isearch-hidden t))))))) +(defun isearch-success-function-default (beg end) + "Default function to report if the new search match is successful. +Returns t if search can match hidden text, or otherwise checks if some +text from BEG to END is visible." + (or (eq search-invisible t) + (not (isearch-range-invisible beg end)))) + ;; General utilities @@ -2451,23 +2624,32 @@ by other Emacs features." (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-lazy-highlight-case-fold-search) - (isearch-regexp isearch-lazy-highlight-regexp) - (search-spaces-regexp isearch-lazy-highlight-space-regexp)) - (condition-case nil - (isearch-search-string - isearch-lazy-highlight-last-string - (if isearch-forward - (min (or isearch-lazy-highlight-end-limit (point-max)) + (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) + (search-invisible nil) ; don't match invisible text + (retry t) + (success nil) + (bound (if isearch-forward + (min (or isearch-lazy-highlight-end-limit (point-max)) + (if isearch-lazy-highlight-wrapped + isearch-lazy-highlight-start + (window-end))) + (max (or isearch-lazy-highlight-start-limit (point-min)) (if isearch-lazy-highlight-wrapped - isearch-lazy-highlight-start - (window-end))) - (max (or isearch-lazy-highlight-start-limit (point-min)) - (if isearch-lazy-highlight-wrapped - isearch-lazy-highlight-end - (window-start)))) - t) - (error nil)))) + isearch-lazy-highlight-end + (window-start)))))) + ;; Use a loop like in `isearch-search' + (while retry + (setq success (isearch-search-string + isearch-lazy-highlight-last-string bound t)) + (if (or (not success) + (funcall isearch-success-function + (match-beginning 0) (match-end 0))) + (setq retry nil))) + success) + (error nil))) (defun isearch-lazy-highlight-update () "Update highlighting of other matches for current search."