RSS Feed

Lisp Project of the Day

cl-progress-bar

You can support this project by donating at:

Donate using PatreonDonate using Liberapay

cl-progress-barcommandlineterminalui

Documentation🤨
Docstrings😀
Tests 🥺
Examples🤨
RepositoryActivity🤨
CI 🥺

This small library provides a facility to display simple progress-bars in the REPL or command-line app.

The progress bar is hidden by default and you need to set a variable to make it rendered. This can be useful in apps which can be running as a part of the UNIX pipeline.

In this small example, I create a progress bar and update it in a loop:

POFTHEDAY> (cl-progress-bar:with-progress-bar
               (100 "Testing the progressbar")
             (loop for i from 1 upto 100
                   do (cl-progress-bar:update 1)
                      (sleep 0.1)))

Testing the progressbar
==================================================
Finished in 10.26 seconds

The renderer is very simple and can be ruined by any other output, your program produce during the loop:

POFTHEDAY> (cl-progress-bar:with-progress-bar
                 (100 "Testing the progressbar")
               (loop for i from 1 upto 100
                     do (cl-progress-bar:update 1)
                        (when (zerop (mod i 10))
                          (format t "This is ~A-th iteration~%" i))
                        (sleep 0.1)))

Testing the progressbar
=====This is 10-th iteration
====This is 20-th iteration
=====This is 30-th iteration
======This is 40-th iteration
====This is 50-th iteration
=====This is 60-th iteration
======This is 70-th iteration
====This is 80-th iteration
=====This is 90-th iteration
======This is 100-th iteration

Finished in 10.28 seconds

It is interesting, is it possible to detect that some output was written to the *standard-output* and to rerender the progress bar in full length?

Also, it would be a nice feature to output estimated time and to support progress bars for an unknown number of items.

For inspiration, you can take a look at how Python library "tqdm" processes progress bars:

By the way, I found, this library uses documentation-utils and keeps it's docstrings in a separate file. So, when you navigate to the function source, you will not see docstrings.

But if you hit C-c C-d C-d in Emacs, it will show you this nice description:

CL-PROGRESS-BAR:WITH-PROGRESS-BAR
  [symbol]

WITH-PROGRESS-BAR names a macro:
  Lambda-list: ((CL-PROGRESS-BAR::STEPS-COUNT
                 CL-PROGRESS-BAR::DESCRIPTION &REST
                 CL-PROGRESS-BAR::DESC-ARGS)
                &BODY CL-PROGRESS-BAR::BODY)
  Documentation:
    Description:
     Macro. Build active progress bar. Requires size
     and description that will be printed out to
     the REPL. If *progress-bar-endabled* is nil or
     there is another progress bar active already
     progress bar will not be shown.
    
    Notes:
     Because with-progress-bar handles cases where
     another progress-bar is active it is generally
     safe to nest code with this macro on call stack.
     However, top level with-progress-bar should
     contain correct steps-count.
  Source file: /Users/art/poftheday/.qlot/...

I think this is inconvenient. What do you think about this way of keeping documentation for the code?

Update on code documentation

What if somebody create an extended defun macro which will make it possible to combine type annotations and documentation like that:

(defun* update ((unit-count (integer 1 *)
                            "How many steps has been finished?")
                &optional
                (progress-bar (or null cl-progress-bar.progress:progress-bar)
                              *progress-bar*
                              "Instance of progress-bar. Usually should be
                               left with default (namely: *progress-bar*)."))
  -> null
  (:doc "Notify progress bar about step completion."
   :thread-safety "This function is thread safe.")
  
  (when progress-bar
    (bt:with-lock-held ((cl-progress-bar.progress:mutex progress-bar))
      (cl-progress-bar.progress:update-progress progress-bar unit-count))))

In this example I moved all docstrings from the separate file into the function.


Brought to you by 40Ants under Creative Commons License