1;;; highlight-symbol.el --- automatic and manual symbol highlighting
3;; Copyright (C) 2007 Nikolaj Schumacher <bugs * nschum , de>
5;;; License ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7;; This program is free software; you can redistribute it and/or
8;; modify it under the terms of the GNU General Public License
9;; as published by the Free Software Foundation; either version 2
10;; of the License, or (at your option) any later version.
12;; This program is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
17;; You should have received a copy of the GNU General Public License
18;; along with this program; if not, write to the Free Software
19;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21;;; Configuration ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23;; Add the following to your .emacs file:
25;; (require 'highlight-symbol)
26;; (global-set-key [(control f3)] 'highlight-symbol-at-point)
27;; (global-set-key [f3] 'highlight-symbol-next)
28;; (global-set-key [(shift f3)] 'highlight-symbol-prev)
29;; (global-set-key [(meta f3)] 'highlight-symbol-prev)))
31;;; Usage ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
33;; Use `highlight-symbol-at-point' to toggle highlighting of the symbol at
34;; point throughout the current buffer. Use `highlight-symbol-mode' to keep the
35;; symbol at point highlighted.
37;; The functions `highlight-symbol-next', `highlight-symbol-prev',
38;; `highlight-symbol-next-in-defun' and `highlight-symbol-prev-in-defun' allow
39;; for cycling through the locations of any symbol at point.
41;;; Changes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
44;; Fixed bug in `highlight-symbol-jump'. (thanks to Per Nordlöw)
49;;; Customizable Variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
51(defgroup highlight-symbol nil
52 "Automatic and manual symbols highlighting"
55(defface highlight-symbol-face
56 '((((class color) (background dark))
57 (:background "gray30"))
58 (((class color) (background light))
59 (:background "gray90")))
60 "*Face used by `highlight-symbol-mode'."
61 :group 'highlight-symbol)
63(defcustom highlight-symbol-idle-delay 1.5
64 "*Number of seconds of idle time before highlighting the current symbol.
65If this variable is set to 0, no idle time is required.
66Changing this does not take effect until `highlight-symbol-mode' has been
67disabled for all buffers."
69 :group 'highlight-symbol)
71(defvar highlight-symbol-faces '('hi-yellow 'hi-pink 'hi-green 'hi-blue)
72 "The faces that, in this order, will be used for `highlight-symbol-at-point'.
73This list will be rotated after each call to `highlight-symbol-at-point', so
74that the first element will go to the end.")
76;;; Interactive Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
79(define-minor-mode highlight-symbol-mode
80 "Minor mode that highlights the symbol under point throughout the buffer.
81Highlighting takes place after `highlight-symbol-idle-delay'."
85 (if highlight-symbol-mode
88 (add-to-list 'highlight-symbol-instances (current-buffer))
89 (unless highlight-symbol-timer
90 (setq highlight-symbol-timer
91 (when (and highlight-symbol-idle-delay
92 (/= highlight-symbol-idle-delay 0))
93 (run-with-idle-timer highlight-symbol-idle-delay t
94 'highlight-symbol-temp-highlight))))
95 (add-hook 'post-command-hook 'highlight-symbol-mode-post-command nil t))
97 (remove-hook 'post-command-hook 'highlight-symbol-mode-post-command t)
98 (setq highlight-symbol-instances
99 (delete (current-buffer) highlight-symbol-instances))
100 (unless (or highlight-symbol-instances
101 (null highlight-symbol-timer))
102 (cancel-timer highlight-symbol-timer)
103 (setq highlight-symbol-timer nil))
105 (highlight-symbol-mode-remove-temp)
106 (kill-local-variable 'highlight-symbol)))
109(defun highlight-symbol-at-point ()
110 "Toggle highlighting of the symbol at point.
111This highlights or unhighlights the symbol at point using the first
112element in of `highlight-symbol-faces'."
114 (let ((symbol (highlight-symbol-get-symbol)))
115 (if (member symbol highlight-symbol-list)
118 (setq highlight-symbol-list (delete symbol highlight-symbol-list))
119 (hi-lock-unface-buffer symbol))
121 (when (equal symbol highlight-symbol)
122 (highlight-symbol-mode-remove-temp))
123 (let ((face (pop highlight-symbol-faces)))
125 (setq highlight-symbol-faces
126 (nconc highlight-symbol-faces `(,face)))
128 (hi-lock-set-pattern symbol face)
129 (push symbol highlight-symbol-list)))))
131(defun highlight-symbol-next ()
132 "Jump to the next location of the symbol at point within the function."
134 (highlight-symbol-jump 1))
136(defun highlight-symbol-prev ()
137 "Jump to the previous location of the symbol at point within the function."
139 (highlight-symbol-jump -1))
141(defun highlight-symbol-next-in-defun ()
142 "Jump to the next location of the symbol at point within the defun."
146 (highlight-symbol-jump 1)))
148(defun highlight-symbol-prev-in-defun ()
149 "Jump to the previous location of the symbol at point within the defun."
153 (highlight-symbol-jump -11)))
155;;; Internal ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
157(defvar highlight-symbol-timer nil)
158(defvar highlight-symbol-instances nil)
160(defvar highlight-symbol nil)
161(make-variable-buffer-local 'highlight-symbol)
163(defvar highlight-symbol-list nil)
164(make-variable-buffer-local 'highlight-symbol-list)
166(defun highlight-symbol-get-symbol ()
167 "Return a regular expression dandifying the symbol at point."
168 (let ((symbol (thing-at-point 'symbol)))
169 (when symbol (concat "\\_<" (regexp-quote symbol) "\\_>"))))
171(defun highlight-symbol-temp-highlight ()
172 "Highlight the current symbol until a command is executed."
173 (when highlight-symbol-mode
174 (let ((symbol (highlight-symbol-get-symbol)))
175 (unless (or (equal symbol highlight-symbol)
176 (member symbol highlight-symbol-list))
177 (highlight-symbol-mode-remove-temp)
178 (setq highlight-symbol symbol)
179 (hi-lock-set-pattern symbol 'highlight-symbol-face)))))
181(defun highlight-symbol-mode-remove-temp ()
182 "Remove the temporary symbol highlighting."
183 (when highlight-symbol
184 (hi-lock-unface-buffer highlight-symbol)
185 (setq highlight-symbol nil)))
187(defun highlight-symbol-mode-post-command ()
188 "After a command, change the temporary highlighting.
189Remove the temporary symbol highlighting and, unless a timeout is specified,
191 (unless (eq this-command 'highlight-symbol-jump-to-next)
192 (if highlight-symbol-timer
193 (highlight-symbol-mode-remove-temp)
194 (highlight-symbol-temp-highlight))))
196(defun highlight-symbol-jump (dir)
197 "Jump to the next or previous occurence of the symbol at point.
198DIR has to be 1 or -1."
199 (let ((symbol (highlight-symbol-get-symbol)))
201 (let* ((case-fold-search nil)
202 (bounds (bounds-of-thing-at-point 'symbol))
203 (offset (- (point) (if (< 0 dir) (cdr bounds) (car bounds)))))
204 ;; move a little, so we don't find the same instance again
205 (goto-char (- (point) offset))
206 (let ((target (re-search-forward symbol nil t dir)))
208 (goto-char (if (< 0 dir) (point-min) (point-max)))
209 (setq target (re-search-forward symbol nil nil dir)))
210 (goto-char (+ target offset))))
211 (message "No symbol at point"))))
213(provide 'highlight-symbol)