;;; Ishl.el --- extra isearch highlighting ;; Copyright 1997 Bob Glickstein. ;; Author: Bob Glickstein ;; Maintainer: Bob Glickstein ;; Version: 1.5 ;; This file is not part of GNU Emacs. ;; This file 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 2, or (at your ;; option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; 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, send e-mail to ;; this program's maintainer or write to the Free Software Foundation, ;; Inc., 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA. ;;; Plug: ;; Check out my book, "Writing GNU Emacs Extensions," from O'Reilly ;; and Associates. ;;; Commentary: ;; `ishl-mode' is a mode that does additional highlighting during ;; incremental searches. Using the relatively unobtrusive "secondary ;; selection" face, ishl highlights *every* match for the current ;; search string. (Of course, the *current* match remains highlighted ;; with the "region" face.) It does this in a deferred fashion using ;; idle timers, so the cycles needed to highlight additional matches ;; do not rob isearch of its usual snappy response. ;; The additional 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 forward or backward. ;; Each time the search string is changed, ishl-mode waits ;; `ishl-initial-delay' seconds, then starts highlighting matches one ;; every `ishl-delay' seconds. These numbers are 1/4 and 1/16 by ;; default. ;;; To do: ;; Define an "ishl" face. ;;; Code: (require 'timer) (defconst ishl-version "1.4" "Version number of ishl.") (defvar ishl-overlays nil) (defvar ishl-wrapped nil) (defvar ishl-start nil) (defvar ishl-end nil) (defvar ishl-timer nil) (defvar ishl-last-string nil) (defvar ishl-initial-delay 0.25 "*Seconds before starting to highlight additional matches.") (defvar ishl-delay 0.0625 "*Seconds between highlighting additional matches.") (defvar ishl-cleanup t "*Whether to remove highlighting after a search.") (defun ishl-cleanup (&optional force) (interactive '(t)) (if (or force ishl-cleanup) (ishl-remove-overlays)) (if ishl-timer (cancel-timer ishl-timer))) (defun ishl-new-loop () (if (not (equal isearch-string ishl-last-string)) (progn (ishl-cleanup t) (if (and isearch-overlay (not (overlay-get isearch-overlay 'priority))) (overlay-put isearch-overlay 'priority 1)) (setq ishl-start isearch-opoint ishl-end isearch-opoint ishl-last-string isearch-string ishl-wrapped nil ishl-timer (run-with-idle-timer ishl-initial-delay nil 'ishl-update))))) (defun ishl-remove-overlays () (while ishl-overlays (delete-overlay (car ishl-overlays)) (setq ishl-overlays (cdr ishl-overlays)))) (defun ishl-search () (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 ishl-wrapped ishl-start nil) (if ishl-wrapped ishl-end nil)) t))) (defun ishl-update () (if isearch-invalid-regexp nil (save-excursion (save-match-data (goto-char (if isearch-forward ishl-end ishl-start)) (let ((found (ishl-search))) (if found (let ((ov (make-overlay (match-beginning 0) (match-end 0)))) (overlay-put ov 'face 'secondary-selection) (overlay-put ov 'priority 0) (setq ishl-overlays (cons ov ishl-overlays) ishl-timer (run-at-time ishl-delay nil 'ishl-update)) (if isearch-forward (setq ishl-end (point)) (setq ishl-start (point)))) (if ishl-wrapped nil (setq ishl-wrapped t ishl-timer (run-at-time ishl-delay nil 'ishl-update)) (if isearch-forward (setq ishl-end (point-min)) (setq ishl-start (point-max)))))))))) (defadvice isearch-update (after ishl-start-loop compile) (ishl-new-loop)) (defvar ishl-mode nil) (defun ishl-mode (&optional arg) "Highlight additional incremental search matches." (interactive "P") (setq ishl-mode (if (null arg) (not ishl-mode) (> (prefix-numeric-value arg) 0))) (if ishl-mode (progn (ad-activate 'isearch-update t) (add-hook 'isearch-mode-end-hook 'ishl-cleanup)) (ad-deactivate 'isearch-update) (remove-hook 'isearch-mode-end-hook 'ishl-cleanup))) (define-key global-map "\C-c\C-l" 'ishl-cleanup) (provide 'ishl) ;;; ishl.el ends here