Download
(require 'hl-line)
(eval-when-compile
(require 'centered-cursor-mode nil t))
(defvar hl-line-face)
(defvar global-hl-line-mode)
(defface hl-spotlight
'((t :inherit highlight))
"*Face for the spotlight in Hl-Line-Window mode."
:group 'hl-line)
(defcustom hl-spotlight-height 2
"*Number of lines to highlight, before and after the current line."
:type 'integer :group 'hl-line)
(defcustom hl-spotlight-keep-centered-flag t
"*Non-nil means keep the cursor and spotlight centered in the window.
This has no effect unless library `centered-cursor-mode' is available."
:type 'boolean :group 'hl-line)
(defcustom hl-spotlight-scan-period 1.5
"*Number of seconds to wait before moving cursor to next line.
Set this to nil if you do not want the cursor to automatically scan."
:type '(choice
(const :tag "No cursor scanning" nil)
(number :tag "Seconds before cursor moves to next line"))
:group 'hl-line)
(defvar hl-spotlight-old-state nil
"Saved Hl-Line mode values, before `hl-spotlight-mode'.")
(defvar hl-spotlight-scan-timer (timer-create)
"Timer used to move point downward.")
(defun hl-spotlight-enlarge (n)
"Enlarge the hl-line spotlight by N lines.
N is the numeric prefix arg (one, by default).
A negative prefix arg shrinks the spotlight.
The spotlight is used by `hl-spotlight-mode' and
`global-hl-spotlight-mode'."
(interactive "p")
(set-variable 'hl-spotlight-height (+ n hl-spotlight-height))
(when global-hl-spotlight-mode (global-hl-line-highlight))
(when hl-spotlight-mode (hl-line-highlight)))
(defun hl-spotlight-limits ()
"Return a cons of the limits to use for `hl-line-range-function'."
(let ((start (save-excursion (forward-line (- hl-spotlight-height)) (point)))
(end (save-excursion (forward-line (1+ hl-spotlight-height)) (point))))
(cons start end)))
(define-minor-mode hl-spotlight-mode
"Buffer-local minor mode to highlight lines surrounding point.
With ARG, turn Hl-Spotlight mode on if ARG is positive, off otherwise.
Hl-Spotlight mode uses Hl-Line mode. Whenever Hl-Spotlight mode is on
in the current buffer, its overlay is used by Hl-Line mode, which
means that face `hl-spotlight' and option `hl-spotlight-height' are
used; face `hl-line' is not used.
Turn the spotlight on and off by using toggle command
`hl-spotlight-mode'. After turning Hl-Spotlight mode on, command
`hl-line-mode' also toggles the spotlight on and off, but without
turning off Hl-Spotlight mode. To return to the normal behavior of
`hl-line-mode', you must turn off Hl-Spotlight mode. Turning off
Hl-Spotlight mode also turns off Hl-Line mode."
:group 'hl-line
(cond (hl-spotlight-mode
(unless hl-spotlight-old-state
(setq hl-spotlight-old-state (list hl-line-face
hl-line-overlay
global-hl-line-overlay
hl-line-range-function
hl-line-sticky-flag)))
(hl-line-unhighlight)
(setq hl-line-overlay nil
hl-line-face 'hl-spotlight
hl-line-range-function 'hl-spotlight-limits
hl-line-sticky-flag nil)
(when (and (require 'centered-cursor-mode nil t)
hl-spotlight-keep-centered-flag)
(centered-cursor-mode 1))
(add-hook 'change-major-mode-hook #'hl-line-unhighlight nil t)
(if hl-line-sticky-flag
(remove-hook 'pre-command-hook #'hl-line-unhighlight t)
(add-hook 'pre-command-hook #'hl-line-unhighlight nil t))
(add-hook 'post-command-hook #'hl-line-highlight nil t))
(t
(cancel-timer hl-spotlight-scan-timer)
(setq hl-line-face (nth 0 hl-spotlight-old-state)
hl-line-overlay (nth 1 hl-spotlight-old-state)
global-hl-line-overlay (nth 2 hl-spotlight-old-state)
hl-line-range-function (nth 3 hl-spotlight-old-state)
hl-line-sticky-flag (nth 4 hl-spotlight-old-state))
(when hl-spotlight-old-state (setq hl-spotlight-old-state nil))
(when (require 'centered-cursor-mode nil t) (centered-cursor-mode -1))
(remove-hook 'post-command-hook #'hl-line-highlight t)
(hl-line-unhighlight)
(remove-hook 'change-major-mode-hook #'hl-line-unhighlight t)
(remove-hook 'pre-command-hook #'hl-line-unhighlight t)))
(hl-line-mode (if hl-spotlight-mode 1 -1)))
(define-minor-mode global-hl-spotlight-mode
"Global minor mode to highlight lines around point in current window.
With ARG, turn Global-Hl-Spotlight mode on if ARG is positive, off
otherwise.
See `hl-spotlight-mode'. The interaction between
`global-hl-spotlight-mode' and `global-hl-line-mode' is similar to
that between `hl-spotlight-mode' and `hl-line-mode'."
:global t :group 'hl-line
(cond (global-hl-spotlight-mode
(unless hl-spotlight-old-state
(setq hl-spotlight-old-state (list hl-line-face
hl-line-overlay
global-hl-line-overlay
hl-line-range-function
hl-line-sticky-flag)))
(global-hl-line-unhighlight)
(setq global-hl-line-overlay nil
hl-line-face 'hl-spotlight
hl-line-range-function 'hl-spotlight-limits
hl-line-sticky-flag nil)
(when (and (require 'centered-cursor-mode nil t)
hl-spotlight-keep-centered-flag)
(global-centered-cursor-mode 1))
(add-hook 'pre-command-hook #'global-hl-line-unhighlight)
(add-hook 'post-command-hook #'global-hl-line-highlight))
(t
(setq hl-line-face (nth 0 hl-spotlight-old-state)
hl-line-overlay (nth 1 hl-spotlight-old-state)
global-hl-line-overlay (nth 2 hl-spotlight-old-state)
hl-line-range-function (nth 3 hl-spotlight-old-state)
hl-line-sticky-flag (nth 4 hl-spotlight-old-state))
(when hl-spotlight-old-state (setq hl-spotlight-old-state nil))
(when (require 'centered-cursor-mode nil t)
(global-centered-cursor-mode -1))
(global-hl-line-unhighlight)
(remove-hook 'pre-command-hook #'global-hl-line-unhighlight)
(remove-hook 'post-command-hook #'global-hl-line-highlight)))
(global-hl-line-mode (if global-hl-spotlight-mode 1 -1)))
(defun hl-spotlight-scan (arg)
"Scan the buffer, moving the cursor down automatically.
Every `hl-spotlight-scan-period' seconds, move the cursor down one
line or the number of lines specified by a prefix arg. Scanning
starts at point.
With a plain prefix arg (`C-u'), stop a scan already in progess.
With a numeric prefix arg, scan down that many lines.
A negative prefix arg means scan up, not down.
With `C-u C-u', scan down the height of a full spotlight."
(interactive "P")
(if (and (consp arg) (= (car arg) 4))
(cancel-timer hl-spotlight-scan-timer)
(when (consp arg) (setq arg (1+ (* 2 hl-spotlight-height))))
(setq arg (prefix-numeric-value arg))
(setq hl-spotlight-scan-timer (run-at-time 0 hl-spotlight-scan-period
#'hl-spotlight-down arg))))
(defun hl-spotlight-down (&optional n)
"Move the spotlight down N lines (default 1)."
(unless n (setq n 1))
(if (eobp)
(cancel-timer hl-spotlight-scan-timer)
(forward-line n)
(ccm-position-cursor)
(hl-line-highlight)))
(provide 'hl-spotlight)