1 ;;; crosshairs.el --- Highlight the current line and column.
3 ;; Filename: crosshairs.el
4 ;; Description: Highlight the current line and column.
6 ;; Maintainer: Drew Adams
7 ;; Copyright (C) 2006-2011, Drew Adams, all rights reserved.
8 ;; Created: Fri Sep 08 13:09:19 2006
10 ;; Last-Updated: Mon Jan 3 20:26:52 2011 (-0800)
13 ;; URL: http://www.emacswiki.org/cgi-bin/wiki/crosshairs.el
14 ;; Keywords: faces, frames, emulation, highlight, cursor, accessibility
15 ;; Compatibility: GNU Emacs: 22.x, 23.x
17 ;; Features that might be required by this library:
19 ;; `col-highlight', `hl-line', `hl-line+', `vline'.
21 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
25 ;; This library highlights the current line and the current column.
26 ;; It combines the features of libraries `hl-line.el', `hl-line+.el',
27 ;; and `col-highlight.el', which let you highlight the line or column
28 ;; individually. See those libraries for more information.
30 ;; Command `crosshairs-mode' toggles this highlighting on and off.
31 ;; You can do this twice in succession to flash the crosshairs to
32 ;; show you where the cursor is. An alternative way to
33 ;; flash-highlight is to use command `flash-crosshairs' (once).
35 ;; Command `crosshairs-highlight' shows crosshairs highlighting until
36 ;; your next action (next command, technically). Command
37 ;; `crosshairs-unhighlight' turns off crosshairs highlighting due to
38 ;; `crosshairs-highlight'.
40 ;; With no prefix arg, command `crosshairs' is
41 ;; `crosshairs-highlight'. With a prefix arg, it is
44 ;; You can also have crosshairs highlighting come on automatically,
45 ;; when Emacs is idle. Command `toggle-crosshairs-when-idle' toggles
51 ;; * Library `hl-line+.el', which highlights the current line.
53 ;; * Library `col-highlight.el', which highlights the current column.
55 ;; * Library `cursor-chg.el' or library `oneonone.el', to change the
56 ;; cursor type when Emacs is idle.
59 ;; User options defined here:
61 ;; `crosshairs-mode', `crosshairs-overlay-priority',
62 ;; `crosshairs-vline-same-face-flag'.
64 ;; Commands defined here:
66 ;; `crosshairs', `crosshairs-flash', `crosshairs-highlight',
67 ;; `crosshairs-mode', `crosshairs-toggle-when-idle',
68 ;; `crosshairs-unhighlight', `flash-crosshairs',
69 ;; `toggle-crosshairs-when-idle'.
71 ;; Internal variables defined here:
73 ;; `crosshairs-flash-col-timer', `crosshairs-flash-line-timer',
74 ;; `crosshairs-highlight-when-idle-p'.
76 ;; Suggested alternative key bindings:
78 ;; (global-set-key [(control ?+)] 'crosshairs)
79 ;; or (global-set-key [(control ?+)] 'crosshairs-mode)
80 ;; or (global-set-key [(control ?+)] 'crosshairs-flash)
82 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
87 ;; Added autoload cookies for defgroup, defcustoms, commands.
89 ;; Added: crosshairs-overlay-priority.
90 ;; crosshairs-(un)highlight: Set/remove priority if crosshairs-overlay-priority.
92 ;; crosshairs-mode: Don't set previous state if explicit ARG.
93 ;; Added message indicating position.
94 ;; Added: crosshairs, crosshairs-(un)highlight.
96 ;; crosshairs-flash: Cancel timers at the outset.
97 ;; Remove hl-line-unhighlight-now from pre-command-hook.
99 ;; Added: crosshairs-flash-col-timer, crosshairs-flash-line-timer.
101 ;; Call col-highlight-(un)highlight with arg t.
102 ;; Save unhighlighting timers in crosshairs-flash-(col|line)-timer.
103 ;; First, cancel unhighlighting timers.
105 ;; Use vline.el now, instead of column-marker.el.
106 ;; Added group crosshairs, option crosshairs-vline-same-face-flag.
107 ;; crosshairs-mode, crosshairs-toggle-when-idle:
108 ;; If both are already on or off, reflect that as the crosshair state.
109 ;; crosshairs-toggle-when-idle:
110 ;; crosshairs-highlight-when-idle-p, not col-highlight-when-idle-p.
112 ;; Save/restore global-hl-line-mode.
113 ;; Clear and rehighlight column initially. Maybe highlight twice (bug).
114 ;; Don't use highlight modes to unhighlight - just unhighlight.
115 ;; Renamed: line-show-period to hl-line-flash-show-period.
116 ;; Removed semi-support for Emacs 20.
120 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
122 ;; This program is free software; you can redistribute it and/or
123 ;; modify it under the terms of the GNU General Public License as
124 ;; published by the Free Software Foundation; either version 3, or
125 ;; (at your option) any later version.
127 ;; This program is distributed in the hope that it will be useful,
128 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
129 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
130 ;; General Public License for more details.
132 ;; You should have received a copy of the GNU General Public License
133 ;; along with this program; see the file COPYING. If not, write to
134 ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
135 ;; Floor, Boston, MA 02110-1301, USA.
137 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
141 (require 'hl-line+) ;; Requires `hl-line.el'.
142 (require 'col-highlight) ;; Requires `vline.el'.
144 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
147 (defgroup crosshairs nil
148 "Highlight the current line and column."
149 :prefix "crosshairs-"
150 :group 'editing :group 'cursor :group 'hl-line :group 'frames
151 :link `(url-link :tag "Send Bug Report"
152 ,(concat "mailto:" "drew.adams" "@" "oracle" ".com?subject=\
154 &body=Describe bug here, starting with `emacs -q'. \
155 Don't forget to mention your Emacs and library versions."))
156 :link '(url-link :tag "Other Libraries by Drew"
157 "http://www.emacswiki.org/cgi-bin/wiki/DrewsElispLibraries")
158 :link '(url-link :tag "Download"
159 "http://www.emacswiki.org/cgi-bin/wiki/crosshairs.el"))
162 (defcustom crosshairs-overlay-priority nil
163 "*Priority to use for overlay `global-hl-line-overlay'."
165 (const :tag "No priority (default priority)" nil)
166 (integer :tag "Priority" 100))
170 (defcustom crosshairs-vline-same-face-flag t
171 "*Non-nil means use face `hl-line' for column highlighting also.
172 nil means highlight the column according to the value of `vline-style'
174 :type 'boolean :group 'crosshairs)
176 (defvar crosshairs-highlight-when-idle-p nil
177 "Non-nil means highlight current line and column when Emacs is idle.
178 Do NOT change this yourself; instead, use
179 `\\[toggle-crosshairs-when-idle]'.")
181 (defvar crosshairs-flash-line-timer (timer-create)
182 "Timer used to unhighlight current line for `crosshairs-flash'.")
184 (defvar crosshairs-flash-col-timer (timer-create)
185 "Timer used to unhighlight current column for `crosshairs-flash'.")
188 (define-minor-mode crosshairs-mode
189 "Toggle highlighting the current line and column.
190 With ARG, turn highlighting on if and only if ARG is positive."
191 :init-value nil :global t :group 'crosshairs
192 :link `(url-link :tag "Send Bug Report"
193 ,(concat "mailto:" "drew.adams" "@" "oracle" ".com?subject=\
195 &body=Describe bug here, starting with `emacs -q'. \
196 Don't forget to mention your Emacs and library versions."))
197 :link '(url-link :tag "Other Libraries by Drew"
198 "http://www.emacswiki.org/cgi-bin/wiki/DrewsElispLibraries")
199 :link '(url-link :tag "Download"
200 "http://www.emacswiki.org/cgi-bin/wiki/crosshairs.el")
201 :link '(url-link :tag "Description"
202 "http://www.emacswiki.org/cgi-bin/wiki/ChangingCursorDynamically")
203 :link '(emacs-commentary-link :tag "Commentary" "crosshairs")
204 ;; If both were already on or off, reflect that as the previous crosshairs state.
206 (cond ((and global-hl-line-mode column-highlight-mode)
207 (setq crosshairs-mode nil))
208 ((and (not global-hl-line-mode) (not column-highlight-mode))
209 (setq crosshairs-mode t))))
210 (cond (crosshairs-mode
211 (unless global-hl-line-mode
212 (global-hl-line-mode 1)
213 (global-hl-line-highlight))
214 (column-highlight-mode 1)
215 (message "Point: %d - Crosshairs mode enabled" (point)))
217 (global-hl-line-mode -1)
218 (global-hl-line-unhighlight)
219 (column-highlight-mode -1)
220 (message "Point: %d - Crosshairs mode disabled" (point)))))
223 (defalias 'toggle-crosshairs-when-idle 'crosshairs-toggle-when-idle)
225 (defun crosshairs-toggle-when-idle (&optional arg)
226 "Toggle highlighting the current line and column when Emacs is idle.
227 With prefix argument, turn on if ARG > 0; else turn off.
228 You can use commands `col-highlight-set-interval' and
229 `hl-line-when-idle-interval' to change the idle times."
231 ;; First, if both are already on or off, reflect that as the crosshair state.
232 (when (or (and hl-line-when-idle-p col-highlight-when-idle-p)
233 (and (not hl-line-when-idle-p) (not col-highlight-when-idle-p)))
234 (setq crosshairs-highlight-when-idle-p hl-line-when-idle-p))
235 (setq crosshairs-highlight-when-idle-p (if arg
236 (> (prefix-numeric-value arg) 0)
237 (not crosshairs-highlight-when-idle-p)))
238 (setq hl-line-when-idle-p crosshairs-highlight-when-idle-p
239 col-highlight-when-idle-p crosshairs-highlight-when-idle-p)
240 (cond (crosshairs-highlight-when-idle-p
241 (timer-activate-when-idle col-highlight-idle-timer)
242 (timer-activate-when-idle hl-line-idle-timer)
243 (add-hook 'pre-command-hook #'col-highlight-unhighlight)
244 (add-hook 'pre-command-hook #'hl-line-unhighlight-now)
245 (message "Turned ON highlighting line and column when Emacs is idle."))
247 (cancel-timer col-highlight-idle-timer)
248 (cancel-timer hl-line-idle-timer)
249 (remove-hook 'pre-command-hook #'col-highlight-unhighlight)
250 (remove-hook 'pre-command-hook #'hl-line-unhighlight-now)
251 (message "Turned OFF highlighting line and column when Emacs is idle."))))
254 (defalias 'flash-crosshairs 'crosshairs-flash)
256 (defun crosshairs-flash (&optional seconds)
257 "Highlight the current line and column temporarily.
258 Highlight the line for `hl-line-flash-show-period' and the column for
259 `column-show-period' seconds. With prefix argument SECONDS, highlight
260 both for SECONDS seconds."
262 (cancel-timer crosshairs-flash-line-timer) ; Cancel to prevent duplication.
263 (cancel-timer crosshairs-flash-col-timer)
264 (let ((global-hl-line-mode global-hl-line-mode))
265 (col-highlight-unhighlight t)
266 (col-highlight-highlight t)
267 (when column-highlight-mode (col-highlight-highlight t)) ; Extra - a vline bug.
268 (hl-line-highlight-now)
269 (remove-hook 'pre-command-hook 'hl-line-unhighlight-now)
270 (let ((line-period hl-line-flash-show-period) ; Defined in `hl-line+.el'.
271 (column-period col-highlight-period)) ; Defined in `col-highlight.el'.
273 (setq line-period (prefix-numeric-value seconds)
274 column-period line-period))
275 (setq crosshairs-flash-line-timer (run-at-time
277 #'global-hl-line-unhighlight)
278 crosshairs-flash-col-timer (run-at-time
280 #'col-highlight-unhighlight t)))))
283 (defun crosshairs (&optional modalp)
284 "Highlight current position with crosshairs.
285 With no prefix arg, highlighting turns off at the next command.
286 With a prefix arg, highlighting stays on until you toggle it off using
289 (if modalp (crosshairs-mode 1) (crosshairs-highlight)))
292 (defun crosshairs-highlight (&optional mode nomsg)
293 "Echo current position and highlight it with crosshairs.
294 If optional arg MODE is `line-only', then highlight only the line.
295 If optional arg MODE is `col-only', then highlight only the column.
297 A non-negative prefix argument uses MODE `line-only'.
298 A negative prefix argument uses MODE `col-only'.
300 Optional arg NOMSG non-nil means show no message.
302 If the current buffer is not the same as the value of `orig-buff',
303 then indicate the buffer, as well as the position. Variable
304 `orig-buff' is not bound here; if you want to take advantage of this
305 feature in your code, then bind it.
307 Return current position as a marker."
308 (interactive (list (and current-prefix-arg
309 (if (wholenump (prefix-numeric-value current-prefix-arg))
312 (when crosshairs-mode (crosshairs-mode -1))
313 (prog1 (point-marker)
314 (unless (eq mode 'line-only) (require 'col-highlight nil t))
315 (unless (eq mode 'col-only) (require 'hl-line nil t))
316 (setq mark-active nil)
317 (crosshairs-unhighlight 'even-if-frame-switch)
318 (when (and (boundp 'global-hl-line-overlay) (not (eq mode 'col-only)))
319 (unless global-hl-line-overlay
320 (setq global-hl-line-overlay (make-overlay 1 1)) ; to be moved
321 (overlay-put global-hl-line-overlay 'face hl-line-face))
322 (overlay-put global-hl-line-overlay 'window (selected-window))
323 (when crosshairs-overlay-priority
324 (overlay-put global-hl-line-overlay 'priority crosshairs-overlay-priority)
325 (when (boundp 'vline-overlay-table)
326 (mapcar (lambda (ov) (when (overlayp ov)
327 (overlay-put ov 'priority crosshairs-overlay-priority)))
328 vline-overlay-table)))
329 (hl-line-move global-hl-line-overlay))
330 (when (and (fboundp 'col-highlight-highlight) (not (eq mode 'line-only)))
331 (redisplay t) ; Force a redisplay, or else it doesn't always show up.
332 (col-highlight-highlight))
333 (when (or (boundp 'global-hl-line-overlay) (fboundp 'col-highlight-highlight))
334 (add-hook 'pre-command-hook 'crosshairs-unhighlight))
336 (if (and (boundp 'orig-buff) (eq (current-buffer) orig-buff))
337 (message "Point: %d" (point))
338 (message "Buffer: `%s', Point: %d" (current-buffer) (point))))))
341 (defun crosshairs-unhighlight (&optional arg)
342 "Turn off crosshairs highlighting of current position.
343 Optional arg nil means do nothing if this event is a frame switch."
345 (when (or arg (not (and (consp last-input-event)
346 (eq (car last-input-event) 'switch-frame))))
347 (when (fboundp 'col-highlight-unhighlight) (col-highlight-unhighlight t))
348 (when (and (boundp 'global-hl-line-overlay) global-hl-line-overlay)
349 (when crosshairs-overlay-priority
350 (overlay-put global-hl-line-overlay 'priority nil))
351 (delete-overlay global-hl-line-overlay))
352 (remove-hook 'pre-command-hook 'crosshairs-unhighlight)))
355 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
357 (provide 'crosshairs)
359 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
360 ;;; crosshairs.el ends here