Skip to content

Commit

Permalink
Add ability to pause a bar progression and suspend time measurements
Browse files Browse the repository at this point in the history
  • Loading branch information
piotrmurach committed Jan 11, 2021
1 parent 6e028c9 commit 9b4fe85
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* Add :bar_format option to allow selecting preconfigured bar displays
* Add :eta_time format token to display the estimated time of day at completion
* Add measurement of the total elapsed time that ignores stopped time intervals
* Add #pause to prevent bar from continuing progression and suspend time measurements

### Changed
* Change Multi#stopped? to check that all bars are stopped
Expand Down
45 changes: 32 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,13 @@ Or install it yourself as:
* [2.7 update](#27-update)
* [2.8 finish](#28-finish)
* [2.9 stop](#29-stop)
* [2.10 reset](#210-reset)
* [2.11 resume](#211-resume)
* [2.12 complete?](#212-complete)
* [2.13 indeterminate?](#213-indeterminate)
* [2.14 resize](#214-resize)
* [2.15 on](#215-on)
* [2.10 pause](#210-pause)
* [2.11 reset](#211-reset)
* [2.12 resume](#212-resume)
* [2.13 complete?](#213-complete)
* [2.14 indeterminate?](#214-indeterminate)
* [2.15 resize](#215-resize)
* [2.16 on](#216-on)
* [3. Configuration](#3-configuration)
* [3.1 :total](#31-total)
* [3.1 :width](#32-width)
Expand Down Expand Up @@ -291,7 +292,17 @@ In order to immediately stop the bar in the current position and thus prevent an
bar.stop
```

### 2.10 reset
### 2.10 pause

A running progress bar can be paused at the current position using `pause` method:

```ruby
bar.pause
```

A paused progress bar will stop accumulating any time measurements like elapsed time. It also won't return to a new line, so a progress animation can be smoothly resumed.

### 2.11 reset

In order to reset currently running or finished progress bar to its original configuration and initial position use `reset` like so:

Expand All @@ -301,31 +312,33 @@ bar.reset

After resetting the bar if you wish to draw and start the bar and its timers use `start` call.

### 2.11 resume
### 2.12 resume

When a bar is stopped, you can continue its progression using the `resume` method.
When a bar is stopped or paused, you can continue its progression using the `resume` method.

```ruby
bar.resume
```

### 2.12 complete?
A resumed progression will continue accumulating the total elapsed time without including time intervals for pausing or stopping.

### 2.13 complete?

During progression you can check if a bar is finished or not by calling `complete?`. The bar will only return `true` if the progression finished successfully, otherwise `false` will be returned.

```ruby
bar.complete? # => false
```

### 2.13 indeterminate?
### 2.14 indeterminate?

You can make a progress bar indeterminate by setting `:total` to nil. In this state, an animation is displayed to show unbounded task. You can check if the progress bar is indeterminate with the `indeterminate?` method:

```ruby
bar.indeterminate? # => false
```

### 2.14 resize
### 2.15 resize

If you wish for a progress bar to change it's current width, you can use `resize` by passing in a new desired length. However, if you don't provide any width the `resize` will use terminal current width as its base for scaling.

Expand All @@ -340,7 +353,7 @@ To handle automatic resizing you can trap `:WINCH` signal:
trap(:WINCH) { bar.resize }
```

### 2.15 on
### 2.16 on

The progress bar fires events when it is progressing, stopped or finished. You can register to listen for events using the `on` message.

Expand All @@ -362,6 +375,12 @@ Alternatively, when the progress bar gets stopped the `:stopped` event is fired.
bar.on(:stopped) { ... }
```

Anytime a progress bar is paused the `:paused` event will be fired. To listen for this event do:

```ruby
bar.on(:paused) { ... }
```

## 3. Configuration

There are number of configuration options that can be provided:
Expand Down
34 changes: 28 additions & 6 deletions lib/tty/progressbar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ def reset
@last_render_width = 0
@done = false
@stopped = false
@paused = false
@start_at = Time.now
@elapsed_time = 0
@time_offset = 0
Expand Down Expand Up @@ -435,13 +436,16 @@ def finish
emit(:done)
end

# Resume rendering when bar is done or stopped to update information
# Resume rendering when bar is done, stopped or paused
#
# @api public
def resume
@started = false
@done = false
@stopped = false
synchronize do
@started = false
@done = false
@stopped = false
@paused = false
end
end

# Stop and cancel the progress at the current position
Expand All @@ -463,6 +467,15 @@ def stop
emit(:stopped)
end

# Pause the progress at the current position
#
# @api public
def pause
@paused = true
@time_offset += Time.now - @start_at
emit(:paused)
end

# Clear current line
#
# @api public
Expand All @@ -489,13 +502,22 @@ def stopped?
@stopped
end

# Check if progress is finished or stopped
# Check if progress is paused
#
# @return [Boolean]
#
# @api public
def paused?
@paused
end

# Check if progress is finished, stopped or paused
#
# @return [Boolean]
#
# @api public
def done?
@done || @stopped
@done || @stopped || @paused
end

# Register callback with this bar
Expand Down
10 changes: 10 additions & 0 deletions spec/unit/events_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,14 @@

expect(events).to eq([:stopped])
end

it "emits :paused event" do
events = []
bar = TTY::ProgressBar.new("[:bar]", output: output, total: 5)
bar.on(:paused) { events << :paused }

bar.pause

expect(events).to eq([:paused])
end
end
37 changes: 37 additions & 0 deletions spec/unit/resume_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,41 @@
"\e[1G[==========] 13/13 100% 13B/13B 1B/s 1B/s 1.00/s 1.00/s 4s 0s\n"
].join)
end

it "resumes paused progression with all the metrics" do
time_now = Time.local(2021, 1, 11, 12, 0, 0)
Timecop.freeze(time_now)
format = "[:bar] :current/:total :percent " \
":current_byte/:total_byte :byte_rate/s :mean_byte/s " \
":rate/s :mean_rate/s :elapsed :eta"

progress = described_class.new(format, output: output, total: 10)

3.times do |i|
time_now = Time.local(2021, 1, 11, 12, 0, 1 + i)
Timecop.freeze(time_now)
progress.advance
end
progress.pause
expect(progress.paused?).to eq(true)

progress.resume
expect(progress.paused?).to eq(false)

3.times do |i|
time_now = Time.local(2021, 1, 11, 12, 0, 4 + i)
Timecop.freeze(time_now)
progress.advance
end

output.rewind
expect(output.read).to eq([
"\e[1G[= ] 1/10 10% 1B/10B 1B/s 1B/s 1.00/s 1.00/s 0s 0s",
"\e[1G[== ] 2/10 20% 2B/10B 1B/s 1B/s 1.00/s 1.00/s 1s 4s",
"\e[1G[=== ] 3/10 30% 3B/10B 1B/s 1B/s 1.00/s 1.00/s 2s 4s", # pause render
"\e[1G[==== ] 4/10 40% 4B/10B 1B/s 1B/s 1.00/s 1.00/s 2s 3s",
"\e[1G[===== ] 5/10 50% 5B/10B 1B/s 1B/s 1.00/s 1.00/s 3s 3s",
"\e[1G[====== ] 6/10 60% 6B/10B 1B/s 1B/s 1.00/s 1.00/s 4s 2s"
].join)
end
end

0 comments on commit 9b4fe85

Please sign in to comment.