spinner

A terminal spinner for tasks that have a non-deterministic time frame
term logo

Term::Spinner

spec status

A terminal spinner for tasks that have non-deterministic time frame.

Term::Screen provides an independent spinner component for crystal-term.

formats demo

Installation

  1. Add the dependency to your shard.yml:

    dependencies:
      term-spinner:
        github: crystal-term/spinner
    
  2. Run shards install

Usage

First the library must be required:

require "term-spinner"

Term::Spinner by default requires no arguments and defaults to the :classic formatter:

spinner = Term::Spinner.new

In addition you can provide a format message with a :spinner token where you would like the spinner to appear:

spinner = Term::Spinner.new("[:spinner] Loading ...", format: :pulse_2)

spinner.auto_spin # Automatic animation with default interval

sleep(2) # Perform task

spinner.stop("Done!") # Stop animation

This would produce an animation in your terminal that looks something like this:

[|] Loading ...

and when finished:

[] Loading ... Done!

API

#spin

This is the main workhorse of the spinner. Looping over the spin method will animate a given spinner.

loop do
  spinner.spin
end

#auto_spin

The auto_spin method performs automatic spinning in its own dedicated fiber.

spinner.auto_spin

The speed at which the spinning occurs is determined by the interval parameter, or defaults to the given format interval. The interval is a number in hertz, or (n * 100) milliseconds.

#pause

Pauses a spinner that's using auto_spin:

spinner.pause

#resume

Resumes a paused spinner:

spinner.resume

#run

Use run, passing a block with a job that will run and display the spinning animation. From within the block you can call stop, success, or error to finish the animation, or just allow the animation to finish when the block exits:

spinner.run do |spinner|
  ...
end

Optionally you can pass a stop message to the run command to display when the animation is finished:

spinner.run("Done!") do |spinner|
  ...
end

The stop message passed to run is overridden if you use stop, success, or error.

#start

To set a start time or reuse the same spinner after it has stopped, call start:

spinner.start

#stop

In order to stop the spinner, call stop. This will finish drawing the spinning animation and go to a new line:

spinner.stop

You can also pass a message to stop, which will be displayed after the animation:

spinner.stop("Done!")

#success

Use success to stop the spinning animation and replace the spinning symbol with success_mark (defaults to ) to indicate successful completion:

spinner = Term::Spinner.new("[:spinner] Task name")
spinner.success("(successful)")

This will produce:

[] Task name (successful)

#error

Use error to stop the spinning animation and replace the spinning symbol with error_mark (defaults to ) to indicate a failed completion:

spinner = Term::Spinner.new("[:spinner] Task name")
spinner.error("(error)")

This will produce:

[] Task name (error)

#update

Use update to dynamically change label name(s). Labels can be used like :spinner, allowing you to inject a value into a format string while the spinner is running.

Provide arbitrary token name(s) in the message string, such as :status:

spinner = TTY::Spinner.new("[:spinner] :status")

and then pass token name and value:

spinner.update(status: "Downloading File 1")

next start the animation:

spinner.run { ... }
# => | Downloading File 1

Once the animation finishes, or even while it's still running, you can update the status to whatever you want:

spinner.update(status: "Downloading File 2")

#reset

Reset the spinner to its initial state:

spinner.reset

Configuration

These are the values that can be supplied to Term::Spinner.new to customize the behavior of the spinner.

:format

Use one of the prefefined spinner styles by passing the formatting token :format:

spinner = Term::Spinner.new(format: :pulse_2)

All accepted formats are located in /src/spinner/format.cr

If you want an example of each of the formats in action, you can try running /examples/formats.cr

:frames

You can always set your own custom frames using the frames option:

spinner = Term::Spinner.new(frames: [".", "o", "0", "@", "*"])

:interval

The interval option accepts a number representing Hz. For instance, a value of 10, the default, will result in 10 animation frames per second. You can also pass in a Time::Span ti use as a delay between frames.

spinner = Term::Spinner.new(interval: 20) # 20 Hz (20 times per second)

:hide_cursor

Hides cursors whens pinning animation is running. Defaults to false.

spinner = Term::Spinner.new(hide_cursor: true)

:clear

