Commit 44336afb authored by Gerd Moellmann's avatar Gerd Moellmann
Browse files

Add lazy highlighting.

parent 87be76f6
1999-11-11 Gerd Moellmann <>
* isearch.el: Add lazy-highlighting feature.
1999-11-10 Peter Kleiweg <>
* progmodes/ps-mode.el (ps-mode-maintainer-address): New
......@@ -613,7 +613,7 @@ is treated as a regexp. See \\[isearch-forward] for more info."
(setq ;; quit-flag nil not for isearch-mode
isearch-adjusted nil
isearch-yank-flag nil)
(defun isearch-done (&optional nopush edit)
(remove-hook 'mouse-leave-buffer-hook 'isearch-done)
......@@ -622,6 +622,7 @@ is treated as a regexp. See \\[isearch-forward] for more info."
(setq overriding-terminal-local-map nil)
;; (setq pre-command-hook isearch-old-pre-command-hook) ; for lemacs
(isearch-dehighlight t)
(let ((found-start (window-start (selected-window)))
(found-point (point)))
(if isearch-window-configuration
......@@ -1741,4 +1742,176 @@ since they have special meaning in a regexp."
(setq unread-command-events
(append char-or-events unread-command-events)))
;;; isearch-lazy-highlight feature
;;; by Bob Glickstein <>
;;; When active, *every* match for the current search string is
;;; highlighted: the current one using the normal isearch match color
;;; and all the others using the unobtrusive `secondary-selection'
;;; color. The extra highlighting makes it easier to anticipate where
;;; the cursor will land each time you press C-s or C-r to repeat a
;;; pending search. Highlighting of these additional matches happens
;;; in a deferred fashion using "idle timers," so the cycles needed do
;;; not rob isearch of its usual snappy response.
;;; IMPLEMENTATION NOTE: This depends on some isearch internals.
;;; Specifically:
;;; - `isearch-update' is expected to be called (at least) every time
;;; the search string changes;
;;; - `isearch-string' is expected to contain the current search
;;; string as entered by the user;
;;; - `isearch-overlay' is expected to contain the overlay used for
;;; primary isearch match-highlighting;
;;; - `isearch-opoint' is expected to contain the location where the
;;; current search began;
;;; - the type of the current search is expected to be given by
;;; `isearch-word' and `isearch-regexp';
;;; - the direction of the current search is expected to be given by
;;; `isearch-forward';
;;; - the variable `isearch-invalid-regexp' is expected to be true
;;; iff `isearch-string' is an invalid regexp.
(require 'timer)
(defgroup isearch-lazy-highlight nil
"Lazy highlighting feature for incremental search."
:prefix "isearch-lazy-highlight-"
:group 'isearch)
(defcustom isearch-lazy-highlight t
"*Controls the lazy-highlighting during incremental searches.
When non-nil, all text in the buffer matching the current search
string is highlighted lazily (see `isearch-lazy-highlight-initial-delay'
and `isearch-lazy-highlight-interval')."
:type 'boolean
:group 'isearch-lazy-highlight)
(defcustom isearch-lazy-highlight-cleanup t
"*Controls whether to remove extra highlighting after a search.
If this is nil, extra highlighting can be \"manually\" removed with
:type 'boolean
:group 'isearch-lazy-highlight)
(defcustom isearch-lazy-highlight-initial-delay 0.25
"*Seconds to wait before beginning to lazily highlight all matches."
:type 'number
:group 'isearch-lazy-highlight)
(defcustom isearch-lazy-highlight-interval 0.0625
"*Seconds between lazily highlighting successive matches."
:type 'number
:group 'isearch-lazy-highlight)
(defcustom isearch-lazy-highlight-face 'secondary-selection
"*Face to use for lazily highlighting all matches."
:type 'face
:group 'isearch-lazy-highlight)
(defvar isearch-lazy-highlight-overlays nil)
(defvar isearch-lazy-highlight-wrapped nil)
(defvar isearch-lazy-highlight-start nil)
(defvar isearch-lazy-highlight-end nil)
(defvar isearch-lazy-highlight-timer nil)
(defvar isearch-lazy-highlight-last-string nil)
(defun isearch-lazy-highlight-cleanup (&optional force)
"Stop lazy highlighting and remove extra highlighting from current buffer.
FORCE non-nil means do it whether or not `isearch-lazy-highlight-cleanup'
is nil. This function is called when exiting an incremental search if
`isearch-lazy-highlight-cleanup' is non-nil."
(interactive '(t))
(if (or force isearch-lazy-highlight-cleanup)
(if isearch-lazy-highlight-timer
(cancel-timer isearch-lazy-highlight-timer)
(setq isearch-lazy-highlight-timer nil))))
(defun isearch-lazy-highlight-remove-overlays ()
"Remove lazy highlight overlays from the current buffer."
(while isearch-lazy-highlight-overlays
(delete-overlay (car isearch-lazy-highlight-overlays))
(setq isearch-lazy-highlight-overlays
(cdr isearch-lazy-highlight-overlays))))
(defun isearch-lazy-highlight-new-loop ()
"Cleanup any previous isearch-lazy-highlight loop and begin a new one.
This happens when `isearch-update' is invoked (which can cause the
search string to change)."
(if (and isearch-lazy-highlight
(not (equal isearch-string isearch-lazy-highlight-last-string)))
;; the search string did indeed change
(isearch-lazy-highlight-cleanup t) ;kill old loop & remove overlays
(if (and isearch-overlay
(not (overlay-get isearch-overlay 'priority)))
;; make sure the isearch-overlay takes priority
(overlay-put isearch-overlay 'priority 1))
(setq isearch-lazy-highlight-start isearch-opoint
isearch-lazy-highlight-end isearch-opoint
isearch-lazy-highlight-last-string isearch-string
isearch-lazy-highlight-wrapped nil)
(setq isearch-lazy-highlight-timer
(run-with-idle-timer isearch-lazy-highlight-initial-delay nil
(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-case-fold-search))
(funcall (cond (isearch-word (if isearch-forward
(isearch-regexp (if isearch-forward
(t (if isearch-forward
(if isearch-forward
(if isearch-lazy-highlight-wrapped
(if isearch-lazy-highlight-wrapped
(defun isearch-lazy-highlight-update ()
"Find and highlight the next match in the lazy highlighting loop."
(when (not isearch-invalid-regexp)
(goto-char (if isearch-forward
(let ((found (isearch-lazy-highlight-search))) ;do search
(if found
;; found the next match
(let ((ov (make-overlay (match-beginning 0)
(match-end 0))))
(overlay-put ov 'face isearch-lazy-highlight-face)
(overlay-put ov 'priority 0)
(setq isearch-lazy-highlight-overlays
(cons ov isearch-lazy-highlight-overlays))
(setq isearch-lazy-highlight-timer
(run-at-time isearch-lazy-highlight-interval nil
(if isearch-forward
(setq isearch-lazy-highlight-end (point))
(setq isearch-lazy-highlight-start (point))))
;; found no next match
(when (not isearch-lazy-highlight-wrapped)
;; let's try wrapping around the end of the buffer
(setq isearch-lazy-highlight-wrapped t)
(setq isearch-lazy-highlight-timer
(run-at-time isearch-lazy-highlight-interval nil
(if isearch-forward
(setq isearch-lazy-highlight-end (point-min))
(setq isearch-lazy-highlight-start (point-max))))))))))
;;; isearch.el ends here
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment