release | ||
dev |
Progress indicators for command line Clojure apps, including support for indeterminate tasks (those where progress cannot be measured) and determinate tasks (those where progress can be measured). The former are represented using "spinners", while the latter are represented using "progress bars".
To give the user of a command line app a visual progress indicator during long running processes.
Here it is in action (from the unit tests):
Note that using Unicode characters in progress indicators may be unreliable, depending on your OS, terminal, font, encoding, phase of the moon, etc.
spinner
is available as a Maven artifact from Clojars.
Important Notes:
-
If you're using leiningen, your REPL must be run in a trampoline (
lein trampoline repl
) in order for the ANSI escape sequences emitted byspinner
to function. -
If you're using the Clojure CLI tools, you must use the
clojure
binary, as theclj
binary wraps the JVM inrlwrap
which then incorrectly interprets some of the ANSI escape sequences emitted byspinner
. Some other readline alternatives (notably Rebel Readline) have been reported to work correctly.
$ clojure -Sdeps '{:deps {com.github.pmonks/spinner {:mvn/version "RELEASE"}}}'
$ lein trampoline try com.github.pmonks/spinner
Doesn't work properly, for the same reason the clj
command line doesn't work properly (rlwrap
intercepts the ANSI escape sequences emitted by this library and misinterprets them).
(require '[progress.indeterminate :as pi] :reload-all)
(pi/animate!
(pi/print "A long running process...")
(Thread/sleep 2500) ; Simulate a long running process
(pi/print "\nAnother long running process...")
(Thread/sleep 2500) ; Simulate another long running process
(pi/print "\nAll done!\n"))
(require '[progress.determinate :as pd] :reload-all)
(let [a (atom 0)]
; Add up all the numbers from 1 to 100... ...slowly
(pd/animate!
a
(reduce + (map #(do (Thread/sleep 10) (swap! a inc) %) (range 100)))))
The functionality is provided by the progress.indeterminate
and progress.determinate
namespaces.
Require them in the REPL:
(require '[progress.indeterminate :as pi] :reload-all)
(require '[progress.determinate :as pd] :reload-all)
Require them in your application:
(ns my-app.core
(:require [progress.indeterminate :as pi]
[progress.determinate :as pd]))
API documentation is available here. The unit tests provide comprehensive usage examples (alternative animation sets, formatting, etc.).
This project uses the git-flow branching strategy, and the permanent branches are called release
and dev
. Any changes to the release
branch are considered a release and auto-deployed (JARs to Clojars, API docs to GitHub Pages, etc.).
For this reason, all development must occur either in branch dev
, or (preferably) in temporary branches off of dev
. All PRs from forked repos must also be submitted against dev
; the release
branch is only updated from dev
via PRs created by the core development team. All other changes submitted to release
will be rejected.
spinner
uses tools.build
. You can get a list of available tasks by running:
clojure -A:deps -T:build help/doc
Of particular interest are:
clojure -T:build test
- run the unit testsclojure -T:build lint
- run the linters (clj-kondo and eastwood)clojure -T:build ci
- run the full CI suite (check for outdated dependencies, run the unit tests, run the linters)clojure -T:build install
- build the JAR and install it locally (e.g. so you can test it with downstream code)
Please note that the deploy
task is restricted to the core development team (and will not function if you run it yourself).
The project was originally developed under my personal GitHub account. In early 2018 it was transferred to the clj-commons
GitHub organisation, but then, as that group refined their scope and mission, it was determined that it no longer belonged there, and the project were transferred back in late 2021. During this time the build tooling for the project also changed from Leiningen to tools.build, which created further groupId churn (tools.build introduced special, useful semantics for com.github.username
groupIds that don't exist with Leiningen or Clojars).
tl;dr - historical reasons and naming is hard.
The library started life providing a single hardcoded animation sequence (the classic "/-\|" sequence), and then organically grew from there. Because the name "spinner" appears in various places where changing it would break things (the GitHub repo, Maven artifact ids, etc.), I decided to stick with the name even though it's no longer very accurate.
Copyright © 2014 Peter Monks
Distributed under the Apache License, Version 2.0.
SPDX-License-Identifier: Apache-2.0