X-Git-Url: https://code.delx.au/gnu-emacs-elpa/blobdiff_plain/2a7b2eb6d92473cdbdec84df7d05238b43599fb7..a7b4e52766977b58c6b9899305e962a2b5235bda:/spinner.el diff --git a/spinner.el b/spinner.el index 721f9c29f..0132bf718 100644 --- a/spinner.el +++ b/spinner.el @@ -1,9 +1,11 @@ -;;; spinner.el --- Mode-line spinner for operations in progress -*- lexical-binding: t; -*- +;;; spinner.el --- Add spinners and progress-bars to the mode-line for ongoing operations -*- lexical-binding: t; -*- ;; Copyright (C) 2015 Artur Malabarba ;; Author: Artur Malabarba ;; Version: 1.0 +;; Package-Requires: ((cl-lib "0.5")) +;; URL: https://github.com/Bruce-Connor/spinner.el ;; Keywords: processes mode-line ;; This program is free software; you can redistribute it and/or modify @@ -20,15 +22,40 @@ ;; along with this program. If not, see . ;;; Commentary: - -;; Run `(spinner-start)' to see the effect. +;; 1 Usage +;; ═══════ +;; +;; 1. Add `(spinner "1.0")' 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. +;; +;; +;; 2 Behavior +;; ══════════ +;; +;; The default spinner is a line drawing that rotates. You can pass an +;; argument to `spinner-start' to specify which spinner you want. All +;; possibilities are listed in the `spinner-types' variable, but here are +;; a few examples for you to try: +;; +;; • `(spinner-start 'vertical-breathing 10)' +;; • `(spinner-start 'minibox)' +;; • `(spinner-start 'moon)' +;; • `(spinner-start 'triangle)' ;;; Code: +(require 'cl-lib) (defconst spinner-types '((3-line-clock . ["┤" "┘" "┴" "└" "├" "┌" "┬" "┐"]) (2-line-clock . ["┘" "└" "┌" "┐"]) + (flipping-line . ["_" "\\" "|" "/"]) + (rotating-line . ["-" "\\" "|" "/"]) (progress-bar . ["[ ]" "[= ]" "[== ]" "[=== ]" "[====]" "[ ===]" "[ ==]" "[ =]"]) (progress-bar-filled . ["| |" "|█ |" "|██ |" "|███ |" "|████|" "| ███|" "| ██|" "| █|"]) (vertical-breathing . ["▁" "▂" "▃" "▄" "▅" "▆" "▇" "█" "▇" "▆" "▅" "▄" "▃" "▂" "▁" " "]) @@ -51,20 +78,15 @@ vector, the spinner itself.") "Spinner curently being displayed on the mode-line.") (make-variable-buffer-local 'spinner-current) -(defun spinner-stop () - "Stop the current buffer's spinner." - (when (timerp spinner--timer) - (cancel-timer spinner--timer)) - (setq spinner--timer nil - spinner-current nil) - (setq mode-line-format - (remove 'spinner--mode-line-construct mode-line-format))) +(defvar spinner--counter 0 + "Current frame of the spinner.") +(make-variable-buffer-local 'spinner--counter) (defconst spinner--mode-line-construct '((spinner-current (" " (:eval (elt spinner-current - (% (cadr (current-time)) + (% spinner--counter (length spinner-current))))) (spinner--timer (:eval (spinner-stop))))) @@ -75,10 +97,24 @@ vector, the spinner itself.") "Holds the timer being used on the current buffer.") (make-variable-buffer-local 'spinner--timer) -(defun spinner-start (&optional type) +(defvar spinner-frames-per-second 5 + "Default speed at which spinners spin, in frames per second. +Applications can override this value.") + + +;;; The main function +;;;###autoload +(defun spinner-start (&optional type fps) "Start a mode-line spinner of given TYPE. -Spinners are buffer local. Call `spinner-stop' in the same buffer -to stop it. +Spinners are buffer local. It is added to the mode-line in the +buffer where `spinner-start' is called. + +Return value is a function which can be called anywhere to stop +this spinner. You can also call `spinner-stop' 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'. If TYPE is nil, use the first element of `spinner-types'. If TYPE is `random', use a random element of `spinner-types'. @@ -99,10 +135,11 @@ is chosen as the spinner type." spinner-types))) ((symbolp type) (cdr (assq type spinner-types))) (t (error "Unknown spinner type: %s" type)))) - + (setq spinner--counter 0) + ;; Maybe add to mode-line. (unless (memq 'spinner--mode-line-construct mode-line-format) - (setq mode-line-format (copy-list mode-line-format)) + (setq mode-line-format (cl-copy-list mode-line-format)) (let ((cell (memq 'mode-line-buffer-identification mode-line-format))) (if cell (setcdr cell (cons 'spinner--mode-line-construct (cdr cell))) @@ -113,14 +150,31 @@ is chosen as the spinner type." (cancel-timer spinner--timer)) (let ((buffer (current-buffer)) ;; Create the timer as a lex variable so it can cancel itself. - (timer (run-at-time t 1 #'ignore))) + (timer (run-at-time t + (/ 1.0 (or fps spinner-frames-per-second)) + #'ignore))) (timer-set-function timer (lambda () (if (buffer-live-p buffer) (with-current-buffer buffer + (setq spinner--counter (1+ spinner--counter)) (force-mode-line-update)) (ignore-errors (cancel-timer timer))))) - (setq spinner--timer timer))) + (setq spinner--timer timer) + ;; Return a stopping function. + (lambda () (when (buffer-live-p buffer) + (with-current-buffer buffer + (spinner-stop)))))) + +(defun spinner-stop () + "Stop the current buffer's spinner." + (when (timerp spinner--timer) + (cancel-timer spinner--timer)) + (setq spinner--timer nil + spinner-current nil) + (setq mode-line-format + (remove 'spinner--mode-line-construct mode-line-format))) (provide 'spinner) + ;;; spinner.el ends here