tty-progressbar 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b9e021f67756883c39075abe088ad0861ef85582
4
- data.tar.gz: 08b1cd0a9925899b0a7c6ace9dddeef1a1545953
3
+ metadata.gz: c2470861861ae00abd4f276cede9731c712d2508
4
+ data.tar.gz: 38d29289ddfd613781defa037dc1181654ef7a3a
5
5
  SHA512:
6
- metadata.gz: 7719a9ffa8814c51e301dd5e441a4516e87230ee7f66780ba40c3b29556bdd086f5dc18b6ee024b2b54b1344bb52996c51048837bafffcc560164c4b44165f0e
7
- data.tar.gz: 98974cccbbad3174dcbf24dfd66957db87aca29f79ba94f4f287c6fff789251130a042c6e2ed8ae9831ea1be95380f433c3b14093a9ae01b282d4a4331f0ef97
6
+ metadata.gz: 1e2e6a01da4dcb082e8e55e1ecfc18841dd42a1cf1a2d622aa6d081d13f112a9f28fa4ef32cec33ffa68f50578a979eb3e4398f28145ac7204114a18a4145eaa
7
+ data.tar.gz: 5226faf2809e8939088d0d9ab4b91f391c687bc7e92149df9b13d0fbd6a7ea0a7a337863d9c1c54a59a6cbe92088605b0e915f6c7640d4b88d9e32b71fb6111a
@@ -7,9 +7,10 @@ script: "bundle exec rake ci"
7
7
  rvm:
8
8
  - 2.0.0
9
9
  - 2.1.10
10
- - 2.2.8
10
+ - 2.2.9
11
11
  - 2.3.6
12
- - 2.4.3
12
+ - 2.4.4
13
+ - 2.5.1
13
14
  - ruby-head
14
15
  - jruby-9.1.5.0
15
16
  - jruby-head
@@ -1,6 +1,25 @@
1
1
  # Change log
2
2
 
3
- ## [v0.14.0] - 2017-01-17
3
+ ## [v0.15.0] - 2018-06-24
4
+
5
+ ### Added
6
+ * Add #format= for overriding formatting string
7
+ * Add #display_columns for determining display width of multibyte characters
8
+ * Add :inset option to bar configuration options
9
+ * Add ability to configure width for multi bar with top level bar
10
+ * Add unicode-display_width dependency
11
+
12
+ ### Changed
13
+ * Change #update to only set configuration if actually present
14
+ * Change bar formatter to handle multibyte characters
15
+
16
+ ### Fixed
17
+ * Fix to stop reseting multibar state when registered bar reset by Eric Hodel(@drbrain)
18
+ * Fix rendered bar to pad formatted output when it gets shorter by Eric Hodel(@drbrain)
19
+ * Fix multi bar to advance in steps matching each bar advance progress
20
+ * Fix multi bar rendering for widths exceeding screen columns count
21
+
22
+ ## [v0.14.0] - 2018-01-17
4
23
 
5
24
  ### Changed
6
25
  * Change to only output to a console and stop output to a file, pipe etc...
@@ -160,6 +179,7 @@
160
179
 
161
180
  * Initial implementation and release
162
181
 
182
+ [v0.15.0]: https://github.com/peter-murach/tty-progressbar/compare/v0.14.0...v0.15.0
163
183
  [v0.14.0]: https://github.com/peter-murach/tty-progressbar/compare/v0.13.0...v0.14.0
164
184
  [v0.13.0]: https://github.com/peter-murach/tty-progressbar/compare/v0.12.2...v0.13.0
165
185
  [v0.12.2]: https://github.com/peter-murach/tty-progressbar/compare/v0.12.1...v0.12.2
