tty-progressbar 0.17.0 → 0.18.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -0
- data/LICENSE.txt +1 -1
- data/README.md +492 -126
- data/lib/tty-progressbar.rb +2 -2
- data/lib/tty/progressbar.rb +168 -68
- data/lib/tty/progressbar/configuration.rb +121 -27
- data/lib/tty/progressbar/converter.rb +16 -19
- data/lib/tty/progressbar/formats.rb +120 -0
- data/lib/tty/progressbar/formatter.rb +33 -38
- data/lib/tty/progressbar/formatter/bar.rb +74 -27
- data/lib/tty/progressbar/formatter/byte_rate.rb +6 -20
- data/lib/tty/progressbar/formatter/current.rb +4 -19
- data/lib/tty/progressbar/formatter/current_byte.rb +9 -17
- data/lib/tty/progressbar/formatter/elapsed.rb +9 -18
- data/lib/tty/progressbar/formatter/estimated.rb +14 -18
- data/lib/tty/progressbar/formatter/estimated_time.rb +37 -0
- data/lib/tty/progressbar/formatter/mean_byte.rb +6 -20
- data/lib/tty/progressbar/formatter/mean_rate.rb +6 -20
- data/lib/tty/progressbar/formatter/percent.rb +10 -16
- data/lib/tty/progressbar/formatter/rate.rb +5 -19
- data/lib/tty/progressbar/formatter/total.rb +10 -16
- data/lib/tty/progressbar/formatter/total_byte.rb +14 -18
- data/lib/tty/progressbar/formatters.rb +53 -0
- data/lib/tty/progressbar/meter.rb +2 -2
- data/lib/tty/progressbar/multi.rb +61 -21
- data/lib/tty/progressbar/pipeline.rb +13 -6
- data/lib/tty/progressbar/timer.rb +89 -0
- data/lib/tty/progressbar/version.rb +1 -1
- metadata +44 -103
- data/Rakefile +0 -8
- data/examples/color.rb +0 -18
- data/examples/failure.rb +0 -12
- data/examples/iterator.rb +0 -5
- data/examples/lazy.rb +0 -6
- data/examples/multi/main_bar.rb +0 -13
- data/examples/multi/simple.rb +0 -13
- data/examples/multi/width.rb +0 -13
- data/examples/simple.rb +0 -7
- data/examples/slow_process.rb +0 -29
- data/examples/speed.rb +0 -11
- data/examples/threaded.rb +0 -14
- data/examples/tokens.rb +0 -12
- data/examples/unicode.rb +0 -7
- data/spec/spec_helper.rb +0 -53
- data/spec/unit/advance_spec.rb +0 -25
- data/spec/unit/clear_spec.rb +0 -17
- data/spec/unit/complete_spec.rb +0 -16
- data/spec/unit/converter/to_bytes_spec.rb +0 -47
- data/spec/unit/converter/to_seconds_spec.rb +0 -15
- data/spec/unit/converter/to_time_spec.rb +0 -19
- data/spec/unit/custom_formatter_spec.rb +0 -26
- data/spec/unit/custom_token_spec.rb +0 -14
- data/spec/unit/events_spec.rb +0 -33
- data/spec/unit/finish_spec.rb +0 -15
- data/spec/unit/formatter/bar_spec.rb +0 -33
- data/spec/unit/formatter/byte_rate_spec.rb +0 -32
- data/spec/unit/formatter/current_byte_spec.rb +0 -16
- data/spec/unit/formatter/current_spec.rb +0 -14
- data/spec/unit/formatter/elapsed_spec.rb +0 -58
- data/spec/unit/formatter/estimated_spec.rb +0 -27
- data/spec/unit/formatter/mean_byte_spec.rb +0 -32
- data/spec/unit/formatter/mean_rate_spec.rb +0 -31
- data/spec/unit/formatter/percent_spec.rb +0 -16
- data/spec/unit/formatter/rate_spec.rb +0 -31
- data/spec/unit/formatter/total_byte_spec.rb +0 -16
- data/spec/unit/formatter/total_spec.rb +0 -16
- data/spec/unit/frequency_spec.rb +0 -27
- data/spec/unit/head_spec.rb +0 -32
- data/spec/unit/hide_cursor_spec.rb +0 -27
- data/spec/unit/inspect_spec.rb +0 -11
- data/spec/unit/iterate_spec.rb +0 -79
- data/spec/unit/log_spec.rb +0 -29
- data/spec/unit/meter_spec.rb +0 -70
- data/spec/unit/multi/advance_spec.rb +0 -123
- data/spec/unit/multi/events_spec.rb +0 -115
- data/spec/unit/multi/finish_spec.rb +0 -41
- data/spec/unit/multi/line_inset_spec.rb +0 -65
- data/spec/unit/multi/register_spec.rb +0 -35
- data/spec/unit/multi/reset_spec.rb +0 -28
- data/spec/unit/multi/stop_spec.rb +0 -15
- data/spec/unit/multi/width_spec.rb +0 -118
- data/spec/unit/new_spec.rb +0 -76
- data/spec/unit/pipeline_spec.rb +0 -19
- data/spec/unit/ratio_spec.rb +0 -31
- data/spec/unit/render_spec.rb +0 -25
- data/spec/unit/reset_spec.rb +0 -31
- data/spec/unit/resize_spec.rb +0 -35
- data/spec/unit/set_current_spec.rb +0 -43
- data/spec/unit/start_spec.rb +0 -14
- data/spec/unit/stop_spec.rb +0 -19
- data/spec/unit/update_spec.rb +0 -22
- data/spec/unit/width_spec.rb +0 -86
- data/tasks/console.rake +0 -9
- data/tasks/coverage.rake +0 -9
- data/tasks/spec.rake +0 -27
- data/tty-progressbar.gemspec +0 -32
data/lib/tty-progressbar.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
require_relative
|
2
|
-
require_relative
|
1
|
+
require_relative "tty/progressbar"
|
2
|
+
require_relative "tty/progressbar/multi"
|
data/lib/tty/progressbar.rb
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
|
11
|
-
require_relative
|
12
|
-
require_relative
|
13
|
-
require_relative
|
14
|
-
require_relative
|
3
|
+
require "io/console"
|
4
|
+
require "forwardable"
|
5
|
+
require "monitor"
|
6
|
+
require "tty-cursor"
|
7
|
+
require "tty-screen"
|
8
|
+
require "strings-ansi"
|
9
|
+
require "unicode/display_width"
|
10
|
+
|
11
|
+
require_relative "progressbar/timer"
|
12
|
+
require_relative "progressbar/configuration"
|
13
|
+
require_relative "progressbar/formatters"
|
14
|
+
require_relative "progressbar/meter"
|
15
|
+
require_relative "progressbar/version"
|
15
16
|
|
16
17
|
module TTY
|
17
18
|
# Used for creating terminal progress bar
|
@@ -21,7 +22,9 @@ module TTY
|
|
21
22
|
extend Forwardable
|
22
23
|
include MonitorMixin
|
23
24
|
|
24
|
-
ECMA_CSI = "\e["
|
25
|
+
ECMA_CSI = "\e["
|
26
|
+
|
27
|
+
NEWLINE = "\n"
|
25
28
|
|
26
29
|
CURSOR_LOCK = Monitor.new
|
27
30
|
|
@@ -29,17 +32,15 @@ module TTY
|
|
29
32
|
|
30
33
|
attr_reader :current
|
31
34
|
|
32
|
-
attr_reader :start_at
|
33
|
-
|
34
35
|
attr_reader :row
|
35
36
|
|
36
|
-
def_delegators :@configuration, :total, :width, :
|
37
|
-
:
|
38
|
-
:
|
37
|
+
def_delegators :@configuration, :total, :width, :complete, :incomplete,
|
38
|
+
:head, :clear_head, :hide_cursor, :clear, :output,
|
39
|
+
:frequency, :interval, :inset, :width=, :unknown, :bar_format
|
39
40
|
|
40
41
|
def_delegators :@meter, :rate, :mean_rate
|
41
42
|
|
42
|
-
|
43
|
+
def_delegators :@timer, :elapsed_time, :start_time
|
43
44
|
|
44
45
|
# Determine terminal width
|
45
46
|
#
|
@@ -64,6 +65,12 @@ module TTY
|
|
64
65
|
|
65
66
|
# Create progress bar
|
66
67
|
#
|
68
|
+
# @example
|
69
|
+
# bar = TTY::Progressbar.new
|
70
|
+
# bar.configure do |config|
|
71
|
+
# config.total = 20
|
72
|
+
# end
|
73
|
+
#
|
67
74
|
# @param [String] format
|
68
75
|
# the tokenized string that displays the output
|
69
76
|
#
|
@@ -71,20 +78,29 @@ module TTY
|
|
71
78
|
# @option options [Numeric] :total
|
72
79
|
# the total number of steps to completion
|
73
80
|
# @option options [Numeric] :width
|
74
|
-
# the maximum width for the
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
81
|
+
# the maximum width for the progress bar except all formatting tokens
|
82
|
+
# @option option [String] :complete
|
83
|
+
# the complete character in progress animation
|
84
|
+
# @option options [String] :incomplete
|
85
|
+
# the incomplete character in progress animation
|
86
|
+
# @option options [String] :head
|
87
|
+
# the head character, defaults to complete
|
88
|
+
# @option options [String] :unknown
|
89
|
+
# the unknown character for indeterminate progress animation
|
90
|
+
# @option options [Boolean] :bar_format
|
91
|
+
# the preconfigured bar format name, defaults to :classic
|
82
92
|
# @option options [Object] :output
|
83
|
-
# the object that responds to print call
|
93
|
+
# the object that responds to print call, defaults to stderr
|
84
94
|
# @option options [Number] :frequency
|
85
|
-
# the frequency with which to display
|
95
|
+
# the frequency with which to display a progress bar per second
|
86
96
|
# @option options [Number] :interval
|
87
|
-
# the
|
97
|
+
# the time interval for sampling of speed measurement, defaults to 1 second
|
98
|
+
# @option options [Boolean] :hide_cursor
|
99
|
+
# whether or not to hide the cursor, defaults to false
|
100
|
+
# @option options [Boolean] :clear
|
101
|
+
# whether or not to clear the progress line, defaults to false
|
102
|
+
# @option options [Boolean] :clear_head
|
103
|
+
# whether or not to replace head character with complete, defaults to false
|
88
104
|
#
|
89
105
|
# @api public
|
90
106
|
def initialize(format, options = {})
|
@@ -97,34 +113,52 @@ module TTY
|
|
97
113
|
@configuration = TTY::ProgressBar::Configuration.new(options)
|
98
114
|
yield @configuration if block_given?
|
99
115
|
|
100
|
-
@
|
101
|
-
@meter
|
116
|
+
@formatters = TTY::ProgressBar::Formatters.new
|
117
|
+
@meter = TTY::ProgressBar::Meter.new(interval)
|
118
|
+
@timer = TTY::ProgressBar::Timer.new
|
102
119
|
@callbacks = Hash.new { |h, k| h[k] = [] }
|
103
120
|
|
104
|
-
@
|
121
|
+
@formatters.load(self)
|
105
122
|
reset
|
106
123
|
|
107
124
|
@first_render = true
|
108
|
-
@multibar
|
109
|
-
@row
|
125
|
+
@multibar = nil
|
126
|
+
@row = nil
|
110
127
|
end
|
111
128
|
|
112
129
|
# Reset progress to default configuration
|
113
130
|
#
|
114
131
|
# @api public
|
115
132
|
def reset
|
116
|
-
@width = 0 if
|
133
|
+
@width = 0 if indeterminate?
|
117
134
|
@render_period = frequency == 0 ? 0 : 1.0 / frequency
|
118
135
|
@current = 0
|
136
|
+
@unknown = 0
|
119
137
|
@last_render_time = Time.now
|
120
138
|
@last_render_width = 0
|
121
139
|
@done = false
|
122
140
|
@stopped = false
|
123
|
-
@
|
124
|
-
@started = false
|
141
|
+
@paused = false
|
125
142
|
@tokens = {}
|
126
143
|
|
127
144
|
@meter.clear
|
145
|
+
@timer.reset
|
146
|
+
end
|
147
|
+
|
148
|
+
# Access instance configuration
|
149
|
+
#
|
150
|
+
# @api public
|
151
|
+
def configure
|
152
|
+
yield @configuration
|
153
|
+
end
|
154
|
+
|
155
|
+
# Check if progress can be determined or not
|
156
|
+
#
|
157
|
+
# @return [Boolean]
|
158
|
+
#
|
159
|
+
# @api public
|
160
|
+
def indeterminate?
|
161
|
+
total.nil?
|
128
162
|
end
|
129
163
|
|
130
164
|
# Attach this bar to multi bar
|
@@ -137,13 +171,26 @@ module TTY
|
|
137
171
|
@multibar = multibar
|
138
172
|
end
|
139
173
|
|
174
|
+
# Use custom token formatter
|
175
|
+
#
|
176
|
+
# @param [Object] formatter_class
|
177
|
+
# the formatter class to add to formatting pipeline
|
178
|
+
#
|
179
|
+
# @api public
|
180
|
+
def use(formatter_class)
|
181
|
+
unless formatter_class.is_a?(Class)
|
182
|
+
raise ArgumentError, "Formatter needs to be a class"
|
183
|
+
end
|
184
|
+
|
185
|
+
@formatters.use(formatter_class.new(self))
|
186
|
+
end
|
187
|
+
|
140
188
|
# Start progression by drawing bar and setting time
|
141
189
|
#
|
142
190
|
# @api public
|
143
191
|
def start
|
144
192
|
synchronize do
|
145
|
-
@
|
146
|
-
@start_at = Time.now
|
193
|
+
@timer.start
|
147
194
|
@meter.start
|
148
195
|
end
|
149
196
|
|
@@ -163,17 +210,21 @@ module TTY
|
|
163
210
|
if progress.respond_to?(:to_hash)
|
164
211
|
tokens, progress = progress, 1
|
165
212
|
end
|
166
|
-
@
|
167
|
-
@current
|
168
|
-
|
213
|
+
@timer.start
|
214
|
+
@current += progress
|
215
|
+
# When progress is unknown increase by 2% up to max 200%, after
|
216
|
+
# that reset back to 0%
|
217
|
+
@unknown += 2 if indeterminate?
|
218
|
+
@unknown = 0 if @unknown > 199
|
219
|
+
@tokens = tokens
|
169
220
|
@meter.sample(Time.now, progress)
|
170
221
|
|
171
|
-
if !
|
222
|
+
if !indeterminate? && @current >= total
|
172
223
|
finish && return
|
173
224
|
end
|
174
225
|
|
175
|
-
|
176
|
-
|
226
|
+
return if (Time.now - @last_render_time) < @render_period
|
227
|
+
|
177
228
|
render
|
178
229
|
end
|
179
230
|
end
|
@@ -190,7 +241,7 @@ module TTY
|
|
190
241
|
# be convenient in "unsure number of iterations" situations
|
191
242
|
# (like downloading in chunks, when server may eventually send
|
192
243
|
# more chunks than predicted), but be careful to not pass infinite
|
193
|
-
# enumerators without
|
244
|
+
# enumerators without previously doing `.take(some_finite_number)`
|
194
245
|
# on them.
|
195
246
|
#
|
196
247
|
# @example
|
@@ -257,12 +308,20 @@ module TTY
|
|
257
308
|
|
258
309
|
# Ratio of completed over total steps
|
259
310
|
#
|
311
|
+
# When the total is unknown the progress ratio oscillates
|
312
|
+
# by going up from 0 to 1 and then down from 1 to 0 and
|
313
|
+
# up again to infinity.
|
314
|
+
#
|
260
315
|
# @return [Float]
|
261
316
|
#
|
262
317
|
# @api public
|
263
318
|
def ratio
|
264
319
|
synchronize do
|
265
|
-
proportion =
|
320
|
+
proportion = if total
|
321
|
+
total > 0 ? (@current.to_f / total) : 0
|
322
|
+
else
|
323
|
+
(@unknown > 100 ? 200 - @unknown : @unknown).to_f / 100
|
324
|
+
end
|
266
325
|
[[proportion, 0].max, 1].min
|
267
326
|
end
|
268
327
|
end
|
@@ -272,7 +331,9 @@ module TTY
|
|
272
331
|
# @api private
|
273
332
|
def render
|
274
333
|
return if done?
|
275
|
-
|
334
|
+
|
335
|
+
if hide_cursor && @last_render_width == 0 &&
|
336
|
+
(indeterminate? || @current < total)
|
276
337
|
write(TTY::Cursor.hide)
|
277
338
|
end
|
278
339
|
|
@@ -281,7 +342,7 @@ module TTY
|
|
281
342
|
update(inset: self.class.display_columns(characters_in))
|
282
343
|
end
|
283
344
|
|
284
|
-
formatted = @
|
345
|
+
formatted = @formatters.decorate(@format)
|
285
346
|
@tokens.each do |token, val|
|
286
347
|
formatted = formatted.gsub(":#{token}", val)
|
287
348
|
end
|
@@ -304,7 +365,7 @@ module TTY
|
|
304
365
|
if @first_render
|
305
366
|
@row = @multibar.next_row
|
306
367
|
yield if block_given?
|
307
|
-
output.print
|
368
|
+
output.print NEWLINE
|
308
369
|
@first_render = false
|
309
370
|
else
|
310
371
|
lines_up = (@multibar.rows + 1) - @row
|
@@ -343,6 +404,7 @@ module TTY
|
|
343
404
|
# @api public
|
344
405
|
def resize(new_width = nil)
|
345
406
|
return if done?
|
407
|
+
|
346
408
|
synchronize do
|
347
409
|
clear_line
|
348
410
|
if new_width
|
@@ -356,12 +418,14 @@ module TTY
|
|
356
418
|
# @api public
|
357
419
|
def finish
|
358
420
|
return if done?
|
359
|
-
|
421
|
+
|
422
|
+
@current = total unless indeterminate?
|
360
423
|
render
|
361
|
-
clear ? clear_line : write(
|
424
|
+
clear ? clear_line : write(NEWLINE, false)
|
362
425
|
ensure
|
363
426
|
@meter.clear
|
364
427
|
@done = true
|
428
|
+
@timer.stop
|
365
429
|
|
366
430
|
# reenable cursor if it is turned off
|
367
431
|
if hide_cursor && @last_render_width != 0
|
@@ -371,31 +435,57 @@ module TTY
|
|
371
435
|
emit(:done)
|
372
436
|
end
|
373
437
|
|
438
|
+
# Resume rendering when bar is done, stopped or paused
|
439
|
+
#
|
440
|
+
# @api public
|
441
|
+
def resume
|
442
|
+
synchronize do
|
443
|
+
@done = false
|
444
|
+
@stopped = false
|
445
|
+
@paused = false
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
374
449
|
# Stop and cancel the progress at the current position
|
375
450
|
#
|
376
451
|
# @api public
|
377
452
|
def stop
|
378
|
-
# reenable cursor if it is turned off
|
379
|
-
if hide_cursor && @last_render_width != 0
|
380
|
-
write(TTY::Cursor.show, false)
|
381
|
-
end
|
382
453
|
return if done?
|
454
|
+
|
383
455
|
render
|
384
|
-
clear ? clear_line : write(
|
456
|
+
clear ? clear_line : write(NEWLINE, false)
|
385
457
|
ensure
|
386
458
|
@meter.clear
|
387
459
|
@stopped = true
|
460
|
+
@timer.stop
|
461
|
+
|
462
|
+
# reenable cursor if it is turned off
|
463
|
+
if hide_cursor && @last_render_width != 0
|
464
|
+
write(TTY::Cursor.show, false)
|
465
|
+
end
|
466
|
+
|
388
467
|
emit(:stopped)
|
389
468
|
end
|
390
469
|
|
470
|
+
# Pause the progress at the current position
|
471
|
+
#
|
472
|
+
# @api public
|
473
|
+
def pause
|
474
|
+
synchronize do
|
475
|
+
@paused = true
|
476
|
+
@timer.stop
|
477
|
+
emit(:paused)
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
391
481
|
# Clear current line
|
392
482
|
#
|
393
483
|
# @api public
|
394
484
|
def clear_line
|
395
|
-
output.print(ECMA_CSI
|
485
|
+
output.print("#{ECMA_CSI}0m#{TTY::Cursor.clear_line}")
|
396
486
|
end
|
397
487
|
|
398
|
-
# Check if progress is
|
488
|
+
# Check if progress is finished
|
399
489
|
#
|
400
490
|
# @return [Boolean]
|
401
491
|
# true when progress finished, false otherwise
|
@@ -414,13 +504,22 @@ module TTY
|
|
414
504
|
@stopped
|
415
505
|
end
|
416
506
|
|
417
|
-
# Check if progress is
|
507
|
+
# Check if progress is paused
|
508
|
+
#
|
509
|
+
# @return [Boolean]
|
510
|
+
#
|
511
|
+
# @api public
|
512
|
+
def paused?
|
513
|
+
@paused
|
514
|
+
end
|
515
|
+
|
516
|
+
# Check if progress is finished, stopped or paused
|
418
517
|
#
|
419
518
|
# @return [Boolean]
|
420
519
|
#
|
421
520
|
# @api public
|
422
521
|
def done?
|
423
|
-
@done || @stopped
|
522
|
+
@done || @stopped || @paused
|
424
523
|
end
|
425
524
|
|
426
525
|
# Register callback with this bar
|
@@ -445,14 +544,14 @@ module TTY
|
|
445
544
|
#
|
446
545
|
# @api public
|
447
546
|
def log(message)
|
448
|
-
sanitized_message = message.gsub(/\r|\n/,
|
547
|
+
sanitized_message = message.gsub(/\r|\n/, " ")
|
449
548
|
if done?
|
450
|
-
write(sanitized_message
|
549
|
+
write("#{sanitized_message}#{NEWLINE}", false)
|
451
550
|
return
|
452
551
|
end
|
453
552
|
sanitized_message = padout(sanitized_message)
|
454
553
|
|
455
|
-
write(sanitized_message
|
554
|
+
write("#{sanitized_message}#{NEWLINE}", true)
|
456
555
|
render
|
457
556
|
end
|
458
557
|
|
@@ -472,13 +571,14 @@ module TTY
|
|
472
571
|
# @api public
|
473
572
|
def inspect
|
474
573
|
"#<#{self.class.name} " \
|
475
|
-
"@format=\"#{format}\", " \
|
574
|
+
"@format=\"#{@format}\", " \
|
476
575
|
"@current=\"#{@current}\", " \
|
477
576
|
"@total=\"#{total}\", " \
|
478
577
|
"@width=\"#{width}\", " \
|
479
578
|
"@complete=\"#{complete}\", " \
|
480
579
|
"@head=\"#{head}\", " \
|
481
580
|
"@incomplete=\"#{incomplete}\", " \
|
581
|
+
"@unknown=\"#{unknown}\", " \
|
482
582
|
"@interval=\"#{interval}\">"
|
483
583
|
end
|
484
584
|
|
@@ -492,7 +592,7 @@ module TTY
|
|
492
592
|
|
493
593
|
if @last_render_width > message_length
|
494
594
|
remaining_width = @last_render_width - message_length
|
495
|
-
message +=
|
595
|
+
message += " " * remaining_width
|
496
596
|
end
|
497
597
|
message
|
498
598
|
end
|
@@ -505,7 +605,7 @@ module TTY
|
|
505
605
|
# @api private
|
506
606
|
def emit(name, *args)
|
507
607
|
@callbacks[name].each do |callback|
|
508
|
-
callback.
|
608
|
+
callback.(*args)
|
509
609
|
end
|
510
610
|
end
|
511
611
|
|