]> code.delx.au - gnu-emacs-elpa/blobdiff - beacon.el
Fix #38 - bob error introduced by previous commit
[gnu-emacs-elpa] / beacon.el
index d56e094f282a2ec6088f901cbaca04221c62e083..76c0db0dd1d2b5119c5ca5fe4b435803932e245c 100644 (file)
--- a/beacon.el
+++ b/beacon.el
@@ -5,8 +5,8 @@
 ;; Author: Artur Malabarba <emacs@endlessparentheses.com>
 ;; URL: https://github.com/Malabarba/beacon
 ;; Keywords: convenience
-;; Version: 0.2.1
-;; Package-Requires: ((seq "1.9"))
+;; Version: 0.5.1
+;; Package-Requires: ((seq "1.11"))
 
 ;; 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
 ;;; Code:
 
 (require 'seq)
+(require 'faces)
+(unless (fboundp 'seq-mapn)
+  ;; This is for people who are on outdated Emacs snapshots. Will be
+  ;; deleted in a couple of weeks.
+  (defun seq-mapn (function sequence &rest sequences)
+    "Like `seq-map' but FUNCTION is mapped over all SEQUENCES.
+The arity of FUNCTION must match the number of SEQUENCES, and the
+mapping stops on the shortest sequence.
+Return a list of the results.
+
+\(fn FUNCTION SEQUENCES...)"
+    (let ((result nil)
+          (sequences (seq-map (lambda (s) (seq-into s 'list))
+                            (cons sequence sequences))))
+      (while (not (memq nil sequences))
+        (push (apply function (seq-map #'car sequences)) result)
+        (setq sequences (seq-map #'cdr sequences)))
+      (nreverse result))))
 
 (defgroup beacon nil
   "Customization group for beacon."
@@ -53,13 +71,20 @@ Otherwise this should be a number, and `beacon' will push the
 mark whenever point moves more than that many lines."
   :type '(choice integer (const nil)))
 
-(defcustom beacon-blink-when-point-moves nil
-  "Should the beacon blink when moving a long distance?
-If nil, don't blink due to plain movement.
+(defcustom beacon-blink-when-point-moves-vertically nil
+  "Should the beacon blink when moving a long distance vertically?
+If nil, don't blink due to vertical movement.
 If non-nil, this should be an integer, which is the minimum
 movement distance (in lines) that triggers a beacon blink."
   :type '(choice integer (const nil)))
 
+(defcustom beacon-blink-when-point-moves-horizontally nil
+  "Should the beacon blink when moving a long distance horizontally?
+If nil, don't blink due to horizontal movement.
+If non-nil, this should be an integer, which is the minimum
+movement distance (in columns) that triggers a beacon blink."
+  :type '(choice integer (const nil)))
+
 (defcustom beacon-blink-when-buffer-changes t
   "Should the beacon blink when changing buffer?"
   :type 'boolean)
@@ -103,6 +128,13 @@ If it is a string, it is a color name or specification,
 e.g. \"#666600\"."
   :type '(choice number color))
 
+(defface beacon-fallback-background
+  '((((class color) (background light)) (:background "black"))
+    (((class color) (background dark)) (:background "white")))
+  "Fallback beacon background color.
+Used in cases where the color can't be determined by Emacs.
+Only the background of this face is used.")
+
 (defvar beacon-dont-blink-predicates nil
   "A list of predicates that prevent the beacon blink.
 These predicate functions are called in order, with no
@@ -117,14 +149,16 @@ For instance, if you want to disable beacon on buffers where
 
 (add-hook 'beacon-dont-blink-predicates #'window-minibuffer-p)
 
-(defcustom beacon-dont-blink-major-modes '(magit-status-mode magit-popup-mode)
+(defcustom beacon-dont-blink-major-modes '(t magit-status-mode magit-popup-mode
+                                       gnus-summary-mode gnus-group-mode)
   "A list of major-modes where the beacon won't blink.
 Whenever the current buffer satisfies `derived-mode-p' for
 one of the major-modes on this list, the beacon will not
 blink."
   :type '(repeat symbol))
 
-(defcustom beacon-dont-blink-commands '(recenter-top-bottom)
+(defcustom beacon-dont-blink-commands '(next-line previous-line
+                                            forward-line)
   "A list of commands that should not make the beacon blink.
 Use this for commands that scroll the window in very
 predictable ways, when the blink would be more distracting
@@ -197,9 +231,9 @@ COLORS applied to each one."
 
 (defun beacon--ov-at-point ()
   (car (or (seq-filter (lambda (o) (overlay-get o 'beacon))
-                     (overlays-in (point) (point)))
+                       (overlays-in (point) (point)))
            (seq-filter (lambda (o) (overlay-get o 'beacon))
-                     (overlays-at (point))))))
+                       (overlays-at (point))))))
 
 (defun beacon--vanish ()
   "Turn off the beacon."
@@ -221,14 +255,22 @@ Only returns `beacon-size' elements."
 
 (defun beacon--color-range ()
   "Return a list of background colors for the beacon."
-  (let* ((bg (color-values (face-attribute 'default :background)))
+  (let* ((default-bg (or (save-excursion
+                           (unless (eobp)
+                             (forward-line 1)
+                             (unless (bobp) (forward-char -1)))
+                           (background-color-at-point))
+                         (face-background 'default)))
+         (bg (color-values (if (string-match "\\`unspecified-" default-bg)
+                               (face-attribute 'beacon-fallback-background :background)
+                             default-bg)))
          (fg (cond
               ((stringp beacon-color) (color-values beacon-color))
               ((< (color-distance "black" bg)
                   (color-distance "white" bg))
                (make-list 3 (* beacon-color 65535)))
               (t (make-list 3 (* (- 1 beacon-color) 65535))))))
-    (apply #'cl-mapcar (lambda (r g b) (format "#%04x%04x%04x" r g b))
+    (apply #'seq-mapn (lambda (r g b) (format "#%04x%04x%04x" r g b))
            (mapcar (lambda (n) (butlast (beacon--int-range (elt fg n) (elt bg n))))
                    [0 1 2]))))
 
@@ -284,26 +326,34 @@ Only returns `beacon-size' elements."
 
 \f
 ;;; Movement detection
-(defun beacon--movement-> (delta)
-  "Return non-nil if latest point movement is > DELTA.
-If DELTA is nil, return nil."
-  (and delta
+(defun beacon--movement-> (delta-y &optional delta-x)
+  "Return non-nil if latest vertical movement is > DELTA-Y.
+If DELTA-Y is nil, return nil.
+The same is true for DELTA-X and horizonta movement."
+  (and delta-y
        (markerp beacon--previous-place)
        (equal (marker-buffer beacon--previous-place)
               (current-buffer))
        ;; Quick check that prevents running the code below in very
        ;; short movements (like typing).
        (> (abs (- (point) beacon--previous-place))
-          delta)
-       ;; Check if the movement was >= DELTA lines by moving DELTA
-       ;; lines. `count-screen-lines' is too slow if the movement had
-       ;; thousands of lines.
-       (save-excursion
-         (let ((p (point)))
-           (goto-char (min beacon--previous-place p))
-           (vertical-motion delta)
-           (> (max p beacon--previous-place)
-              (line-beginning-position))))))
+          delta-y)
+       ;; Col movement.
+       (or (and delta-x
+                (> (abs (- (current-column)
+                           (save-excursion
+                             (goto-char beacon--previous-place)
+                             (current-column))))
+                   delta-x))
+           ;; Check if the movement was >= DELTA lines by moving DELTA
+           ;; lines. `count-screen-lines' is too slow if the movement had
+           ;; thousands of lines.
+           (save-excursion
+             (let ((p (point)))
+               (goto-char (min beacon--previous-place p))
+               (vertical-motion delta-y)
+               (> (max p beacon--previous-place)
+                  (line-beginning-position)))))))
 
 (defun beacon--maybe-push-mark ()
   "Push mark if it seems to be safe."
@@ -312,7 +362,7 @@ If DELTA is nil, return nil."
     (let ((head (car mark-ring)))
       (when (and (eq beacon--previous-mark-head head)
                  (not (equal head beacon--previous-place)))
-        (push-mark beacon--previous-place)))))
+        (push-mark beacon--previous-place 'silent)))))
 
 (defun beacon--post-command ()
   "Blink if point moved very far."
@@ -324,19 +374,19 @@ If DELTA is nil, return nil."
          (not (eq beacon--previous-window (selected-window))))
     (beacon-blink))
    ;; Blink for scrolling.
-   ((and beacon-blink-when-window-scrolls
-         beacon--window-scrolled
+   ((and beacon--window-scrolled
          (equal beacon--window-scrolled (selected-window)))
     (beacon-blink))
    ;; Blink for movement
-   ((beacon--movement-> beacon-blink-when-point-moves)
+   ((beacon--movement-> beacon-blink-when-point-moves-vertically
+                  beacon-blink-when-point-moves-horizontally)
     (beacon-blink))
    ;; Even if we don't blink, vanish any previous beacon.
    (t (beacon--vanish)))
   (beacon--maybe-push-mark)
   (setq beacon--window-scrolled nil))
 
-(defun beacon--window-scroll-function (win _start-pos)
+(defun beacon--window-scroll-function (win start-pos)
   "Blink the beacon or record that window has been scrolled.
 If invoked during the command loop, record the current window so
 that it may be blinked on post-command.  This is because the
@@ -345,10 +395,13 @@ scrolled window might not be active, but we only know that at
 
 If invoked outside the command loop, `post-command-hook' would be
 unreliable, so just blink immediately."
-  (if this-command
-      (setq beacon--window-scrolled win)
-    (setq beacon--window-scrolled nil)
-    (beacon-blink)))
+  (unless (or (and (equal beacon--previous-window-start start-pos)
+                   (equal beacon--previous-window win))
+              (not beacon-blink-when-window-scrolls))
+    (if this-command
+        (setq beacon--window-scrolled win)
+      (setq beacon--window-scrolled nil)
+      (beacon-blink))))
 
 (defun beacon--blink-on-focus ()
   "Blink if `beacon-blink-when-focused' is non-nil"