data/README.md CHANGED
@@ -26,6 +26,7 @@
26
26
  * Includes many predefined tokens to calculate ETA, Bytes ... [tokens](#41-tokens)
27
27
  * Allows to define your [custom tokens](#42-custom-formatters)
28
28
  * Supports parallel multi progress bars [multi](#6-ttyprogressbarmulti-api)
29
+ * Handles Unicode characters in progress bar [unicode](#44-unicode)
29
30
  * Works on all ECMA-48 compatible terminals
30
31
 
31
32
  ## Installation
@@ -70,6 +71,7 @@ Or install it yourself as:
70
71
  * [4.1 Tokens](#41-tokens)
71
72
  * [4.2 Custom Formatters](#42-custom-formatters)
72
73
  * [4.3 Custom Tokens](#43-custom-tokens)
74
+ * [4.4 Unicode](#44-unicode)
73
75
  * [5. Logging](#5-logging)
74
76
  * [6. TTY::ProgressBar::Multi API](#6-ttyprogressbarmulti-api)
75
77
  * [6.1 new](#61-new)
@@ -302,10 +304,10 @@ trap(:WINCH) { bar.resize }
302
304
 
303
305
  The progress bar fires events when it is progressing, stopped or finished. You can register to listen for events using the `on` message.
304
306
 
305
- Every time an `advance` is called the `:progress` event gets fired which you can listen for:
307
+ Every time an `advance` is called the `:progress` event gets fired which you can listen for inside a block which includes the actual amount of progress as a first yielded argument:
306
308
 
307
309
  ```ruby
308
- bar.on(:progress) { ... }
310
+ bar.on(:progress) { |amount| ... }
309
311
  ```
310
312
 
311
313
  When the progress bar finishes and completes then the `:done` event is fired. You can listen for this event:
@@ -474,6 +476,26 @@ which outputs:
474
476
  (4) Bye Piotr!
475
477
  ```
476
478
 
479
+ ### 4.4 Unicode
480
+
481
+ The format string as well as `:complete`, `:head` and `:incompelte` configuration options can contain Unicode characters that aren't monospaced.
482
+
483
+ For example, you can specify complete bar progression character to be Unicode non-monospaced:
484
+
485
+ ```ruby
486
+ bar = TTY::ProgressBar.new("Unicode [:bar]", total: 30, complete: 'あ')
487
+ #
488
+ # => Unicode [あああああああああああああああ]
489
+ ```
490
+
491
+ Similarly, the formatted string can include Unicode characters:
492
+
493
+ ```ruby
494
+ bar = TTY::ProgressBar.new("あめかんむり[:bar]", total: 20)
495
+ #
496
+ # => あめかんむり[== ]
497
+ ```
498
+
477
499
  ## 5. Logging
478
500
 
479
501
  If you want to print messages out to terminal along with the progress bar use the `log` method. The messages will appear above the progress bar and will continue scrolling up as more are logged out.
@@ -19,3 +19,5 @@ environment:
19
19
  - ruby_version: "23-x64"
20
20
  - ruby_version: "24"
21
21
  - ruby_version: "24-x64"
22
+ - ruby_version: "25"
23
+ - ruby_version: "25-x64"
@@ -0,0 +1,13 @@
1
+ require_relative '../../lib/tty-progressbar'
2
+
3
+ bars = TTY::ProgressBar::Multi.new("main [:bar] :percent")
4
+
5
+ bar1 = bars.register "foo [:bar] :percent", total: 150
6
+ bar2 = bars.register "bar [:bar] :percent", total: 250
7
+ bar3 = bars.register "baz [:bar] :percent", total: 100
8
+
9
+ th1 = Thread.new { 15.times { sleep(0.1); bar1.advance(10) } }
10
+ th2 = Thread.new { 50.times { sleep(0.1); bar2.advance(5)} }
11
+ th3 = Thread.new { 50.times { sleep(0.1); bar3.advance(5) } }
12
+
13
+ [th1, th2, th3].each(&:join)
@@ -0,0 +1,7 @@
1
+ require_relative '../lib/tty-progressbar'
2
+
3
+ bar = TTY::ProgressBar.new("Unicode [:bar]", total: 30, complete: 'あ')
4
+ 30.times do
5
+ sleep(0.1)
6
+ bar.advance
7
+ end
@@ -5,6 +5,7 @@ require 'forwardable'
5
5
  require 'monitor'
6
6
  require 'tty-cursor'
7
7
  require 'tty-screen'
8
+ require 'unicode/display_width'
8
9
 
9
10
  require_relative 'progressbar/configuration'
10
11
  require_relative 'progressbar/formatter'
@@ -23,7 +24,7 @@ module TTY
23
24
 
24
25
  CURSOR_LOCK = Monitor.new
25
26
 
26
- attr_reader :format
27
+ attr_accessor :format
27
28
 
28
29
  attr_reader :current
29
30
 
@@ -33,12 +34,33 @@ module TTY
33
34
 
34
35
  def_delegators :@configuration, :total, :width, :no_width,
35
36
  :complete, :incomplete, :head, :hide_cursor, :clear,
36
- :output, :frequency, :interval, :width=
37
+ :output, :frequency, :interval, :inset, :width=
37
38
 
38
39
  def_delegators :@meter, :rate, :mean_rate
39
40
 
40
41
  def_delegator :@formatter, :use
41
42
 
43
+ # Determine terminal width
44
+ #
45
+ # @return [Integer]
46
+ #
47
+ # @api public
48
+ def self.max_columns
49
+ TTY::Screen.width
50
+ end
51
+
52
+ # Determine the monospace display width of a string
53
+ #
54
+ # @param [String] value
55
+ # the value to determine width of
56
+ #
57
+ # @return [Integer]
58
+ #
59
+ # @api public
60
+ def self.display_columns(value)
61
+ Unicode::DisplayWidth.of(value)
62
+ end
63
+
42
64
  # Create progress bar
43
65
  #
44
66
  # @param [String] format
@@ -80,6 +102,10 @@ module TTY
80
102
 
81
103
  @formatter.load
82
104
  reset
105
+
106
+ @first_render = true
107
+ @multibar = nil
108
+ @row = nil
83
109
  end
84
110
 
85
111
  # Reset progress to default configuration
@@ -96,9 +122,6 @@ module TTY
96
122
  @start_at = Time.now
97
123
  @started = false
98
124
  @tokens = {}
99
- @multibar = nil
100
- @row = nil
101
- @first_render = true
102
125
 
103
126
  @meter.clear
104
127
  end
@@ -135,7 +158,7 @@ module TTY
135
158
  return if done?
136
159
 
137
160
  synchronize do
138
- emit(:progress)
161
+ emit(:progress, progress)
139
162
  if progress.respond_to?(:to_hash)
140
163
  tokens, progress = progress, 1
141
164
  end
@@ -201,7 +224,9 @@ module TTY
201
224
  def update(options = {})
202
225
  synchronize do
203
226
  options.each do |name, val|
204
- @configuration.public_send("#{name}=", val)
227
+ if @configuration.respond_to?("#{name}=")
228
+ @configuration.public_send("#{name}=", val)
229
+ end
205
230
  end
206
231
  end
207
232
  end
@@ -250,14 +275,22 @@ module TTY
250
275
  write(TTY::Cursor.hide)
251
276
  end
252
277
 
278
+ if @multibar
279
+ characters_in = @multibar.line_inset(self)
280
+ update(inset: self.class.display_columns(characters_in))
281
+ end
282
+
253
283
  formatted = @formatter.decorate(self, @format)
254
284
  @tokens.each do |token, val|
255
285
  formatted = formatted.gsub(":#{token}", val)
256
286
  end
257
- write(formatted, true)
287
+
288
+ padded = padout(formatted)
289
+
290
+ write(padded, true)
258
291
 
259
292
  @last_render_time = Time.now
260
- @last_render_width = formatted.length
293
+ @last_render_width = self.class.display_columns(formatted)
261
294
  end
262
295
 
263
296
  # Move cursor to a row of the current bar if the bar is rendered
@@ -420,15 +453,6 @@ module TTY
420
453
  render
421
454
  end
422
455
 
423
- # Determine terminal width
424
- #
425
- # @return [Integer]
426
- #
427
- # @api public
428
- def max_columns
429
- TTY::Screen.width
430
- end
431
-
432
456
  # Show bar format
433
457
  #
434
458
  # @return [String]
@@ -461,8 +485,10 @@ module TTY
461
485
  #
462
486
  # @api private
463
487
  def padout(message)
464
- if @last_render_width > message.length
465
- remaining_width = @last_render_width - message.length
488
+ message_length = self.class.display_columns(message)
489
+
490
+ if @last_render_width > message_length
491
+ remaining_width = @last_render_width - message_length
466
492
  message += ' ' * remaining_width
467
493
  end
468
494
  message
@@ -5,6 +5,7 @@ module TTY
5
5
  attr_reader :total
6
6
 
7
7
  attr_accessor :width
8
+ #attr_reader :width
8
9
 
9
10
  attr_accessor :no_width
10
11
 
@@ -24,9 +25,11 @@ module TTY
24
25
 
25
26
  attr_accessor :interval
26
27
 
28
+ attr_accessor :inset
29
+
27
30
  def initialize(options)
28
31
  self.total = options[:total] if options[:total]
29
- @width = options.fetch(:width) { total }
32
+ @width = options.fetch(:width) { total }
30
33
  @no_width = options.fetch(:no_width) { false }
31
34
  @incomplete = options.fetch(:incomplete) { ' ' }
32
35
  @complete = options.fetch(:complete) { '=' }
@@ -36,12 +39,23 @@ module TTY
36
39
  @output = options.fetch(:output) { $stderr }
37
40
  @frequency = options.fetch(:frequency) { 0 } # 0Hz
38
41
  @interval = options.fetch(:interval) { 1 } # 1 sec
42
+ @inset = options.fetch(:inset) { 0 }
39
43
  end
40
44
 
45
+ # def width=(value)
46
+ # return if value.nil?
47
+
48
+ # if value < ProgressBar.max_columns
49
+ # @width = value
50
+ # else
51
+ # @width = ProgressBar.max_columns
52
+ # end
53
+ # end
54
+
41
55
  def total=(value)
42
56
  fail ArgumentError unless value
43
57
  @total = value
44
- @width = value unless width
58
+ self.width = value if width.nil?
45
59
  end
46
60
  end # Configuration
47
61
  end # ProgressBar
@@ -30,12 +30,23 @@ module TTY
30
30
  #
31
31
  # @api public
32
32
  def format(value)
33
- available_space = [0, @progress.max_columns - value.gsub(/:bar/, '').length].max
33
+ without_bar = value.gsub(/:bar/, '')
34
+ available_space = [0, ProgressBar.max_columns -
35
+ ProgressBar.display_columns(without_bar) -
36
+ @progress.inset].max
34
37
  width = [@progress.width, available_space].min
35
- complete_length = (width * @progress.ratio).round
36
- complete = Array.new(complete_length, @progress.complete)
37
- incomplete = Array.new(width - complete_length, @progress.incomplete)
38
- complete[-1] = @progress.head if complete_length > 0
38
+ complete_bar_length = (width * @progress.ratio).round
39
+ complete_char_length = ProgressBar.display_columns(@progress.complete)
40
+ incomplete_char_length = ProgressBar.display_columns(@progress.incomplete)
41
+
42
+ # decimal number of items only when unicode chars are used
43
+ # otherwise it has no effect on regular ascii chars
44
+ complete_items = (complete_bar_length / complete_char_length.to_f).round
45
+ incomplete_items = (width - complete_items * complete_char_length) / incomplete_char_length
46
+
47
+ complete = Array.new(complete_items, @progress.complete)
48
+ incomplete = Array.new(incomplete_items, @progress.incomplete)
49
+ complete[-1] = @progress.head if complete_bar_length > 0
39
50
 
40
51
  bar = ''
41
52
  bar += complete.join
@@ -18,6 +18,8 @@ module TTY
18
18
 
19
19
  def_delegators :@bars, :each, :empty?, :length, :[]
20
20
 
21
+ def_delegators :@top_bar, :width, :width=
22
+
21
23
  DEFAULT_INSET = {
22
24
  top: Gem.win_platform? ? '+ ' : "\u250c ",
23
25
  middle: Gem.win_platform? ? '|-- ' : "\u251c\u2500\u2500 ",
@@ -51,6 +53,9 @@ module TTY
51
53
  @top_bar = nil
52
54
  @top_bar = register(format, observable: false) if format
53
55
 
56
+ @width = @options[:width]
57
+ @top_bar.update(width: @width) if @width
58
+
54
59
  @callbacks = {
55
60
  progress: [],
56
61
  stopped: [],
@@ -73,7 +78,8 @@ module TTY
73
78
  @bars << bar
74
79
  observe(bar) if observable
75
80
  if @top_bar
76
- @top_bar.update(total: total, width: total)
81
+ @top_bar.update(total: total)
82
+ @top_bar.update(width: total) unless @width
77
83
  end
78
84
  end
79
85
 
@@ -105,9 +111,9 @@ module TTY
105
111
  #
106
112
  # @api private
107
113
  def progress_handler
108
- proc do
109
- @top_bar.advance if @top_bar
110
- emit(:progress)
114
+ -> (progress) do
115
+ @top_bar.advance(progress) if @top_bar
116
+ emit(:progress, progress)
111
117
  end
112
118
  end
113
119
 
@@ -1,5 +1,5 @@
1
1
  module TTY
2
2
  class ProgressBar
3
- VERSION = '0.14.0'.freeze
3
+ VERSION = '0.15.0'.freeze
4
4
  end # ProgressBar
5
5
  end # TTY
@@ -17,6 +17,7 @@ require 'timecop'
17
17
  require 'tty-progressbar'
18
18
 
19
19
  class StringIO
20
+ undef_method :tty?
20
21
  def tty?
21
22
  true
22
23
  end
@@ -8,7 +8,7 @@ RSpec.describe TTY::ProgressBar, 'custom token' do
8
8
  output.rewind
9
9
  expect(output.read).to eq([
10
10
  "\e[1G(1) Hello Piotr!",
11
- "\e[1G(4) Bye Piotr!\n"
11
+ "\e[1G(4) Bye Piotr! \n"
12
12
  ].join)
13
13
  end
14
14
  end
@@ -0,0 +1,28 @@
1
+ RSpec.describe TTY::ProgressBar::Multi, '#reset' do
2
+ let(:output) { StringIO.new('', 'w+') }
3
+
4
+ it "leaves multibar state alone" do
5
+ main = TTY::ProgressBar::Multi.new("", output: output, total: 10)
6
+ progress = main.register("[:bar]")
7
+ progress.advance(10)
8
+ expect(progress.complete?).to be(true)
9
+ progress.reset
10
+ expect(progress.complete?).to be(false)
11
+ progress.advance(10)
12
+ output.rewind
13
+
14
+ top = TTY::ProgressBar::Multi::DEFAULT_INSET[:top]
15
+ bottom = TTY::ProgressBar::Multi::DEFAULT_INSET[:bottom]
16
+
17
+ progress_updates =
18
+ output.read.scan(/#{Regexp.escape top}|#{Regexp.escape bottom}/)
19
+ expect(progress_updates.shift).to match(top)
20
+ expect(progress_updates.shift).to match(top)
21
+ expect(progress_updates.shift).to match(bottom)
22
+ expect(progress_updates.shift).to match(bottom)
23
+ expect(progress_updates.shift).to match(bottom)
24
+ expect(progress_updates.shift).to match(bottom)
25
+
26
+ expect(progress_updates).to be_empty
27
+ end
28
+ end
@@ -0,0 +1,118 @@
1
+ RSpec.describe TTY::ProgressBar::Multi, 'width' do
2
+ let(:output) { StringIO.new('', 'w+') }
3
+ let(:save) { TTY::Cursor.save }
4
+ let(:restore) { TTY::Cursor.restore }
5
+ let(:top) { TTY::ProgressBar::Multi::DEFAULT_INSET[:top] }
6
+ let(:middle) { TTY::ProgressBar::Multi::DEFAULT_INSET[:middle] }
7
+ let(:bottom) { TTY::ProgressBar::Multi::DEFAULT_INSET[:bottom] }
8
+
9
+ it "sets top level bar width to maximum columns when exceeds terminal width" do
10
+ allow(TTY::Screen).to receive(:width).and_return(15)
11
+
12
+ bars = TTY::ProgressBar::Multi.new("[:bar] main", output: output)
13
+
14
+ bar1 = bars.register("[:bar] one", total: 20)
15
+ bar2 = bars.register("[:bar] two", total: 20)
16
+
17
+ bar1.advance(10)
18
+ bar2.advance(10)
19
+
20
+ output.rewind
21
+ expect(output.read).to eq([
22
+ "\e[1G#{top}[== ] main\n",
23
+ "\e[1G#{bottom}[=== ] one\n",
24
+ save,
25
+ "\e[2A", # up 2 lines
26
+ "\e[1G#{top}[=== ] main",
27
+ restore,
28
+ "\e[1G#{bottom}[=== ] two\n"
29
+ ].join)
30
+
31
+ bar1.advance(10)
32
+
33
+ output.rewind
34
+ expect(output.read).to eq([
35
+ "\e[1G#{top}[== ] main\n",
36
+ "\e[1G#{bottom}[=== ] one\n",
37
+ save,
38
+ "\e[2A", # up 2 lines
39
+ "\e[1G#{top}[=== ] main",
40
+ restore,
41
+ "\e[1G#{bottom}[=== ] two\n",
42
+ save,
43
+ "\e[3A", # up 3 lines
44
+ "\e[1G#{top}[===== ] main",
45
+ restore,
46
+ save,
47
+ "\e[2A", # up 2 lines
48
+ "\e[1G#{middle}[=====] one",
49
+ restore,
50
+ save,
51
+ "\e[2A", # up 2 lines
52
+ "#{middle}\n", # bar finished
53
+ restore
54
+ ].join)
55
+
56
+ bar2.advance(10)
57
+
58
+ output.rewind
59
+ expect(output.read).to eq([
60
+ "\e[1G#{top}[== ] main\n",
61
+ "\e[1G#{bottom}[=== ] one\n",
62
+ save,
63
+ "\e[2A", # up 2 lines
64
+ "\e[1G#{top}[=== ] main",
65
+ restore,
66
+ "\e[1G#{bottom}[=== ] two\n",
67
+ save,
68
+ "\e[3A", # up 3 lines
69
+ "\e[1G#{top}[===== ] main",
70
+ restore,
71
+ save,
72
+ "\e[2A", # up 2 lines
73
+ "\e[1G#{middle}[=====] one",
74
+ restore,
75
+ save,
76
+ "\e[2A", # up 2 lines
77
+ "#{middle}\n", # bar finished
78
+ restore,
79
+ save,
80
+ "\e[3A", # up 3 lines
81
+ "\e[1G#{top}[======] main",
82
+ restore,
83
+ save,
84
+ "\e[3A", # up 1 line
85
+ "#{top}\n",
86
+ restore,
87
+ save,
88
+ "\e[1A", # up 1 line
89
+ "\e[1G#{bottom}[=====] two",
90
+ restore,
91
+ save,
92
+ "\e[1A", # up 1 line
93
+ "#{bottom}\n",
94
+ restore
95
+ ].join)
96
+ end
97
+
98
+ it "sets top level bar width to a custom value" do
99
+ bars = TTY::ProgressBar::Multi.new("[:bar] main", output: output, width: 20)
100
+
101
+ bar1 = bars.register("[:bar] one", total: 20)
102
+ bar2 = bars.register("[:bar] two", total: 20)
103
+
104
+ bar1.advance(10)
105
+ bar2.advance(10)
106
+
107
+ output.rewind
108
+ expect(output.read).to eq([
109
+ "\e[1G#{top}[===== ] main\n",
110
+ "\e[1G#{bottom}[========== ] one\n",
111
+ save,
112
+ "\e[2A", # up 2 lines
113
+ "\e[1G#{top}[========== ] main",
114
+ restore,
115
+ "\e[1G#{bottom}[========== ] two\n"
116
+ ].join)
117
+ end
118
+ end
@@ -7,6 +7,16 @@ RSpec.describe TTY::ProgressBar, '::new' do
7
7
  }.to raise_error(ArgumentError, /Expected bar formatting string, got `{:output=>#{output}}` instead\./)
8
8
  end
9
9
 
10
+ it "allows to change formatting string" do
11
+ bar = TTY::ProgressBar.new("[:bar]", output: output, total: 4)
12
+ bar.advance(2)
13
+ bar.format = "(:bar)"
14
+ bar.advance(2)
15
+ output.rewind
16
+
17
+ expect(output.read).to eq("\e[1G[== ]\e[1G(====)\n")
18
+ end
19
+
10
20
  it "displays output where width == total" do
11
21
  progress = TTY::ProgressBar.new("[:bar]", output: output, total: 10)
12
22
  progress.advance
@@ -0,0 +1,25 @@
1
+ RSpec.describe TTY::ProgressBar, "#render" do
2
+ let(:output) { StringIO.new("", "w+") }
3
+
4
+ it "pads out longer previous lines" do
5
+ progress = TTY::ProgressBar.new ":current_byte" do |config|
6
+ config.no_width = true
7
+ config.output = output
8
+ config.total = 1_048_577
9
+ end
10
+
11
+ progress.advance(1)
12
+ progress.advance(1_048_574)
13
+ progress.advance(1)
14
+ progress.advance(1)
15
+
16
+ output.rewind
17
+
18
+ expect(output.read).to eq([
19
+ "\e[1G1B",
20
+ "\e[1G1024.00KB", # must not pad, line is longer
21
+ "\e[1G1.00MB ", # must pad out "0KB"
22
+ "\e[1G1.00MB", # must not pad, line is equal
23
+ ].join)
24
+ end
25
+ end
@@ -11,7 +11,7 @@ RSpec.describe TTY::ProgressBar, '#resize' do
11
11
  "\e[1G[== ]",
12
12
  "\e[1G[==== ]",
13
13
  "\e[0m\e[2K\e[1G",
14
- "\e[1G[=== ]",
14
+ "\e[1G[=== ] ",
15
15
  "\e[1G[==== ]",
16
16
  "\e[1G[=====]\n"
17
17
  ].join)
@@ -8,8 +8,10 @@ RSpec.describe TTY::ProgressBar, '#width' do
8
8
  config.width = 1024
9
9
  end
10
10
  allow(TTY::Screen).to receive(:width).and_return(20)
11
+
11
12
  5.times { progress.advance }
12
13
  output.rewind
14
+
13
15
  expect(output.read).to eq([
14
16
  "\e[1G[==== ]",
15
17
  "\e[1G[======= ]",
@@ -18,4 +20,67 @@ RSpec.describe TTY::ProgressBar, '#width' do
18
20
  "\e[1G[==================]\n"
19
21
  ].join)
20
22
  end
23
+
24
+ it "handles unicode characters width in formatting string" do
25
+ bar = TTY::ProgressBar.new("あめかんむり[:bar]", output: output, total: 20)
26
+ allow(TTY::Screen).to receive(:width).and_return(20)
27
+
28
+ 4.times { bar.advance(5) }
29
+ output.rewind
30
+
31
+ expect(output.read).to eq([
32
+ "\e[1Gあめかんむり[== ]",
33
+ "\e[1Gあめかんむり[=== ]",
34
+ "\e[1Gあめかんむり[===== ]",
35
+ "\e[1Gあめかんむり[======]\n"
36
+ ].join)
37
+ end
38
+
39
+ it "handles unicodes characters within bar" do
40
+ bar = TTY::ProgressBar.new("[:bar]", output: output, total: 20,
41
+ complete: 'あ', incomplete: 'め')
42
+ allow(TTY::Screen).to receive(:width).and_return(20)
43
+
44
+ 4.times { bar.advance(5) }
45
+ output.rewind
46
+
47
+ expect(output.read).to eq([
48
+ "\e[1G[あああめめめめめめ]",
49
+ "\e[1G[あああああめめめめ]",
50
+ "\e[1G[あああああああめめ]",
51
+ "\e[1G[あああああああああ]\n"
52
+ ].join)
53
+ end
54
+
55
+ it "handles unicodes characters within bar" do
56
+ bar = TTY::ProgressBar.new("[:bar]", output: output, total: 20,
57
+ complete: 'あ', incomplete: ' ')
58
+ allow(TTY::Screen).to receive(:width).and_return(20)
59
+
60
+ 4.times { bar.advance(5) }
61
+ output.rewind
62
+
63
+ expect(output.read).to eq([
64
+ "\e[1G[あああ ]",
65
+ "\e[1G[あああああ ]",
66
+ "\e[1G[あああああああ ]",
67
+ "\e[1G[あああああああああ]\n"
68
+ ].join)
69
+ end
70
+
71
+ it "handles unicodes characters within bar" do
72
+ bar = TTY::ProgressBar.new("[:bar]", output: output, total: 20,
73
+ complete: 'x', incomplete: 'め')
74
+ allow(TTY::Screen).to receive(:width).and_return(20)
75
+
76
+ 4.times { bar.advance(5) }
77
+ output.rewind
78
+
79
+ expect(output.read).to eq([
80
+ "\e[1G[xxxxxめめめめめめ]",
81
+ "\e[1G[xxxxxxxxxめめめめ]",
82
+ "\e[1G[xxxxxxxxxxxxxxめめ]",
83
+ "\e[1G[xxxxxxxxxxxxxxxxxx]\n"
84
+ ].join)
85
+ end
21
86
  end
@@ -20,8 +20,9 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.required_ruby_version = '>= 2.0.0'
22
22
 
23
- spec.add_dependency "tty-cursor", '~> 0.5.0'
24
- spec.add_dependency "tty-screen", '~> 0.6.4'
23
+ spec.add_dependency 'tty-cursor', '~> 0.5.0'
24
+ spec.add_dependency 'tty-screen', '~> 0.6.4'
25
+ spec.add_dependency 'unicode-display_width', '~> 1.3'
25
26
 
26
27
  spec.add_development_dependency 'bundler', '>= 1.5.0', '< 2.0'
27
28
  spec.add_development_dependency 'rspec', '~> 3.1'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tty-progressbar
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Murach
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-17 00:00:00.000000000 Z
11
+ date: 2018-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tty-cursor
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 0.6.4
41
+ - !ruby/object:Gem::Dependency
42
+ name: unicode-display_width
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -124,11 +138,13 @@ files:
124
138
  - examples/lazy.rb
125
139
  - examples/multi/main_bar.rb
126
140
  - examples/multi/simple.rb
141
+ - examples/multi/width.rb
127
142
  - examples/simple.rb
128
143
  - examples/slow_process.rb
129
144
  - examples/speed.rb
130
145
  - examples/threaded.rb
131
146
  - examples/tokens.rb
147
+ - examples/unicode.rb
132
148
  - lib/tty-progressbar.rb
133
149
  - lib/tty/progressbar.rb
134
150
  - lib/tty/progressbar/configuration.rb
@@ -185,10 +201,13 @@ files:
185
201
  - spec/unit/multi/finish_spec.rb
186
202
  - spec/unit/multi/line_inset_spec.rb
187
203
  - spec/unit/multi/register_spec.rb
204
+ - spec/unit/multi/reset_spec.rb
188
205
  - spec/unit/multi/stop_spec.rb
206
+ - spec/unit/multi/width_spec.rb
189
207
  - spec/unit/new_spec.rb
190
208
  - spec/unit/pipeline_spec.rb
191
209
  - spec/unit/ratio_spec.rb
210
+ - spec/unit/render_spec.rb
192
211
  - spec/unit/reset_spec.rb
193
212
  - spec/unit/resize_spec.rb
194
213
  - spec/unit/set_current_spec.rb
@@ -260,10 +279,13 @@ test_files:
260
279
  - spec/unit/multi/finish_spec.rb
261
280
  - spec/unit/multi/line_inset_spec.rb
262
281
  - spec/unit/multi/register_spec.rb
282
+ - spec/unit/multi/reset_spec.rb
263
283
  - spec/unit/multi/stop_spec.rb
284
+ - spec/unit/multi/width_spec.rb
264
285
  - spec/unit/new_spec.rb
265
286
  - spec/unit/pipeline_spec.rb
266
287
  - spec/unit/ratio_spec.rb
288
+ - spec/unit/render_spec.rb
267
289
  - spec/unit/reset_spec.rb
268
290
  - spec/unit/resize_spec.rb
269
291
  - spec/unit/set_current_spec.rb