[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: simple patch for `etags.el'
From: |
Paul Pogonyshev |
Subject: |
Re: simple patch for `etags.el' |
Date: |
Fri, 24 Sep 2004 01:21:45 -0200 |
User-agent: |
KMail/1.4.3 |
RMS wrote:
> It looks good.
>
> To install it, we need the text for etc/NEWS and for the manual.
Here is the patch rediffed together with new manual node. I also
tweaked comments in `subr.el' as I have suddenly discovered that
minibuffer is not the same as echo area.
My problems with CVS are still present, so the patch is made ``by
hands.''
A news entry could look like this (to go to ``Lisp Changes''):
+++
** New functions `make-progress-reporter', `progress-reporter-update',
`progress-reporter-force-update' and `progress-reporter-done' provide
a simple and efficient way of printing progress messages to the user.
Change log entry for `lisp/ChangeLog':
2004-09-24 Paul Pogonyshev <address@hidden>
* tar-mode.el (tar-summarize-buffer): Use progress reporter.
* progmodes/etags.el (etags-tags-completion-table): Use progress
reporter.
(etags-tags-apropos): Likewise.
* subr.el (make-progress-reporter, progress-reporter-update)
(progress-reporter-force-update, progress-reporter-do-update)
(progress-reporter-done): New functions.
Change log entry for `lispref/ChangeLog':
2004-09-24 Paul Pogonyshev <address@hidden>
* display.texi (Progress): New node.
--- lispref/display.texi.~1.124.~ 2004-07-17 12:40:22.000000000 -0200
+++ lispref/display.texi 2004-09-24 00:58:48.000000000 -0200
@@ -16,6 +16,7 @@ that Emacs presents to the user.
* Truncation:: Folding or wrapping long text lines.
* The Echo Area:: Where messages are displayed.
* Warnings:: Displaying warning messages for the user.
+* Progress:: Informing user about progress of a long operation.
* Invisible Text:: Hiding part of the buffer text.
* Selective Display:: Hiding part of the buffer text (the old way).
* Overlay Arrow:: Display of an arrow to indicate position.
@@ -530,7 +531,105 @@ symbols. If it matches the first few el
that warning is not logged.
@end defopt
address@hidden Progress
address@hidden Operation Progress
address@hidden progress
+
+When an operation can take a while to finish, you should inform the
+user about the progress it makes. This way the user can estimate
+remaining time and clearly see that Emacs is busy working, not hung.
+
+Functions listed in this section provide simple and efficient way of
+reporting operation progress. Here is a working example that does
+nothing useful:
+
address@hidden
+(let ((progress-reporter
+ (make-progress-reporter "Collecting some mana for Emacs..."
+ 0 500)))
+ (dotimes (k 500)
+ (sit-for 0.01)
+ (progress-reporter-update progress-reporter k))
+ (progress-reporter-done progress-reporter))
address@hidden example
+
address@hidden make-progress-reporter message min-value max-value &optional
current-value min-change min-time
+This function creates a progress reporter---the object you will use as
+an argument for all other functions listed here. The idea is to
+precompute as much data as possible to make progress reporting very
+fast.
+
+The @var{message} will be displayed in the echo area, followed by
+progress percentage. @var{message} is treated as a simple string. If
+you need it to depend on a filename, for instance, use @code{format}
+before calling this function.
+
address@hidden and @var{max-value} arguments stand for starting and
+final states of your operation. For instance, if you scan a buffer,
+they should be the results of @code{point-min} and @code{point-max}
+correspondingly. It is required that @var{max-value} is greater than
address@hidden If you create progress reporter when some part of
+the operation has already been completed, then specify
address@hidden argument. But normally you should omit it or set
+it to @code{nil}---it will default to @var{min-value} then.
+
+Remaining arguments control the rate of echo area updates. Progress
+reporter will wait for at least @var{min-change} more percents of the
+operation to be completed before printing next message.
address@hidden specifies the minimum time in seconds to pass between
+successive prints. It can be fractional. Depending on Emacs and
+system capabilities, progress reporter may or may not respect this
+last argument or do it with varying precision. Default value for
address@hidden is 1 (one percent), for @var{min-time}---0.2
+(seconds.)
+
+This function calls @code{progress-reporter-update}, so the first
+message is printed immediately.
address@hidden defun
+
address@hidden progress-reporter-update reporter value
+This function does the main work of reporting progress of your
+operation. It print the message of @var{reporter} followed by
+progress percentage determined by @var{value}. If percentage is zero,
+then it is not printed at all.
+
address@hidden must be the result of a call to
address@hidden @var{value} specifies the current
+state of your operation and must be between @var{min-value} and
address@hidden (inclusive) as passed to
address@hidden For instance, if you scan a buffer,
+then @var{value} should be the result of a call to @code{point}.
+
+This function respects @var{min-change} and @var{min-time} as passed
+to @code{make-progress-reporter} and so does not output new messages
+on every invocation. It is thus very fast and normally you should not
+try to reduce the number of calls to it: resulting overhead will most
+likely negate your effort.
address@hidden defun
+
address@hidden progress-reporter-force-update reporter value &optional
new-message
+This function is similar to @code{progress-reporter-update} except
+that it prints a message in the echo area unconditionally.
+
+First two arguments has the same meaning as for
address@hidden Optional @var{new-message} allows
+you to change the message of the @var{reporter}. Since this functions
+always updates the echo area, such a change will be immediately
+presented to the user.
address@hidden defun
+
address@hidden progress-reporter-done reporter
+This function should be called when the operation is finished. It
+prints the message of @var{reporter} followed by word ``done'' in the
+echo area.
+
+You should always call this function and not hope for
address@hidden to print ``100%.'' Firstly, it may
+never print it, there are many good reasons for this not to happen.
+Secondly, ``done'' is more explicit.
address@hidden defun
+
@node Invisible Text
@section Invisible Text
--- lisp/subr.el.~1.407.~ 2004-09-08 10:24:29.000000000 -0200
+++ lisp/subr.el 2004-09-24 00:45:07.000000000 -0200
@@ -2644,5 +2644,133 @@ The properties used on SYMBOL are `compo
(put symbol 'abortfunc (or abortfunc 'kill-buffer))
(put symbol 'hookvar (or hookvar 'mail-send-hook)))
+
+;; Standardized progress reporting
+
+;; Progress reporter has the following structure:
+;;
+;; (NEXT-UPDATE-VALUE . [NEXT-UPDATE-TIME
+;; MIN-VALUE
+;; MAX-VALUE
+;; MESSAGE
+;; MIN-CHANGE
+;; MIN-TIME])
+;;
+;; This weirdeness is for optimization reasons: we want
+;; `progress-reporter-update' to be as fast as possible, so
+;; `(car reporter)' is better than `(aref reporter 0)'.
+;;
+;; NEXT-UPDATE-TIME is a float. While `float-time' loses a couple
+;; digits of precision, it doesn't really matter here. On the other
+;; hand, it greatly simplifies the code.
+
+(defun make-progress-reporter (message min-value max-value
+ &optional current-value
+ min-change min-time)
+ "Return an object suitable for reporting operation progress 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."
+
+ (unless min-time
+ (setq min-time 0.2))
+ (let ((reporter
+ (cons min-value ;; Force a call to `message' now
+ (vector (if (and (fboundp 'float-time)
+ (>= min-time 0.02))
+ (float-time) nil)
+ min-value
+ max-value
+ message
+ (if min-change (max (min min-change 50) 1) 1)
+ min-time))))
+ (progress-reporter-update reporter (or current-value min-value))
+ reporter))
+
+(defsubst progress-reporter-update (reporter 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))
+ (progress-reporter-do-update reporter value)))
+
+(defun progress-reporter-force-update (reporter value &optional 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."
+ (let ((parameters (cdr reporter)))
+ (when new-message
+ (aset parameters 3 new-message))
+ (when (aref parameters 0)
+ (aset parameters 0 (float-time)))
+ (progress-reporter-do-update reporter value)))
+
+(defun progress-reporter-do-update (reporter value)
+ (let* ((parameters (cdr reporter))
+ (min-value (aref parameters 1))
+ (max-value (aref parameters 2))
+ (one-percent (/ (- max-value min-value) 100.0))
+ (percentage (truncate (/ (- value min-value) one-percent)))
+ (update-time (aref parameters 0))
+ (current-time (float-time))
+ (enough-time-passed
+ ;; See if enough time has passed since the last update.
+ (or (not update-time)
+ (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))))))
+
+(defun progress-reporter-done (reporter)
+ "Print reporter's message followed by word \"done\" in echo area."
+ (message "%s%d%%" (aref (cdr reporter) 3) 20))
+
;;; arch-tag: f7e0e6e5-70aa-4897-ae72-7a3511ec40bc
;;; subr.el ends here
--- lisp/tar-mode.el.~1.95.~ 2004-02-09 03:47:32.000000000 -0200
+++ lisp/tar-mode.el 2004-09-22 21:42:29.000000000 -0200
@@ -404,11 +404,10 @@ Place a dired-like listing on the front;
then narrow to it, so that only that listing
is visible (and the real data of the buffer is hidden)."
(set-buffer-multibyte nil)
- (message "Parsing tar file...")
(let* ((result '())
(pos (point-min))
- (bs (max 1 (- (buffer-size) 1024))) ; always 2+ empty blocks at end.
- (bs100 (max 1 (/ bs 100)))
+ (progress-reporter "Parsing tar file..."
+ (point-min) (max 1 (- (buffer-size) 1024)))
tokens)
(while (and (<= (+ pos 512) (point-max))
(not (eq 'empty-tar-block
@@ -416,10 +415,7 @@ is visible (and the real data of the buf
(tar-header-block-tokenize
(buffer-substring pos (+ pos 512)))))))
(setq pos (+ pos 512))
- (message "Parsing tar file...%d%%"
- ;(/ (* pos 100) bs) ; this gets round-off lossage
- (/ pos bs100) ; this doesn't
- )
+ (progress-reporter-update progress-reporter pos)
(if (eq (tar-header-link-type tokens) 20)
;; Foo. There's an extra empty block after these.
(setq pos (+ pos 512)))
@@ -446,7 +442,7 @@ is visible (and the real data of the buf
;; A tar file should end with a block or two of nulls,
;; but let's not get a fatal error if it doesn't.
(if (eq tokens 'empty-tar-block)
- (message "Parsing tar file...done")
+ (progress-reporter-done progress-reporter)
(message "Warning: premature EOF parsing tar file")))
(save-excursion
(goto-char (point-min))
--- lisp/progmodes/etags.el.~1.181.~ 2004-08-28 13:30:31.000000000 -0200
+++ lisp/progmodes/etags.el 2004-09-22 21:30:55.000000000 -0200
@@ -1229,10 +1229,10 @@ where they were found."
(defun etags-tags-completion-table ()
(let ((table (make-vector 511 0))
- (point-max (/ (float (point-max)) 100.0))
- (msg-fmt (format
- "Making tags completion table for %s...%%d%%%%"
- buffer-file-name)))
+ (progress-reporter
+ (make-progress-reporter
+ (format "Making tags completion table for %s..." buffer-file-name)
+ (point-min) (point-max))))
(save-excursion
(goto-char (point-min))
;; This monster regexp matches an etags tag line.
@@ -1253,7 +1253,7 @@ where they were found."
(buffer-substring (match-beginning 5) (match-end 5))
;; No explicit tag name. Best guess.
(buffer-substring (match-beginning 3) (match-end 3)))
- (message msg-fmt (/ (point) point-max)))
+ (progress-reporter-update progress-reporter (point)))
table)))
table))
@@ -1433,11 +1433,12 @@ where they were found."
(tags-with-face 'highlight (princ buffer-file-name))
(princ "':\n\n"))
(goto-char (point-min))
- (let ((point-max (/ (float (point-max)) 100.0)))
+ (let ((progress-reporter (make-progress-reporter
+ (format "Making tags apropos buffer for `%s'..."
+ string)
+ (point-min) (point-max))))
(while (re-search-forward string nil t)
- (message "Making tags apropos buffer for `%s'...%d%%"
- string
- (/ (point) point-max))
+ (progress-reporter-update progress-reporter (point))
(beginning-of-line)
(let* ( ;; Get the local value in the tags table
Re: simple patch for `etags.el', Richard Stallman, 2004/09/21
- Re: simple patch for `etags.el', Paul Pogonyshev, 2004/09/21
- Re: simple patch for `etags.el', Kim F. Storm, 2004/09/22
- Re: simple patch for `etags.el', Paul Pogonyshev, 2004/09/22
- Re: simple patch for `etags.el', Kim F. Storm, 2004/09/22
- Re: simple patch for `etags.el', David Kastrup, 2004/09/22
- Re: simple patch for `etags.el', Paul Pogonyshev, 2004/09/22
- Re: simple patch for `etags.el', Richard Stallman, 2004/09/23