* Usage
- 1. Add ~(spinner "VERSION")~ to your package’s dependencies.
+ First of all, don’t forget to add ~(spinner "VERSION")~ to your package’s dependencies.
- 2. Call ~(spinner-start)~ and a spinner will be added to the mode-line.
-
- 3. Call ~(spinner-stop)~ on the same buffer when you want to remove it.
-
- * Behavior
+ ** Major-modes
+ 1. Just call ~(spinner-start)~ and a spinner will be added to the mode-line.
+ 2. Call ~(spinner-stop)~ on the same buffer when you want to remove it.
The default spinner is a line drawing that rotates. You can pass an
argument to ~spinner-start~ to specify which spinner you want. All
- ~(spinner-start 'minibox)~
- ~(spinner-start 'moon)~
- ~(spinner-start 'triangle)~
+
+ You can also define your own as a vector of strings (see the examples
+ in ~spinner-types~).
+
+ ** Minor-modes
+ Minor-modes can create a spinner with ~spinner-create~ and then add it
+ to their mode-line lighter. They can then start the spinner by setting
+ a variable and calling ~spinner-start-timer~. Finally, they can stop
+ the spinner (and the timer) by just setting the same variable to nil.
+
+ Here’s an example for a minor-mode named ~foo~. Assuming that
+ ~foo--lighter~ is used as the mode-line lighter, the following code
+ will add an *inactive* global spinner to the mode-line.
+ #+begin_src emacs-lisp
+ (defvar foo--spinner (spinner-create 'rotating-line))
+ (defconst foo--lighter
+ '(" foo" (:eval (spinner-print foo--spinner))))
+ #+end_src
+
+ 1. To activate the spinner, just call ~(spinner-start foo--spinner)~.
+ It will show up on the mode-line and start animating.
+ 2. To get rid of it, call ~(spinner-stop foo--spinner)~. It will then
+ disappear again.
+
+ Some minor-modes will need spinners to be buffer-local. To achieve
+ that, just make the ~foo--spinner~ variable buffer-local and use the
+ third argument of the ~spinner-create~ function. The snippet below is an example.
+
+ #+begin_src emacs-lisp
+ (defvar-local foo--spinner nil)
+ (defconst foo--lighter
+ '(" foo" (:eval (spinner-print foo--spinner))))
+ (defun foo--start-spinner ()
+ "Create and start a spinner on this buffer."
+ (unless foo--spinner
+ (setq foo--spinner (spinner-create 'moon t)))
+ (spinner-start foo--spinner))
+ #+end_src
+
+ 1. To activate the spinner, just call ~(foo--start-spinner)~.
+ 2. To get rid of it, call ~(spinner-stop foo--spinner)~.
+
+ This will use the ~moon~ spinner, but you can use any of the names
+ defined in the ~spinner-types~ variable or even define your own.
+
+ * Extra options
+
+ Both ~spinner-start~ and ~spinner-create~ take extra options to configure the spinner, these are:
+
+ - ~FPS~: The number of frames to display per second. Defaults to ~spinner-frames-per-second~.
+ - ~DELAY~: After startin a spinner, it still won’t be displayed for this many seconds.
;; Copyright (C) 2015 Free Software Foundation, Inc.
;; Author: Artur Malabarba <emacs@endlessparentheses.com>
- ;; Version: 1.3.1
+ ;; Version: 1.4
;; URL: https://github.com/Malabarba/spinner.el
;; Keywords: processes mode-line
(defstruct (spinner
(:copier nil)
(:conc-name spinner--)
- (:constructor make-spinner (&optional type buffer-local fps)))
+ (:constructor make-spinner (&optional type buffer-local frames-per-second delay-before-start)))
(frames (spinner--type-to-frames type))
(counter 0)
- (fps spinner-frames-per-second)
+ (fps (or frames-per-second spinner-frames-per-second))
(timer (timer-create) :read-only)
(active-p nil)
(buffer (when buffer-local
(if (bufferp buffer-local)
buffer-local
- (current-buffer)))))
+ (current-buffer))))
+ (delay (or delay-before-start 0)))
;;;###autoload
- (defun spinner-create (&optional type buffer-local fps)
+ (defun spinner-create (&optional type buffer-local fps delay)
"Create a spinner of the given TYPE.
The possible TYPEs are described in `spinner--type-to-frames'.
timer which periodically calls `force-mode-line-update' in the
curent buffer. If BUFFER-LOCAL was set at creation time, then
`force-mode-line-update' is called in that buffer instead. When
- the spinner is stopped, the timer is deactivated."
- (make-spinner type buffer-local fps))
+ the spinner is stopped, the timer is deactivated.
+
+ DELAY, if given, is the number of seconds to wait after starting
+ the spinner before actually displaying it. It is safe to cancel
+ the spinner before this time, in which case it won't display at
+ all."
+ (make-spinner type buffer-local fps delay))
(defun spinner-print (spinner)
"Return a string of the current frame of SPINNER.
Designed to be used in the mode-line with:
(:eval (spinner-print some-spinner))"
(when (and spinner (spinner--active-p spinner))
- (elt (spinner--frames spinner)
- (spinner--counter spinner))))
+ (let ((frame (spinner--counter spinner)))
+ (when (>= frame 0)
+ (elt (spinner--frames spinner) frame)))))
(defun spinner--timer-function (spinner)
"Function called to update SPINNER.
(and buffer (not (buffer-live-p buffer))))
(spinner-stop spinner)
;; Increment
- (callf (lambda (x) (% (1+ x) (length (spinner--frames spinner))))
+ (callf (lambda (x) (if (< x 0)
+ (1+ x)
+ (% (1+ x) (length (spinner--frames spinner)))))
(spinner--counter spinner))
;; Update mode-line.
(if (buffer-live-p buffer)
(force-mode-line-update)))))
(defun spinner--start-timer (spinner)
- "Start a SPINNER's timer at FPS frames per second."
+ "Start a SPINNER's timer."
(let ((old-timer (spinner--timer spinner)))
(when (timerp old-timer)
(cancel-timer old-timer))
(setf (spinner--active-p spinner) t)
+
+ (unless (ignore-errors (> (spinner--fps spinner) 0))
+ (error "A spinner's FPS must be a positive number"))
+ (setf (spinner--counter spinner) (- (* (or (spinner--delay spinner) 0)
+ (spinner--fps spinner))))
;; Create timer.
- (let* ((repeat (/ 1.0 (or (spinner--fps spinner)
- spinner-frames-per-second)))
+ (let* ((repeat (/ 1.0 (spinner--fps spinner)))
(time (timer-next-integral-multiple-of-time (current-time) repeat))
;; Create the timer as a lex variable so it can cancel itself.
(timer (spinner--timer spinner)))
\f
;;; The main functions
;;;###autoload
- (defun spinner-start (&optional type-or-object fps)
+ (defun spinner-start (&optional type-or-object fps delay)
"Start a mode-line spinner of given TYPE-OR-OBJECT.
If TYPE-OR-OBJECT is an object created with `make-spinner',
simply activate it. This method is designed for minor modes, so
in the same buffer where the spinner was created.
FPS, if given, is the number of desired frames per second.
- Default is `spinner-frames-per-second'."
+ Default is `spinner-frames-per-second'.
+
+ DELAY, if given, is the number of seconds to wait until actually
+ displaying the spinner. It is safe to cancel the spinner before
+ this time, in which case it won't display at all."
(unless (spinner-p type-or-object)
;; Choose type.
(if (spinner-p spinner-current)
- (setf (spinner--frames spinner-current)
- (spinner--type-to-frames type-or-object))
- (setq spinner-current (make-spinner type-or-object (current-buffer) fps)))
+ (setf (spinner--frames spinner-current) (spinner--type-to-frames type-or-object))
+ (setq spinner-current (make-spinner type-or-object (current-buffer) fps delay)))
(setq type-or-object spinner-current)
;; Maybe add to mode-line.
(unless (memq 'spinner--mode-line-construct mode-line-process)
;; Create timer.
(when fps (setf (spinner--fps type-or-object) fps))
+ (when delay (setf (spinner--delay type-or-object) delay))
(spinner--start-timer type-or-object))
(defun spinner-start-print (spinner)