Mercurial > emacs
changeset 107573:954352cc49bd
* subr.el: Extend progress reporters to perform "spinning".
(progress-reporter-update, progress-reporter-do-update): Handle
non-numeric value arguments.
(progress-reporter--pulse-characters): New var.
author | Chong Yidong <cyd@stupidchicken.com> |
---|---|
date | Mon, 29 Mar 2010 19:18:48 -0400 |
parents | ed0efa62bd7d |
children | 2628198e4d2a |
files | etc/NEWS lisp/ChangeLog lisp/subr.el |
diffstat | 3 files changed, 105 insertions(+), 68 deletions(-) [+] |
line wrap: on
line diff
--- a/etc/NEWS Mon Mar 29 10:19:03 2010 +0000 +++ b/etc/NEWS Mon Mar 29 19:18:48 2010 -0400 @@ -112,6 +112,13 @@ `image-animate-max-time' and the delay between sub-images defined by the Graphic Control Extension of the image. +** Progress reporters can now "spin". +The MIN-VALUE and MAX-VALUE arguments of `make-progress-reporter' can +now be nil, or omitted. This makes a "non-numeric" reporter. Each +time you call `progress-reporter-update' on that progress reporter, +with a nil or omitted VALUE argument, the reporter message is +displayed with a "spinning bar". + * Changes in Emacs 24.1 on non-free operating systems
--- a/lisp/ChangeLog Mon Mar 29 10:19:03 2010 +0000 +++ b/lisp/ChangeLog Mon Mar 29 19:18:48 2010 -0400 @@ -1,3 +1,11 @@ +2010-03-29 Phil Hagelberg <phil@evri.com> + Chong Yidong <cyd@stupidchicken.com> + + * subr.el: Extend progress reporters to perform "spinning". + (progress-reporter-update, progress-reporter-do-update): Handle + non-numeric value arguments. + (progress-reporter--pulse-characters): New var. + 2010-03-28 Chong Yidong <cyd@stupidchicken.com> * progmodes/compile.el (compilation-start): Fix regexp detection
--- a/lisp/subr.el Mon Mar 29 10:19:03 2010 +0000 +++ b/lisp/subr.el Mon Mar 29 19:18:48 2010 -0400 @@ -3421,51 +3421,59 @@ ;; digits of precision, it doesn't really matter here. On the other ;; hand, it greatly simplifies the code. -(defsubst progress-reporter-update (reporter value) +(defsubst progress-reporter-update (reporter &optional value) "Report progress of an operation in the echo area. -However, if the change since last echo area update is too small -or not enough time has passed, then do nothing (see -`make-progress-reporter' for details). - -First parameter, REPORTER, should be the result of a call to -`make-progress-reporter'. Second, VALUE, determines the actual -progress of operation; it must be between MIN-VALUE and MAX-VALUE -as passed to `make-progress-reporter'. - -This function is very inexpensive, you may not bother how often -you call it." - (when (>= value (car reporter)) +REPORTER should be the result of a call to `make-progress-reporter'. + +If REPORTER is a numerical progress reporter---i.e. if it was + made using non-nil MIN-VALUE and MAX-VALUE arguments to + `make-progress-reporter'---then VALUE should be a number between + MIN-VALUE and MAX-VALUE. + +If REPORTER is a non-numerical reporter, VALUE should be nil. + +This function is relatively inexpensive. If the change since +last update is too small or insufficient time has passed, it does +nothing." + (when (or (not (numberp value)) ; For pulsing reporter + (>= value (car reporter))) ; For numerical reporter (progress-reporter-do-update reporter value))) -(defun make-progress-reporter (message min-value max-value - &optional current-value - min-change min-time) - "Return progress reporter object to be used with `progress-reporter-update'. - -MESSAGE is shown in the echo area. When at least 1% of operation -is complete, the exact percentage will be appended to the -MESSAGE. When you call `progress-reporter-done', word \"done\" -is printed after the MESSAGE. You can change MESSAGE of an -existing progress reporter with `progress-reporter-force-update'. - -MIN-VALUE and MAX-VALUE designate starting (0% complete) and -final (100% complete) states of operation. The latter should be -larger; if this is not the case, then simply negate all values. -Optional CURRENT-VALUE specifies the progress by the moment you -call this function. You should omit it or set it to nil in most -cases since it defaults to MIN-VALUE. - -Optional MIN-CHANGE determines the minimal change in percents to -report (default is 1%.) Optional MIN-TIME specifies the minimal -time before echo area updates (default is 0.2 seconds.) If -`float-time' function is not present, then time is not tracked -at all. If OS is not capable of measuring fractions of seconds, -then this parameter is effectively rounded up." - +(defun make-progress-reporter (message &optional min-value max-value + current-value min-change min-time) + "Return progress reporter object for use with `progress-reporter-update'. + +MESSAGE is shown in the echo area, with a status indicator +appended to the end. When you call `progress-reporter-done', the +word \"done\" is printed after the MESSAGE. You can change the +MESSAGE of an existing progress reporter by calling +`progress-reporter-force-update'. + +MIN-VALUE and MAX-VALUE, if non-nil, are starting (0% complete) +and final (100% complete) states of operation; the latter should +be larger. In this case, the status message shows the percentage +progress. + +If MIN-VALUE and/or MAX-VALUE is omitted or nil, the status +message shows a \"spinning\", non-numeric indicator. + +Optional CURRENT-VALUE is the initial progress; the default is +MIN-VALUE. +Optional MIN-CHANGE is the minimal change in percents to report; +the default is 1%. +CURRENT-VALUE and MIN-CHANGE do not have any effect if MIN-VALUE +and/or MAX-VALUE are nil. + +Optional MIN-TIME specifies the minimum interval time between +echo area updates (default is 0.2 seconds.) If the function +`float-time' is not present, time is not tracked at all. If the +OS is not capable of measuring fractions of seconds, this +parameter is effectively rounded up." (unless min-time (setq min-time 0.2)) (let ((reporter - (cons min-value ;; Force a call to `message' now + ;; Force a call to `message' now + (cons (or min-value 0) (vector (if (and (fboundp 'float-time) (>= min-time 0.02)) (float-time) nil) @@ -3477,12 +3485,11 @@ (progress-reporter-update reporter (or current-value min-value)) reporter)) -(defun progress-reporter-force-update (reporter value &optional new-message) +(defun progress-reporter-force-update (reporter &optional value new-message) "Report progress of an operation in the echo area unconditionally. -First two parameters are the same as for -`progress-reporter-update'. Optional NEW-MESSAGE allows you to -change the displayed message." +The first two arguments are the same as in `progress-reporter-update'. +NEW-MESSAGE, if non-nil, sets a new message for the reporter." (let ((parameters (cdr reporter))) (when new-message (aset parameters 3 new-message)) @@ -3490,15 +3497,15 @@ (aset parameters 0 (float-time))) (progress-reporter-do-update reporter value))) +(defvar progress-reporter--pulse-characters ["-" "\\" "|" "/"] + "Characters to use for pulsing progress reporters.") + (defun progress-reporter-do-update (reporter value) (let* ((parameters (cdr reporter)) + (update-time (aref parameters 0)) (min-value (aref parameters 1)) (max-value (aref parameters 2)) - (one-percent (/ (- max-value min-value) 100.0)) - (percentage (if (= max-value min-value) - 0 - (truncate (/ (- value min-value) one-percent)))) - (update-time (aref parameters 0)) + (text (aref parameters 3)) (current-time (float-time)) (enough-time-passed ;; See if enough time has passed since the last update. @@ -3506,26 +3513,41 @@ (when (>= current-time update-time) ;; Calculate time for the next update (aset parameters 0 (+ update-time (aref parameters 5))))))) - ;; - ;; Calculate NEXT-UPDATE-VALUE. If we are not going to print - ;; message this time because not enough time has passed, then use - ;; 1 instead of MIN-CHANGE. This makes delays between echo area - ;; updates closer to MIN-TIME. - (setcar reporter - (min (+ min-value (* (+ percentage - (if enough-time-passed - (aref parameters 4) ;; MIN-CHANGE - 1)) - one-percent)) - max-value)) - (when (integerp value) - (setcar reporter (ceiling (car reporter)))) - ;; - ;; Only print message if enough time has passed - (when enough-time-passed - (if (> percentage 0) - (message "%s%d%%" (aref parameters 3) percentage) - (message "%s" (aref parameters 3)))))) + (cond ((and min-value max-value) + ;; Numerical indicator + (let* ((one-percent (/ (- max-value min-value) 100.0)) + (percentage (if (= max-value min-value) + 0 + (truncate (/ (- value min-value) + one-percent))))) + ;; Calculate NEXT-UPDATE-VALUE. If we are not printing + ;; message because not enough time has passed, use 1 + ;; instead of MIN-CHANGE. This makes delays between echo + ;; area updates closer to MIN-TIME. + (setcar reporter + (min (+ min-value (* (+ percentage + (if enough-time-passed + ;; MIN-CHANGE + (aref parameters 4) + 1)) + one-percent)) + max-value)) + (when (integerp value) + (setcar reporter (ceiling (car reporter)))) + ;; Only print message if enough time has passed + (when enough-time-passed + (if (> percentage 0) + (message "%s%d%%" text percentage) + (message "%s" text))))) + ;; Pulsing indicator + (enough-time-passed + (let ((index (mod (1+ (car reporter)) 4)) + (message-log-max nil)) + (setcar reporter index) + (message "%s %s" + text + (aref progress-reporter--pulse-characters + index))))))) (defun progress-reporter-done (reporter) "Print reporter's message followed by word \"done\" in echo area."