bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#29360: 26.0; Add full-buffer choice for `isearch-lazy-highlight'


From: Juri Linkov
Subject: bug#29360: 26.0; Add full-buffer choice for `isearch-lazy-highlight'
Date: Thu, 25 Oct 2018 02:11:25 +0300
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (x86_64-pc-linux-gnu)

> Absolutely.  Like with any similar interaction in
> Emacs the delay before starting should be a user
> option.  Users are different, and user machines etc.
> are different.

You are right, with a small delay lazy-highlighting is responsive.

In the attached patch I also added a separate variable that you asked for
programmatic use, changed text to "currently visible on the screen" and
mentioned lazy-highlight-cleanup.

The patch is extensively tested for various scenarios:

diff --git a/lisp/isearch.el b/lisp/isearch.el
index 1e785a44c5..dae85208cb 100644
--- a/lisp/isearch.el
+++ b/lisp/isearch.el
@@ -304,9 +304,9 @@ 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
-string is highlighted lazily (see `lazy-highlight-initial-delay'
-and `lazy-highlight-interval').
+When non-nil, all text currently visible on the screen
+matching the current search string is highlighted lazily
+(see `lazy-highlight-initial-delay' and `lazy-highlight-interval').
 
 When multiple windows display the current buffer, the
 highlighting is displayed only on the selected window, unless
@@ -316,6 +316,17 @@ isearch-lazy-highlight
   :group 'lazy-highlight
   :group 'isearch)
 
+(defcustom isearch-lazy-highlight-buffer nil
+  "Controls the lazy-highlighting of the full 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').
+This is useful when `lazy-highlight-cleanup' is customized to nil
+and doesn't remove full-buffer highlighting after a search."
+  :type 'boolean
+  :group 'lazy-highlight
+  :group 'isearch)
+
 ;;; Lazy highlight customization.
 
 (defgroup lazy-highlight nil
@@ -351,6 +362,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"))
@@ -3178,6 +3198,7 @@ isearch-lazy-highlight-window
 (defvar isearch-lazy-highlight-window-group nil)
 (defvar isearch-lazy-highlight-window-start nil)
 (defvar isearch-lazy-highlight-window-end nil)
+(defvar isearch-lazy-highlight-buffer-p nil)
 (defvar isearch-lazy-highlight-case-fold-search nil)
 (defvar isearch-lazy-highlight-regexp nil)
 (defvar isearch-lazy-highlight-lax-whitespace nil)
@@ -3226,10 +3247,12 @@ isearch-lazy-highlight-new-loop
                          isearch-lax-whitespace))
                 (not (eq isearch-lazy-highlight-regexp-lax-whitespace
                          isearch-regexp-lax-whitespace))
-                 (not (= (window-group-start)
-                         isearch-lazy-highlight-window-start))
-                 (not (= (window-group-end) ; Window may have been 
split/joined.
-                        isearch-lazy-highlight-window-end))
+                (not (or isearch-lazy-highlight-buffer-p
+                         (= (window-group-start)
+                            isearch-lazy-highlight-window-start)))
+                (not (or isearch-lazy-highlight-buffer-p
+                         (= (window-group-end) ; Window may have been 
split/joined.
+                            isearch-lazy-highlight-window-end)))
                 (not (eq isearch-forward
                          isearch-lazy-highlight-forward))
                 ;; In case we are recovering from an error.
@@ -3247,6 +3270,7 @@ isearch-lazy-highlight-new-loop
           isearch-lazy-highlight-window-group (selected-window-group)
          isearch-lazy-highlight-window-start (window-group-start)
          isearch-lazy-highlight-window-end   (window-group-end)
+         isearch-lazy-highlight-buffer-p     isearch-lazy-highlight-buffer
          ;; Start lazy-highlighting at the beginning of the found
          ;; match (`isearch-other-end').  If no match, use point.
          ;; One of the next two variables (depending on search direction)
@@ -3264,12 +3288,22 @@ isearch-lazy-highlight-new-loop
          isearch-lazy-highlight-regexp-lax-whitespace 
isearch-regexp-lax-whitespace
          isearch-lazy-highlight-regexp-function  isearch-regexp-function
          isearch-lazy-highlight-forward      isearch-forward)
+    ;; Extend start/end to match whole string at point
+    (if isearch-lazy-highlight-forward
+        (setq isearch-lazy-highlight-start
+             (min (+ isearch-lazy-highlight-start
+                     (1- (length isearch-lazy-highlight-last-string)))
+                  (point-max)))
+      (setq isearch-lazy-highlight-end
+           (max (- isearch-lazy-highlight-end
+                   (1- (length isearch-lazy-highlight-last-string)))
+                (point-min))))
     (unless (equal isearch-string "")
       (setq isearch-lazy-highlight-timer
             (run-with-idle-timer lazy-highlight-initial-delay nil
                                  'isearch-lazy-highlight-start)))))
 
-(defun isearch-lazy-highlight-search ()
+(defun isearch-lazy-highlight-search (string bound)
   "Search ahead for the next or previous match, for lazy highlighting.
 Attempt to do the search exactly the way the pending Isearch would."
   (condition-case nil
@@ -3283,24 +3317,10 @@ isearch-lazy-highlight-search
            (isearch-forward isearch-lazy-highlight-forward)
            (search-invisible nil)      ; don't match invisible text
            (retry t)
-           (success nil)
-           (bound (if isearch-lazy-highlight-forward
-                      (min (or isearch-lazy-highlight-end-limit (point-max))
-                           (if isearch-lazy-highlight-wrapped
-                               (+ isearch-lazy-highlight-start
-                                  ;; Extend bound to match whole string at 
point
-                                  (1- (length 
isearch-lazy-highlight-last-string)))
-                             (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))))))
+           (success nil))
        ;; Use a loop like in `isearch-search'.
        (while retry
-         (setq success (isearch-search-string
-                        isearch-lazy-highlight-last-string bound t))
+         (setq success (isearch-search-string string bound t))
          ;; Clear RETRY unless the search predicate says
          ;; to skip this search hit.
          (if (or (not success)
@@ -3312,6 +3332,20 @@ isearch-lazy-highlight-search
        success)
     (error nil)))
 
+(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-start ()
   "Start a new lazy-highlight updating loop."
   (lazy-highlight-cleanup t) ;remove old overlays
@@ -3321,19 +3355,32 @@ isearch-lazy-highlight-update
   "Update highlighting of other matches for current search."
   (let ((max lazy-highlight-max-at-a-time)
         (looping t)
-        nomore)
+        nomore window-start window-end)
     (with-local-quit
       (save-selected-window
        (if (and (window-live-p isearch-lazy-highlight-window)
                 (not (memq (selected-window) 
isearch-lazy-highlight-window-group)))
            (select-window isearch-lazy-highlight-window))
+       (setq window-start (window-group-start))
+       (setq window-end (window-group-end))
        (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)))
+             (let* ((bound (if isearch-lazy-highlight-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-end
+                                    window-start))))
+                    (found (isearch-lazy-highlight-search
+                            isearch-lazy-highlight-last-string
+                            bound)))
                (when max
                  (setq max (1- max))
                  (if (<= max 0)
@@ -3345,24 +3392,16 @@ isearch-lazy-highlight-update
                          (if isearch-lazy-highlight-forward
                              (if (= mb (if isearch-lazy-highlight-wrapped
                                            isearch-lazy-highlight-start
-                                         (window-group-end)))
+                                         window-end))
                                  (setq found nil)
                                (forward-char 1))
                            (if (= mb (if isearch-lazy-highlight-wrapped
                                          isearch-lazy-highlight-end
-                                       (window-group-start)))
+                                       window-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.
@@ -3378,17 +3417,83 @@ isearch-lazy-highlight-update
                      (setq isearch-lazy-highlight-wrapped t)
                      (if isearch-lazy-highlight-forward
                          (progn
-                           (setq isearch-lazy-highlight-end 
(window-group-start))
+                           (setq isearch-lazy-highlight-end window-start)
                            (goto-char (max (or 
isearch-lazy-highlight-start-limit (point-min))
-                                           (window-group-start))))
-                       (setq isearch-lazy-highlight-start (window-group-end))
+                                           window-start)))
+                       (setq isearch-lazy-highlight-start window-end)
                        (goto-char (min (or isearch-lazy-highlight-end-limit 
(point-max))
-                                       (window-group-end))))))))
-           (unless nomore
+                                       window-end)))))))
+           (if nomore
+               (when isearch-lazy-highlight-buffer-p
+                 (if isearch-lazy-highlight-forward
+                     (setq isearch-lazy-highlight-end (point-min))
+                   (setq isearch-lazy-highlight-start (point-max)))
+                 (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 window-start window-end)
+    (with-local-quit
+      (save-selected-window
+       (if (and (window-live-p isearch-lazy-highlight-window)
+                (not (memq (selected-window) 
isearch-lazy-highlight-window-group)))
+           (select-window isearch-lazy-highlight-window))
+       (setq window-start (window-group-start))
+       (setq window-end (window-group-end))
+       (save-excursion
+         (save-match-data
+           (goto-char (if isearch-lazy-highlight-forward
+                          isearch-lazy-highlight-end
+                        isearch-lazy-highlight-start))
+           (while looping
+             (let* ((bound (if isearch-lazy-highlight-forward
+                               (or isearch-lazy-highlight-end-limit 
(point-max))
+                             (or isearch-lazy-highlight-start-limit 
(point-min))))
+                    (found (isearch-lazy-highlight-search
+                            isearch-lazy-highlight-last-string
+                            bound)))
+               (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 (point-max))
+                                 (setq found nil)
+                               (forward-char 1))
+                           (if (= mb (point-min))
+                               (setq found nil)
+                             (forward-char -1)))
+                       ;; Already highlighted by isearch-lazy-highlight-update
+                       (unless (or (and (>= mb window-start) (<= me 
window-end))
+                                    (not isearch-lazy-highlight-buffer-p))
+                         ;; 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-buffer-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)
+                   (setq looping nil
+                         nomore  t))))
+           (unless nomore
+             (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.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]