summaryrefslogtreecommitdiffstats
path: root/emacs.d/nxhtml/util/hl-needed.el
blob: 7a160b69212190bda0b1ad34b718c13f20c0b959 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
;;; hl-needed.el --- Turn on highlighting of line and column when needed
;;
;; Author: Lennart Borgman (lennart O borgman A gmail O com)
;; Created: Fri Nov 30 21:19:18 2007
;; Version: 0.60
;; Last-Updated: 2010-03-19 Fri
;; URL: http://www.emacswiki.org/cgi-bin/wiki/hl-needed.el
;; Keywords:
;; Compatibility:
;;
;; Features that might be required by this library:
;;
  ;; `hl-line', `vline'.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Commentary:
;;
;; This is yet another highlight line and/or column idea.  The idea is
;; to try to show line and column only when it is probably most
;; needed.  See `hl-needed-mode' for more info.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Change log:
;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; This program 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 this program; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
;; Floor, Boston, MA 02110-1301, USA.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Code:

(require 'hl-line)
(require 'vline nil t)

;;;###autoload
(defgroup hl-needed nil
  "Customization group for `hl-needed-mode'."
  :group 'convenience)

(defcustom hl-needed-always nil
  "Highlight always.
This is similar to turning on `vline-mode' and `hl-line-mode'"
  :type 'boolean
  :group 'hl-needed)

(defcustom hl-needed-mark-line t
  "Highlight line."
  :type 'boolean
  :group 'hl-needed)

(defcustom hl-needed-mark-column t
  "Highlight column."
  :type 'boolean
  :group 'hl-needed)

(defcustom hl-needed-in-readonly-buffers nil
  "Do not highlight in read-only buffers unless non-nil."
  :type 'boolean
  :group 'hl-needed)

(defcustom hl-needed-not-in-modes
  '(wab-compilation-mode
    custom-mode)
  "List of modes where highlighting should not be done."
  :type '(repeat function)
  :group 'hl-needed)

;;(setq hl-needed-idle-time 5)
(defcustom hl-needed-idle-time 20
  "Highligh current line and/or column if Emacs is idle for more seconds.
If nil do not turn on `hl-line-mode' when Emacs is idle."
  :type '(choice (const :tag "Don't turn on when Emacs is idle" nil)
                 (integer :tag "Turn on after (seconds)"))
  :group 'hl-needed)

(defcustom hl-needed-on-mouse t
  "Highlight current line and/or column on clicks."
  :type 'boolean
  :group 'hl-needed)

(defcustom hl-needed-on-new-window t
  "Highlight current line and/or column on new window selection."
  :type 'boolean
  :group 'hl-needed)

(defcustom hl-needed-on-new-buffer t
  "Highlight current line and/or column on new buffer selection."
  :type 'boolean
  :group 'hl-needed)

(defcustom hl-needed-on-config-change t
  "Highlight current line and/or column on window conf change."
  :type 'boolean
  :group 'hl-needed)

(defcustom hl-needed-on-scrolling t
  "Highlight current line and/or column after scrolling."
  :type 'boolean
  :group 'hl-needed)

(defvar hl-needed-face 'hl-needed-face)
(defface hl-needed-face
  '((t (:inherit highlight)))
  "Face for flashing."
  :group 'hl-needed)

(defcustom hl-needed-flash-delay 0.0
  "Time to wait before turning on flash highlighting.
If a key is pressed before this flash highlighting is not done."
  :type 'float
  :group 'hl-needed)

(defcustom hl-needed-flash-duration 1.0
  "Turn off flash highlighting after this number of second.
Highlighting is turned off only if it was turned on because of
some change. It will not be turned off if it was turned on
because Emacs was idle for more than `hl-needed-idle-time'.

The default time is choosen to not disturb too much. I believe
human short attention may often be of this time. \(Compare eye
contact time.)"
  :type 'float
  :group 'hl-needed)

(defcustom hl-needed-currently-fun 'hl-needed-currently
  "Function that checks if highlighting should be done.
The function should return nil if not needed and non-nil
otherwise."
  :type 'function
  :group 'hl-needed)

(defvar hl-needed-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map [(control ?c) ?? ??] 'hl-needed-show)
    map))

;;;###autoload
(define-minor-mode hl-needed-mode
  "Try to highlight current line and column when needed.
This is a global minor mode.  It can operate in some different
ways:

- Highlighting can be on always, see `hl-needed-always'.

Or, it can be turned on depending on some conditions.  In this
case highlighting is turned off after each command and turned on
again in the current window when either:

- A new window was selected, see `hl-needed-on-new-window'.
- A new buffer was selected, see `hl-needed-on-new-buffer'.
- Window configuration was changed, see `hl-needed-on-config-change'.
- Buffer was scrolled see `hl-needed-on-scrolling'.
- A window was clicked with the mouse, see `hl-needed-on-mouse'.

After this highlighting may be turned off again, normally after a
short delay, see `hl-needed-flash'.

If either highlighting was not turned on or was turned off again
it will be turned on when

- Emacs has been idle for `hl-needed-idle-time' seconds.

See also `hl-needed-not-in-modes' and `hl-needed-currently-fun'.

Note 1: For columns to be highlighted vline.el must be available.

Note 2: This mode depends on `hl-line-mode' and `vline-mode' and
tries to cooperate with them. If you turn on either of these that
overrides the variables for turning on the respective
highlighting here."
  :global t
  :group 'hl-needed
  ;;:keymap hl-needed-mode-map
  (if hl-needed-mode
      (progn
        ;;(unless (memq major-mode hl-needed-not-in-modes) (setq hl-needed-window t))
        (when (featurep 'hl-needed) (hl-needed-show))
        (add-hook 'post-command-hook 'hl-needed-post-command)
        (add-hook 'pre-command-hook 'hl-needed-pre-command)
        (add-hook 'window-configuration-change-hook 'hl-needed-config-change)
        )
    (remove-hook 'post-command-hook 'hl-needed-post-command)
    (remove-hook 'pre-command-hook 'hl-needed-pre-command)
    (remove-hook 'window-configuration-change-hook 'hl-needed-config-change)
    (hl-needed-cancel-timer)
    (hl-needed-cancel-flash-timer)
    (hl-needed-hide)))

(defvar hl-needed-timer nil)
(defvar hl-needed-flash-timer nil)
(defvar hl-needed-window nil)
(defvar hl-needed-buffer nil)
(defvar hl-needed-window-start nil)
(defvar hl-needed-flash-this nil)
(defvar hl-needed-config-change nil)

(defvar hl-needed-old-blink nil)
(defun hl-needed-show ()
  "Highlight current line and/or column now."
  (interactive)
  (when (with-no-warnings (called-interactively-p))
    (setq hl-needed-flash-this nil)
    (unless hl-needed-mode
      (message "Use hl-needed-hide to remove highlighting")))
  (setq hl-needed-old-blink nil) ;; So blink is not turned on by hl-needed-hide
  (hl-needed-hide)
  (unless (active-minibuffer-window)
    (setq hl-needed-old-blink blink-cursor-mode)
    (when blink-cursor-mode
      (blink-cursor-mode -1)
      ;;(when (timerp blink-cursor-timer) (cancel-timer blink-cursor-timer))
      (blink-cursor-end)
      )
    (unless hl-line-mode
      (when hl-needed-mark-line
        (let ((hl-line-mode t)
              (hl-line-sticky-flag nil)
              (hl-line-face hl-needed-face))
          (hl-line-highlight))))
    (unless vline-mode
      (when hl-needed-mark-column
        (when (featurep 'vline)
          (let ((vline-style 'face)
                (vline-face hl-line-face)
                (vline-current-window-only t))
            (vline-show)))))))

(defun hl-needed-hide ()
  (interactive)
  (when (and hl-needed-old-blink
             (not blink-cursor-mode))
    (blink-cursor-mode 1))
  (setq hl-needed-old-blink nil)
  (unless hl-line-mode
    (hl-line-unhighlight))
  (when (featurep 'vline)
    (unless vline-mode
      (vline-clear))))

(defun hl-needed-cancel-timer ()
  (when (timerp hl-needed-timer) (cancel-timer hl-needed-timer))
  (setq hl-needed-timer nil))

(defun hl-needed-start-timer (wait)
  (hl-needed-cancel-timer)
  (setq hl-needed-timer
        (run-with-idle-timer wait
                             nil 'hl-needed-show-in-timer)))

(defun hl-needed-show-in-timer ()
  "Turn on with special error handling.
Erros may go unnoticed in timers.  This should prevent it."
  (condition-case err
      (save-match-data ;; runs in timer
        (hl-needed-show))
    (error
     (lwarn 'hl-needed-show
            :error "%s" (error-message-string err)))))

(defun hl-needed-hide-in-timer ()
  "Turn off with special error handling.
Erros may go unnoticed in timers.  This should prevent it."
  (condition-case err
      (unless hl-needed-always
        (hl-needed-hide))
    (error
     (lwarn 'hl-needed-hide
            :error "%s" (error-message-string err)))))

(defun hl-needed-hide-flash-in-timer ()
  "Turn off with special error handling.
Erros may go unnoticed in timers.  This should prevent it."
  (condition-case err
      (unless hl-needed-always
        (hl-needed-hide)
        (hl-needed-start-timer hl-needed-idle-time))
    (error
     (lwarn 'hl-needed-hide
            :error "%s" (error-message-string err)))))

(defun hl-needed-currently ()
  "Check if `hl-line-mode' is needed in buffer."
  ;; Check for change of buffer and window
  (if hl-needed-always
      t
    (unless (or (memq major-mode hl-needed-not-in-modes)
                isearch-mode
                (and buffer-read-only
                     (not hl-needed-in-readonly-buffers)))
      (or (and hl-needed-on-new-window
               (not (eq hl-needed-window (selected-window))))
          ;;(progn (message "here1") nil)
          (and hl-needed-on-new-buffer
               (not (eq hl-needed-buffer (current-buffer))))
          ;;(progn (message "here2") nil)
          (and hl-needed-on-config-change
               hl-needed-config-change)
          ;;(progn (message "here3") nil)
          (and hl-needed-on-mouse
               (listp last-input-event)
               (memq (car last-input-event) '(mouse-1 mouse-2 mouse-3)))
          ;;(progn (message "here4") nil)
          (and hl-needed-on-scrolling
               (and (not (eq hl-needed-window-start (window-start)))
                    (< 1
                       (abs
                        (- (line-number-at-pos hl-needed-window-start)
                           (line-number-at-pos (window-start)))))))))))

(defun hl-needed-cancel-flash-timer ()
    (when (timerp hl-needed-flash-timer) (cancel-timer hl-needed-flash-timer))
    (setq hl-needed-flash-timer nil))

(defun hl-needed-start-maybe-flash-timer ()
  (when (and hl-needed-flash-this
             (not hl-needed-always))
    (hl-needed-cancel-flash-timer)
    (setq hl-needed-flash-timer
          (run-with-timer (+ hl-needed-flash-delay hl-needed-flash-duration)
                          nil 'hl-needed-hide-flash-in-timer))))

(defvar hl-needed-pre-command-time (current-time))

(defun hl-needed-check ()
  ;; Cancel `hl-line-mode' and timer
  (unless (active-minibuffer-window)
    (if (funcall hl-needed-currently-fun)
        (progn
          ;; Some time calc for things that pause to show us where we are:
          (let* ((time-pre hl-needed-pre-command-time)
                (time-now (current-time))
                (pre (+ (nth 1 time-pre) (* 0.0000001 (nth 2 time-pre))))
                (now (+ (nth 1 time-now) (* 0.0000001 (nth 2 time-now)))))
            (if (< 1 (- now pre)) ;; Fix-me: option?
                nil ;; Don't show anything here, it just disturbs
              ;;(hl-needed-show)
              (hl-needed-start-timer hl-needed-flash-delay)
              (hl-needed-start-maybe-flash-timer))))
      ;; Submit an idle timer that can turn highlighting on.
      (hl-needed-start-timer hl-needed-idle-time)))
    (setq hl-needed-config-change nil)
    (unless (active-minibuffer-window)
      (setq hl-needed-window (selected-window))
      (setq hl-needed-buffer (current-buffer))
      (setq hl-needed-window-start (window-start))))

(defvar hl-needed-after-active-minibuffer nil)

(defun hl-needed-pre-command ()
  ;;(message "active-minibuffer-window=%s" (active-minibuffer-window))
  (setq hl-needed-after-active-minibuffer (active-minibuffer-window))
  (condition-case err
      (progn
        (hl-needed-cancel-timer)
        (hl-needed-cancel-flash-timer)
        (hl-needed-hide)
        (setq hl-needed-flash-this hl-needed-flash-duration)
        (setq hl-needed-pre-command-time (current-time)))
    (error
     (message "hl-needed-pre-command error: %s" err))))

(defun hl-needed-post-command ()
  (condition-case err
      (if (eq last-command 'keyboard-quit)
          (hl-needed-hide)
        (hl-needed-check))
    (error
     (message "hl-needed-post-command error: %s" err))))

(defvar hl-needed-minibuffer-active nil)

(defun hl-needed-config-change ()
  (condition-case err
      (if (active-minibuffer-window)
          (setq hl-needed-minibuffer-active t)
        ;; Changing buffer in the echo area is a config change. Catch this:
        (setq hl-needed-config-change (not hl-needed-after-active-minibuffer))
        (setq hl-needed-after-active-minibuffer nil)
        (setq hl-needed-minibuffer-active nil))
    (error
     (message "hl-needed-config-change error: %s" err))))

(provide 'hl-needed)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; hl-needed.el ends here