*** ~//xemacs-21.1/lisp/isearch-mode.el Tue Jun 15 15:37:30 1999 --- isearch-mode.el Tue Jul 27 17:21:29 1999 *************** *** 70,75 **** --- 70,94 ---- ;;==================================================================== ;;; Change History: + ;; 27-Jul-99 (Darryl Okahata ) Merged Bob Glickstein's + ;; GNU Emacs isearch enhancements. From his release + ;; message: + ;; + ;; ** New feature in incremental search: "lazy highlighting," controlled + ;; by the variable `isearch-lazy-highlight'. 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. New default keybinding: M-C for clearing the + ;; extra highlighting (which normally happens automatically unless you + ;; turn off `isearch-lazy-highlight-cleanup'). + ;; + ;; Bob's code was modified to use extents instead of overlays. + ;; Header: /import/kaplan/kaplan/liberte/Isearch/RCS/isearch-mode.el,v 1.3 92/06/29 13:10:08 liberte Exp Locker: liberte ;; Log: isearch-mode.el,v ;; *************** *** 528,533 **** --- 547,553 ---- (setq ;; quit-flag nil not for isearch-mode isearch-adjusted nil isearch-yank-flag nil) + (isearch-lazy-highlight-new-loop) ) *************** *** 551,557 **** (set-keymap-parents isearch-mode-map nil) (setq isearch-mode nil) (set-buffer-modified-p (buffer-modified-p));; update modeline ! (isearch-dehighlight t))) ;; it's not critical that this be inside inhibit-quit, but leaving ;; things in small-window-mode would be bad. --- 571,579 ---- (set-keymap-parents isearch-mode-map nil) (setq isearch-mode nil) (set-buffer-modified-p (buffer-modified-p));; update modeline ! (isearch-dehighlight t) ! (isearch-lazy-highlight-cleanup) ! )) ;; it's not critical that this be inside inhibit-quit, but leaving ;; things in small-window-mode would be bad. *************** *** 1622,1626 **** --- 1644,1825 ---- ,@body)) (put 'with-caps-disable-folding 'lisp-indent-function 1) (put 'with-caps-disable-folding 'edebug-form-spec '(form body)) + + + ;;; isearch-lazy-highlight feature + ;;; (formerly "ishl") + ;;; 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-extent' is expected to contain the extent 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-highlight behavior of incremental search. + 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 + \\[isearch-lazy-highlight-cleanup]." + :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-extents 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 lazily highlighting and remove extra highlighting from buffer. + This happens automatically when exiting an incremental search if + `isearch-lazy-highlight-cleanup' is non-nil." + (interactive '(t)) + (if (or force isearch-lazy-highlight-cleanup) + (isearch-lazy-highlight-remove-extents)) + (if isearch-lazy-highlight-timer + (progn + (cancel-timer isearch-lazy-highlight-timer) + (setq isearch-lazy-highlight-timer nil)))) + + (defun isearch-lazy-highlight-remove-extents () + "Remove lazy highlight extents from the buffer." + (while isearch-lazy-highlight-extents + (delete-extent (car isearch-lazy-highlight-extents)) + (setq isearch-lazy-highlight-extents + (cdr isearch-lazy-highlight-extents)))) + + (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 + (progn + (isearch-lazy-highlight-cleanup t) ;kill old loop & remove extents + (if (and isearch-extent + (not (extent-property isearch-extent 'priority))) + ;; make sure the isearch-extent takes priority + (set-extent-priority isearch-extent '(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 + 'isearch-lazy-highlight-update))))) + + (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 + 'word-search-forward + 'word-search-backward)) + (isearch-regexp (if isearch-forward + 're-search-forward + 're-search-backward)) + (t (if isearch-forward + 'search-forward + 'search-backward))) + isearch-string + (if isearch-forward + (if isearch-lazy-highlight-wrapped + isearch-lazy-highlight-start + nil) + (if isearch-lazy-highlight-wrapped + isearch-lazy-highlight-end + nil)) + t))) + + (defun isearch-lazy-highlight-update () + "Find and highlight the next match in the lazy highlighting loop." + (when (not isearch-invalid-regexp) + (save-excursion + (save-match-data + (goto-char (if isearch-forward + isearch-lazy-highlight-end + isearch-lazy-highlight-start)) + (let ((found (isearch-lazy-highlight-search))) ;do search + (if found + ;; found the next match + (let ((ext (make-extent (match-beginning 0) + (match-end 0)))) + (set-extent-properties ext + (list + 'face isearch-lazy-highlight-face + 'priority 0)) + (setq isearch-lazy-highlight-extents + (cons ext isearch-lazy-highlight-extents)) + (setq isearch-lazy-highlight-timer + (run-at-time isearch-lazy-highlight-interval nil + 'isearch-lazy-highlight-update)) + (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 + 'isearch-lazy-highlight-update)) + (if isearch-forward + (setq isearch-lazy-highlight-end (point-min)) + (setq isearch-lazy-highlight-start (point-max)))))))))) + + (define-key esc-map "C" 'isearch-lazy-highlight-cleanup) ;;; isearch-mode.el ends here