diff --git a/lisp/isearch.el b/lisp/isearch.el index 1e785a44c5..cb9e72526b 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -304,7 +304,7 @@ isearch-fail (defcustom isearch-lazy-highlight t "Controls the lazy-highlighting during incremental search. -When non-nil, all text in the buffer matching the current search +When non-nil, all text on the screen matching the current search string is highlighted lazily (see `lazy-highlight-initial-delay' and `lazy-highlight-interval'). @@ -316,6 +316,15 @@ isearch-lazy-highlight :group 'lazy-highlight :group 'isearch) +(defcustom isearch-lazy-highlight-buffer nil + "Controls the lazy-highlighting of the whole buffer. +When non-nil, all text in the buffer matching the current search +string is highlighted lazily (see `lazy-highlight-initial-delay', +`lazy-highlight-interval' and `lazy-highlight-buffer-max-at-a-time')." + :type 'boolean + :group 'lazy-highlight + :group 'isearch) + ;;; Lazy highlight customization. (defgroup lazy-highlight nil @@ -351,6 +360,15 @@ lazy-highlight-max-at-a-time (integer :tag "Some")) :group 'lazy-highlight) +(defcustom lazy-highlight-buffer-max-at-a-time 20 + "Maximum matches to highlight at a time (for `isearch-lazy-highlight-buffer'). +Larger values may reduce Isearch's responsiveness to user input; +smaller values make matches highlight slowly. +A value of nil means highlight all matches shown in the buffer." + :type '(choice (const :tag "All" nil) + (integer :tag "Some")) + :group 'lazy-highlight) + (defface lazy-highlight '((((class color) (min-colors 88) (background light)) (:background "paleturquoise")) @@ -3290,13 +3308,13 @@ isearch-lazy-highlight-search (+ isearch-lazy-highlight-start ;; Extend bound to match whole string at point (1- (length isearch-lazy-highlight-last-string))) - (window-group-end))) + (if isearch-lazy-highlight-buffer (point-max) (window-group-end)))) (max (or isearch-lazy-highlight-start-limit (point-min)) (if isearch-lazy-highlight-wrapped (- isearch-lazy-highlight-end ;; Extend bound to match whole string at point (1- (length isearch-lazy-highlight-last-string))) - (window-group-start)))))) + (if isearch-lazy-highlight-buffer (point-min) (window-group-start))))))) ;; Use a loop like in `isearch-search'. (while retry (setq success (isearch-search-string @@ -3317,6 +3335,20 @@ isearch-lazy-highlight-start (lazy-highlight-cleanup t) ;remove old overlays (isearch-lazy-highlight-update)) +(defvar isearch-lazy-highlight-match-function #'isearch-lazy-highlight-match + "Function that highlights the found match. +The function accepts two arguments: the beginning and the end of the match.") + +(defun isearch-lazy-highlight-match (mb me) + (let ((ov (make-overlay mb me))) + (push ov isearch-lazy-highlight-overlays) + ;; 1000 is higher than ediff's 100+, + ;; but lower than isearch main overlay's 1001 + (overlay-put ov 'priority 1000) + (overlay-put ov 'face 'lazy-highlight) + (unless (eq isearch-lazy-highlight 'all-windows) + (overlay-put ov 'window (selected-window))))) + (defun isearch-lazy-highlight-update () "Update highlighting of other matches for current search." (let ((max lazy-highlight-max-at-a-time) @@ -3353,16 +3385,8 @@ isearch-lazy-highlight-update (window-group-start))) (setq found nil) (forward-char -1))) - ;; non-zero-length match - (let ((ov (make-overlay mb me))) - (push ov isearch-lazy-highlight-overlays) - ;; 1000 is higher than ediff's 100+, - ;; but lower than isearch main overlay's 1001 - (overlay-put ov 'priority 1000) - (overlay-put ov 'face 'lazy-highlight) - (unless (eq isearch-lazy-highlight 'all-windows) - (overlay-put ov 'window (selected-window))))) + (funcall isearch-lazy-highlight-match-function mb me)) ;; Remember the current position of point for ;; the next call of `isearch-lazy-highlight-update' ;; when `lazy-highlight-max-at-a-time' is too small. @@ -3384,11 +3408,75 @@ isearch-lazy-highlight-update (setq isearch-lazy-highlight-start (window-group-end)) (goto-char (min (or isearch-lazy-highlight-end-limit (point-max)) (window-group-end)))))))) - (unless nomore + (if nomore + (when isearch-lazy-highlight-buffer + (setq isearch-lazy-highlight-start (window-group-start)) + (setq isearch-lazy-highlight-end (window-group-end)) + (setq isearch-lazy-highlight-wrapped nil) + (run-at-time lazy-highlight-interval nil + 'isearch-lazy-highlight-buffer-update)) (setq isearch-lazy-highlight-timer (run-at-time lazy-highlight-interval nil 'isearch-lazy-highlight-update))))))))) +(defun isearch-lazy-highlight-buffer-update () + "Update highlighting of other matches in the whole buffer." + (let ((max lazy-highlight-buffer-max-at-a-time) + (looping t) + nomore) + (with-local-quit + (save-excursion + (save-match-data + (goto-char (if isearch-lazy-highlight-forward + isearch-lazy-highlight-end + isearch-lazy-highlight-start)) + (while looping + (let ((found (isearch-lazy-highlight-search))) + (when max + (setq max (1- max)) + (if (<= max 0) + (setq looping nil))) + (if found + (let ((mb (match-beginning 0)) + (me (match-end 0))) + (if (= mb me) ;zero-length match + (if isearch-lazy-highlight-forward + (if (= mb (if isearch-lazy-highlight-wrapped + (window-group-start) + (point-max))) + (setq found nil) + (forward-char 1)) + (if (= mb (if isearch-lazy-highlight-wrapped + (window-group-end) + (point-min))) + (setq found nil) + (forward-char -1))) + ;; non-zero-length match + (funcall isearch-lazy-highlight-match-function mb me)) + ;; Remember the current position of point for + ;; the next call of `isearch-lazy-highlight-update' + ;; when `lazy-highlight-max-at-a-time' is too small. + (if isearch-lazy-highlight-forward + (setq isearch-lazy-highlight-end (point)) + (setq isearch-lazy-highlight-start (point))))) + ;; not found or zero-length match at the search bound + (if (not found) + (if isearch-lazy-highlight-wrapped + (setq looping nil + nomore t) + (setq isearch-lazy-highlight-wrapped t) + (if isearch-lazy-highlight-forward + (progn + (setq isearch-lazy-highlight-end (point-min)) + (goto-char (point-min))) + (setq isearch-lazy-highlight-start (point-max)) + (goto-char (point-max))))))) + (if nomore + (message "Finished lazy-highlighting the buffer") + (setq isearch-lazy-highlight-timer + (run-at-time lazy-highlight-interval nil + 'isearch-lazy-highlight-buffer-update)))))))) + (defun isearch-resume (string regexp word forward message case-fold) "Resume an incremental search. STRING is the string or regexp searched for.