After spinner is finished, clears its output. Defaults to false.

spinner = Term::Spinner.new(clear: true)

:success_mark

To change marker indicating successful completion use the success_mark option:

spinner = Term::Spinner.new(success_mark: "+")

:error_mark

To change marker indicating an error completion use the error_mark option:

spinner = Term::Spinner.new(error_mark: "x")

:output

The spinner only outputs to a console and when output is redirected to a file or a pipe it does nothing. This is so, for example, your error logs do not overflow with spinner output.

You can change where console output is streamed with output option:

spinner = Term::Spinner.new(output: STDOUT)

Term::Spinner::Multi API

#register

Create and register a Term::Spinner under the multispinner

new_spinner = multi_spinner.register("[:spinner] Task 1 name", **options)
# or
#   spinner = Term::Spinner.new("[:spinner] one")
#   sp1 = multi_spinner.register(spinner)

If no options are given it will use the options given to the multi_spinner when it was initialized to create the new spinner. If options are passed, they will override any options given to the top level spinner.

#auto_spin

To create a top level spinner that tracks the activity of all the registered spinners, the multispinner has to be given a message on initialization:

spinners = Term::Spinner::Multi.new("[:spinner] Top level spinner")

The top level multi spinner will perform spinning animation automatically when at least one of the registered spinners starts spinning.

If you register spinners without any tasks then you will have to manually control when the multispinner finishes by calling stop, success or error.

Alternatively, you can register spinners with tasks that will automatically animate and finish spinners when respective tasks are done.

The speed with which the spinning happens is determined by the :interval parameter. All the spinner formats have their default intervals specified.

manual async

In the case where you wish to have complete control over multiple spinners, you will need to perform all actions manually.

For example, create a multispinner that will track the status of all registered spinners:

spinners = Term::Spinner::Multi.new("[:spinner] top")

and then register all spinners with their formats:

sp1 = spinners.register "[:spinner] one"
sp2 = spinners.register "[:spinner] two"

Once registered, you can set spinners running in separate threads:

sp1.auto_spin
sp2.auto_spin

Finally, you need to stop each spinner manually, in our case we mark the second spinner as failure which in turn will stop the top level multi spinner automatically and mark it as failure:

sp1.success
sp2.error

The result may look like this:

 [] top
├── [] one
└── [] two

auto async tasks

In the case when you wish to execute async tasks and update individual spinners automatically, in any order, about their task status use #register and pass additional block parameter with the job to be executed.

For example, create a multi spinner that will track status of all registered spinners:

spinners = TTY::Spinner::Multi.new("[:spinner] top")

and then register spinners with their respective tasks:

spinners.register("[:spinner] one") { |sp| sleep(2); sp.success("yes 2") }
spinners.register("[:spinner] two") { |sp| sleep(3); sp.error("no 2") }

Finally, call #auto_spin to kick things off:

spinners.auto_spin

If any of the child spinners stop with an error then the top level spinner will be marked as failure.

#stop

In order to stop the multi spinner call stop. This will stop the top level spinner, if it exists, and any sub-spinners are still spinning.

spinners.stop

#success

Use success call to stop the spinning animation and replace the spinning symbol with a check mark character to indicate successful completion. This will also call #success on any sub-spinners that are still spinning.

spinners.success

#error

Use error call to stop the spinning animation and replace the spinning symbol with cross character to indicate error completion. This will also call #error on any sub-spinners that are still spinning.

spinners.error

:style

In addition to all the standard Spinner configuration options you can style a multispinner like so:

spinner = Term::Spinner::Multi.new("[:spinner] parent", style: {
  top: ". "
  middle: "|-> "
  bottom: "|__ "
})

Events

Term::Spinner emits :done, :success, and :error events. You can listen for these using the #on method.

spinner.on(:done) { ... }
spinner.on(:error) { ... }
spinner.on(:success) { ... }

Contributing

  1. Fork it (https://github.com/watzon/spinner/fork)
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors

Repository

spinner

Owner
Statistic
  • 20
  • 2
  • 1
  • 5
  • 1
  • 6 months ago
  • May 8, 2020
License

MIT License

Links
Synced at

Thu, 07 Nov 2024 05:10:53 GMT

Languages