natty-ui 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,12 +15,12 @@ module NattyUI
15
15
  # Print given text as lines.
16
16
  #
17
17
  # @example Print two lines text, right aligned
18
- # ui.puts("Two lines", "of nice text", align: :right)
18
+ # ui.puts "Two lines", "of nice text", align: :right
19
19
  # # => Two lines
20
20
  # # => of nice text
21
21
  #
22
22
  # @example Print two lines text, with a prefix
23
- # ui.puts("Two lines", "of nice text", prefix: ': ')
23
+ # ui.puts "Two lines", "of nice text", prefix: ': '
24
24
  # # => : Two lines
25
25
  # # => : of nice text
26
26
  #
@@ -31,14 +31,15 @@ module NattyUI
31
31
  # @param options [{Symbol => Object}]
32
32
  # @option options [:left, :right, :centered] :align (:left)
33
33
  # text alignment
34
- # @option options [true, false] :ignore_newline (false)
35
- # whether to igniore newline characters
34
+ # @option options [true, false] :eol (true)
35
+ # whether to respect newline characters
36
36
  #
37
37
  # @return [Features]
38
38
  # itself
39
39
  def puts(*text, **options)
40
40
  bbcode = true if (bbcode = options[:bbcode]).nil?
41
41
  max_width = options[:max_width] || Terminal.columns
42
+ max_width = Terminal.columns + max_width if max_width < 0
42
43
 
43
44
  prefix_width =
44
45
  if (prefix = options[:prefix])
@@ -84,7 +85,7 @@ module NattyUI
84
85
  limit: max_width,
85
86
  bbcode: bbcode,
86
87
  ansi: Terminal.ansi?,
87
- ignore_newline: options[:ignore_newline]
88
+ ignore_newline: options[:eol] == false || options[:ignore_newline]
88
89
  )
89
90
 
90
91
  if (align = options[:align]).nil?
@@ -272,8 +273,8 @@ module NattyUI
272
273
 
273
274
  # Print a horizontal rule.
274
275
  #
275
- # @example
276
- # ui.hr(:heavy)
276
+ # @example Print double line
277
+ # ui.hr :double
277
278
  #
278
279
  # @param type [Symbol]
279
280
  # border type
@@ -305,10 +306,10 @@ module NattyUI
305
306
  # - any text as prefix
306
307
  #
307
308
  # @example Print all Ruby files as a numbered list
308
- # ui.ls(Dir['*/**/*.rb'], glyph: 1)
309
+ # ui.ls Dir['*/**/*.rb'], glyph: 1
309
310
  #
310
311
  # @example Print all Ruby files as a bullet point list (with green bullets)
311
- # ui.ls(Dir['*/**/*.rb'], glyph: '[green]•[/fg]')
312
+ # ui.ls Dir['*/**/*.rb'], glyph: '[green]•[/fg]'
312
313
  #
313
314
  # @param items [#to_s]
314
315
  # one or more convertible objects to list
@@ -338,13 +339,16 @@ module NattyUI
338
339
  # attributes for the table and default attributes for table cells
339
340
  # @option attributes [Symbol] :border (nil)
340
341
  # kind of border,
341
- # see {Attributes::Border}
342
- # @option attributes [true, false] :border_around (false)
343
- # whether the table should have a border around,
344
- # see {Attributes::BorderAround}
342
+ # see {Table::Attributes}
345
343
  # @option attributes [Enumerable<Symbol>] :border_style (nil)
346
344
  # style of border,
347
- # see {Attributes::BorderStyle}
345
+ # see {Table::Attributes}
346
+ # @option attributes [true, false] :border_around (false)
347
+ # whether the table should have a border around,
348
+ # see {Table::Attributes}
349
+ # @option attributes [:left, :right, :centered] :position (false)
350
+ # where to align the table,
351
+ # see {Table::Attributes}
348
352
  #
349
353
  # @yieldparam table [Table]
350
354
  # helper to define the table layout
@@ -353,7 +357,11 @@ module NattyUI
353
357
  def table(**attributes)
354
358
  return self unless block_given?
355
359
  yield(table = Table.new(**attributes))
356
- puts(*TableRenderer[table, columns])
360
+ puts(
361
+ *TableRenderer[table, columns],
362
+ align: table.attributes.position,
363
+ expand: true
364
+ )
357
365
  end
358
366
 
359
367
  # Print text in columns.
@@ -372,9 +380,10 @@ module NattyUI
372
380
  #
373
381
  # @return (see puts)
374
382
  def cols(*columns, **attributes)
375
- table(**attributes) do |table|
383
+ tab_att, att = Utils.split_table_attr(attributes)
384
+ table(**tab_att) do |table|
376
385
  table.add do |row|
377
- columns.each { row.add(_1, **attributes) }
386
+ columns.each { row.add(_1, **att) }
378
387
  yield(row) if block_given?
379
388
  end
380
389
  end
@@ -403,8 +412,88 @@ module NattyUI
403
412
  # @return (see puts)
404
413
  def div(*text, **attributes)
405
414
  return self if text.empty?
406
- table(border_around: true, **attributes) do |table|
407
- table.add { _1.add(*text, **attributes) }
415
+ tab_att, att = Utils.split_table_attr(attributes)
416
+ tab_att[:border_around] = true
417
+ table(**tab_att) { |table| table.add { _1.add(*text, **att) } }
418
+ end
419
+
420
+ # Dump given values as vertical bars.
421
+ #
422
+ # @example Draw green bars
423
+ # ui.vbars 1..10, style: :green
424
+ #
425
+ # @example Draw very big bars
426
+ # ui.vbars 1..10, bar_width: 5, height: 20
427
+ #
428
+ # @param values [#to_a, Array<Numeric>] values to print
429
+ # @param normalize [true, false] whether the values should be normalized
430
+ # @param height [Integer] output height
431
+ # @param bar_width [:auto, :min, Integer] with of each bar
432
+ # @param style [Symbol, Array<Symbol>, nil] drawing style
433
+ #
434
+ # @raise [ArgumentError] if any value is negative
435
+ #
436
+ # @return (see puts)
437
+ def vbars(
438
+ values,
439
+ normalize: false,
440
+ height: 10,
441
+ bar_width: :auto,
442
+ style: nil
443
+ )
444
+ return self if (values = values.to_a).empty?
445
+ if values.any?(&:negative?)
446
+ raise(ArgumentError, 'values can not be negative')
447
+ end
448
+ puts(
449
+ *VBarsRenderer.lines(
450
+ values,
451
+ columns,
452
+ height,
453
+ normalize,
454
+ bar_width,
455
+ Terminal.ansi? ? style : nil
456
+ )
457
+ )
458
+ end
459
+
460
+ # Dump given values as horizontal bars.
461
+ #
462
+ # @example Draw green bars
463
+ # ui.hbars 1..10, style: :green
464
+ #
465
+ # @example Draw bars in half sreen width
466
+ # ui.hbars 1..10, style: :blue, width: 0.5
467
+ #
468
+ # @param values [#to_a, Array<Numeric>] values to print
469
+ # @param with_values [true, false] whether the values should be printed too
470
+ # @param normalize [true, false] whether the values should be normalized
471
+ # @param height [Integer] output height
472
+ # @param bar_width [:auto, :min, Integer] with of each bar
473
+ # @param style [Symbol, Array<Symbol>, nil] bar drawing style
474
+ # @param text_style [Symbol, Array<Symbol>, nil] text style
475
+ #
476
+ # @raise [ArgumentError] if any value is negative
477
+ #
478
+ # @return (see puts)
479
+ def hbars(
480
+ values,
481
+ with_values: true,
482
+ normalize: false,
483
+ width: :auto,
484
+ style: nil,
485
+ text_style: nil
486
+ )
487
+ return self if (values = values.to_a).empty?
488
+ if values.any?(&:negative?)
489
+ raise(ArgumentError, 'values can not be negative')
490
+ end
491
+ style = text_style = nil unless Terminal.ansi?
492
+ size = Utils.as_size(3..columns, width)
493
+ if with_values
494
+ puts(*HBarsRenderer.lines(values, size, normalize, style, text_style))
495
+ else
496
+ puts(*HBarsRenderer.lines_bars_only(values, size, normalize, style))
408
497
  end
409
498
  end
410
499
 
@@ -426,15 +515,15 @@ module NattyUI
426
515
  # end
427
516
  #
428
517
  # @example Display simple progress
429
- # progress = ui.progress('Check some stuff')
518
+ # progress = ui.progress 'Check some stuff'
430
519
  # 10.times do
431
520
  # # simulate some work
432
- # sleep(0.1)
521
+ # sleep 0.1
433
522
  #
434
523
  # # here we actualize the progress
435
524
  # progress.step
436
525
  # end
437
- # progress.ok('Stuff checked ok')
526
+ # progress.ok 'Stuff checked ok'
438
527
  #
439
528
  # @overload progress(title, max: nil, pin: false)
440
529
  # @param title [#to_s]
@@ -483,10 +572,10 @@ module NattyUI
483
572
  #
484
573
  # @example
485
574
  # ui.section do |section|
486
- # section.h1('About Sections')
575
+ # section.h1 'About Sections'
487
576
  # section.space
488
- # section.puts('Sections are areas of text elements.')
489
- # section.puts('You can use any other feature inside such an area.')
577
+ # section.puts 'Sections are areas of text elements.'
578
+ # section.puts 'You can use any other feature inside such an area.'
490
579
  # end
491
580
  # # => ╭────╶╶╶
492
581
  # # => │ ╴╶╴╶─═══ About Sections ═══─╴╶╴╶
@@ -635,18 +724,14 @@ module NattyUI
635
724
  #
636
725
  # @return [true, false]
637
726
  # wheter the user inputs a positive result
727
+ # @return nil
728
+ # in error case
638
729
  #
639
730
  def await(yes: 'Enter', no: 'Esc')
640
- temporary do |arg|
641
- yield(arg) if block_given?
642
- while (key = Terminal.read_key)
643
- if (no == key) || (no.is_a?(Enumerable) && no.include?(key))
644
- return false
645
- end
646
- if (yes == key) || (yes.is_a?(Enumerable) && yes.include?(key))
647
- return true
648
- end
649
- end
731
+ return __await(yes, no) unless block_given?
732
+ temporary do |temp|
733
+ yield(temp)
734
+ __await(yes, no)
650
735
  end
651
736
  end
652
737
 
@@ -719,12 +804,12 @@ module NattyUI
719
804
  # @return [nil]
720
805
  # when user aborted the selection
721
806
  #
722
- def choice(*choices, abortable: false, **kwchoices, &block)
807
+ def choice(*choices, abortable: false, selected: nil, **kwchoices, &block)
723
808
  return if choices.empty? && kwchoices.empty?
724
809
  choice =
725
810
  case NattyUI.input_mode
726
811
  when :default
727
- Choice.new(self, choices, kwchoices, abortable)
812
+ Choice.new(self, choices, kwchoices, abortable, selected)
728
813
  when :dumb
729
814
  DumbChoice.new(self, choices, kwchoices, abortable)
730
815
  else
@@ -749,7 +834,7 @@ module NattyUI
749
834
  #
750
835
  # @example Show tempoary information
751
836
  # ui.temporary do
752
- # ui.info('Information', 'This text will disappear when you pressed ENTER.')
837
+ # ui.info 'Information', 'This text will disappear when you pressed ENTER.'
753
838
  # ui.await
754
839
  # end
755
840
  #
@@ -775,15 +860,27 @@ module NattyUI
775
860
  __sec(color, "#{Theme.current.mark(color)}#{title}", text, &block)
776
861
  end
777
862
 
863
+ def __await(yes, no)
864
+ while (event = Terminal.read_key_event&.name)
865
+ if (no == event) || (no.is_a?(Enumerable) && no.include?(event))
866
+ return false
867
+ end
868
+ if (yes == event) || (yes.is_a?(Enumerable) && yes.include?(event))
869
+ return true
870
+ end
871
+ end
872
+ end
873
+
778
874
  EOL__ = Terminal.ansi? ? "\e[m\n" : "\n"
779
875
  private_constant :EOL__
780
876
  end
781
877
 
782
878
  dir = __dir__
783
879
  autoload :Choice, "#{dir}/choice.rb"
784
- autoload :CompactLSRenderer, "#{dir}/ls_renderer.rb"
785
880
  autoload :DumbChoice, "#{dir}/dumb_choice.rb"
881
+ autoload :CompactLSRenderer, "#{dir}/ls_renderer.rb"
786
882
  autoload :Framed, "#{dir}/framed.rb"
883
+ autoload :HBarsRenderer, "#{dir}/hbars_renderer.rb"
787
884
  autoload :LSRenderer, "#{dir}/ls_renderer.rb"
788
885
  autoload :Progress, "#{dir}/progress.rb"
789
886
  autoload :DumbProgress, "#{dir}/progress.rb"
@@ -793,6 +890,18 @@ module NattyUI
793
890
  autoload :Temporary, "#{dir}/temporary.rb"
794
891
  autoload :Theme, "#{dir}/theme.rb"
795
892
  autoload :Utils, "#{dir}/utils.rb"
796
-
797
- private_constant :Choice, :DumbChoice, :LSRenderer, :CompactLSRenderer
893
+ autoload :VBarsRenderer, "#{dir}/vbars_renderer.rb"
894
+
895
+ private_constant(
896
+ :Choice,
897
+ :DumbChoice,
898
+ :CompactLSRenderer,
899
+ :Framed,
900
+ :HBarsRenderer,
901
+ :LSRenderer,
902
+ :Progress,
903
+ :DumbProgress,
904
+ :Utils,
905
+ :VBarsRenderer
906
+ )
798
907
  end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'utils'
4
+
5
+ module NattyUI
6
+ module HBarsRenderer
7
+ class << self
8
+ def lines(vals, width, normalize, style, text_style)
9
+ if text_style
10
+ bots = Ansi[*text_style]
11
+ eots = Ansi::RESET
12
+ end
13
+ texts = vals.map { Str.new(_1) }
14
+ tw = texts.max_by(&:width).width
15
+ size = width - tw - 1
16
+ if size < 2 # text only
17
+ return texts.map { "#{bots}#{' ' * (tw - _1.width)}#{_1}#{eots}" }
18
+ end
19
+ if style
20
+ bos = Ansi[*style]
21
+ eos = Ansi::RESET
22
+ end
23
+ vals = normalize ? normalize!(vals, size) : adjust!(vals, size)
24
+ texts.map.with_index do |str, idx|
25
+ "#{bots}#{' ' * (tw - str.width)}#{str}#{eots}#{bos}▕#{
26
+ '▆' * vals[idx]
27
+ }#{eos}"
28
+ end
29
+ end
30
+
31
+ def lines_bars_only(vals, width, normalize, style)
32
+ if style
33
+ bos = Ansi[*style]
34
+ eos = Ansi::RESET
35
+ end
36
+ width -= 1
37
+ vals = normalize ? normalize!(vals, width) : adjust!(vals, width)
38
+ vals.map { "#{bos}▕#{'▆' * _1}#{eos}" }
39
+ end
40
+
41
+ private
42
+
43
+ def adjust!(vals, size)
44
+ max = vals.max.to_f
45
+ vals.map { ((_1 / max) * size).round }
46
+ end
47
+
48
+ def normalize!(vals, size)
49
+ min, max = vals.minmax
50
+ return Array.new(vals.size, size) if min == max
51
+ max = (max - min).to_f
52
+ vals.map { (((_1 - min) / max) * size).round }
53
+ end
54
+ end
55
+ end
56
+
57
+ private_constant :HBarsRenderer
58
+ end
@@ -99,6 +99,9 @@ module NattyUI
99
99
  @pin = pin
100
100
  @pin_line = NattyUI.lines_written
101
101
  @style = Theme.current.task_style
102
+ cm = Theme.current.mark(:current)
103
+ @flp = "#{cm} #{@style}"
104
+ @flpw = cm.width + 1
102
105
  max ? self.max = max : redraw
103
106
  end
104
107
 
@@ -110,8 +113,8 @@ module NattyUI
110
113
  @pin_line = NattyUI.back_to_line(@pin_line) if @last
111
114
  @parent.puts(
112
115
  *curr,
113
- first_line_prefix: "#{@style}➔ ",
114
- first_line_prefix_width: 2
116
+ first_line_prefix: @flp,
117
+ first_line_prefix_width: @flpw
115
118
  )
116
119
  @last = curr
117
120
  end
@@ -48,7 +48,7 @@ module NattyUI
48
48
  @border = Theme.current.section_border(kind)
49
49
  show_title(title)
50
50
  @prefix = @border.prefix
51
- @prefix_width = @prefix.size
51
+ @prefix_width = @prefix.width
52
52
  puts(*rest) if rest && !rest.empty?
53
53
  puts(*msg) unless msg.empty?
54
54
  end
@@ -33,7 +33,7 @@ module NattyUI
33
33
  m = cell.attributes.max_width
34
34
  max = m if m && (max.nil? || max < m)
35
35
  end
36
- wh_from(min.to_i, max.to_i)
36
+ wh_from(min, max)
37
37
  end
38
38
 
39
39
  def respond_to_missing?(name, _)
@@ -181,7 +181,46 @@ module NattyUI
181
181
  class Attributes < NattyUI::Attributes::Base
182
182
  prepend NattyUI::Attributes::Border
183
183
  prepend NattyUI::Attributes::BorderStyle
184
- prepend NattyUI::Attributes::BorderAround
184
+ prepend NattyUI::Attributes::Position
185
+
186
+ # Whether the table has a border around.
187
+ #
188
+ # @return [true, false]
189
+ attr_reader :border_around
190
+
191
+ # @attribute [w] border_around
192
+ def border_around=(value)
193
+ @border_around = value ? true : false
194
+ end
195
+
196
+ # Maximum table width.
197
+ #
198
+ # @return [Integer, nil]
199
+ attr_reader :max_width
200
+
201
+ # @attribute [w] max_width
202
+ def max_width=(value)
203
+ if value.is_a?(Float)
204
+ return @max_width = nil if value < 0
205
+ return @max_width = value if value < 1
206
+ end
207
+ value = value.to_i
208
+ @max_width = value <= 0 ? nil : value
209
+ end
210
+
211
+ protected
212
+
213
+ def _assign(opt)
214
+ @border_around = opt[:border_around]
215
+ self.max_width = opt[:max_width]
216
+ super
217
+ end
218
+
219
+ def _store(opt)
220
+ opt[:border_around] = true if @border_around
221
+ opt[:max_width] = @max_width if @max_width
222
+ super
223
+ end
185
224
  end
186
225
 
187
226
  include Enumerable
@@ -207,10 +246,20 @@ module NattyUI
207
246
 
208
247
  # @return [Row] created row
209
248
  def add(*text, **attributes)
210
- nr = Row.new
211
- @rows << nr
212
- text.each { nr.add(_1, **attributes) }
213
- block_given? ? yield(nr) : nr
249
+ unless text[0].is_a?(Hash)
250
+ @rows << (nr = Row.new)
251
+ text.each { nr.add(_1, **attributes) }
252
+ return block_given? ? yield(nr) : nr
253
+ end
254
+ new_rows = []
255
+ text[0].each_pair do |key, value|
256
+ new_rows << (nr = Row.new)
257
+ @rows << nr
258
+ nr.add(key, **attributes)
259
+ nr.add(value, **attributes)
260
+ yield(nr) if block_given?
261
+ end
262
+ new_rows
214
263
  end
215
264
 
216
265
  def delete(row)
@@ -8,22 +8,28 @@ module NattyUI
8
8
  def self.[](table, max_width)
9
9
  columns = table.columns.map(&:width)
10
10
  return [] if columns.empty?
11
- attributes = table.attributes
12
- unless attributes.border_chars.nil?
11
+ att = table.attributes
12
+ case att.max_width
13
+ when Float
14
+ max_width *= att.max_width
15
+ when Integer
16
+ max_width = [max_width, att.max_width].min
17
+ end
18
+ unless att.border_chars.nil?
13
19
  max_width -= (columns.size - 1)
14
- max_width -= 2 if attributes.border_around
20
+ max_width -= 2 if att.border_around
15
21
  end
16
22
  return [] if max_width < columns.size
17
- new(columns, table.each.to_a, attributes, max_width).lines
23
+ new(columns, table.each.to_a, att, max_width).lines
18
24
  end
19
25
 
20
26
  attr_reader :lines
21
27
 
22
28
  private
23
29
 
24
- def initialize(columns, rows, attributes, max_width)
30
+ def initialize(columns, rows, att, max_width)
25
31
  @max_width, @columns = WidthFinder.find(columns, max_width)
26
- init_borders(attributes)
32
+ init_borders(att)
27
33
  @columns = @columns.each.with_index
28
34
 
29
35
  @lines = render(rows.shift)
@@ -50,12 +56,12 @@ module NattyUI
50
56
  end
51
57
  end
52
58
 
53
- def init_borders(attributes)
54
- chars = attributes.border_chars or return
55
- style = border_style(attributes)
59
+ def init_borders(att)
60
+ chars = att.border_chars or return
61
+ style = border_style(att)
56
62
  @b_inner = style[chars[9]]
57
63
  return if chars[10] == ' '
58
- return init_borders_around(chars, style) if attributes.border_around
64
+ return init_borders_around(chars, style) if att.border_around
59
65
  @b_between = chars[10] * (@max_width + @columns.size - 1)
60
66
  i = -1
61
67
  @columns[0..-2].each { |w| @b_between[i += w + 1] = chars[4] }
@@ -79,8 +85,8 @@ module NattyUI
79
85
  @b_outer = @b_inner
80
86
  end
81
87
 
82
- def border_style(attributes)
83
- style = attributes.border_style_bbcode
88
+ def border_style(att)
89
+ style = att.border_style_bbcode
84
90
  style ? ->(line) { "#{style}#{line}[/]" } : lambda(&:itself)
85
91
  end
86
92
 
@@ -150,6 +156,7 @@ module NattyUI
150
156
  ["#{@style}#{' ' * @padding[3]}", "#{' ' * @padding[1]}[/]"]
151
157
  end
152
158
  end
159
+ private_constant :Cell
153
160
  end
154
161
  private_constant :TableRenderer
155
162
  end
data/lib/natty-ui/task.rb CHANGED
@@ -30,16 +30,17 @@ module NattyUI
30
30
  def initialize(parent, title, msg, pin)
31
31
  super(parent)
32
32
  @title = title
33
- @prefix = '  '
34
- @prefix_width = 2
35
33
  @pin = pin
36
34
  style = Theme.current.task_style
35
+ cm = Theme.current.mark(:current)
36
+ @prefix = ' ' * cm.width
37
+ @prefix_width = cm.width
37
38
  parent.puts(
38
39
  title,
39
- first_line_prefix: "#{style}➔ ",
40
- first_line_prefix_width: 2,
41
- prefix: "#{style}  ",
42
- prefix_width: 2
40
+ first_line_prefix: "#{cm}#{style}",
41
+ first_line_prefix_width: cm.width,
42
+ prefix: "#{@prefix}#{style}",
43
+ prefix_width: cm.width
43
44
  )
44
45
  puts(*msg) unless msg.empty?
45
46
  end
@@ -53,6 +53,7 @@ module NattyUI
53
53
  warning: '[bright_yellow]![/fg]',
54
54
  error: '[red]𝙓[/fg]',
55
55
  failed: '[bright_red]𝑭[/fg]',
56
+ current: '[bright_green]➔[/fg]',
56
57
  choice: '[bright_white]◦[/fg]',
57
58
  current_choice: '[bright_green]◉[/fg]'
58
59
  )
@@ -66,6 +67,35 @@ module NattyUI
66
67
  )
67
68
  end
68
69
  end
70
+
71
+ def emoji
72
+ create do |theme|
73
+ theme.heading_sytle = :bright_blue
74
+ theme.task_style = %i[bright_green b]
75
+ # theme.choice_style =
76
+ theme.choice_current_style = %i[bright_white on_blue b]
77
+ theme.define_marker(
78
+ bullet: '▫️',
79
+ checkmark: '✅',
80
+ quote: '[bright_blue]▍[/fg]',
81
+ information: '📌',
82
+ warning: '⚠️',
83
+ error: '❗️',
84
+ failed: '‼️',
85
+ current: '➡️',
86
+ choice: '[bright_white]•[/fg]',
87
+ current_choice: '[bright_green]●[/fg]'
88
+ )
89
+ theme.define_section(
90
+ default: :bright_blue,
91
+ message: :bright_blue,
92
+ information: :bright_blue,
93
+ warning: :bright_yellow,
94
+ error: :red,
95
+ failed: :bright_red
96
+ )
97
+ end
98
+ end
69
99
  end
70
100
 
71
101
  attr_accessor :section_border
@@ -206,7 +236,7 @@ module NattyUI
206
236
  return create_styled_heading(heading, style) if style
207
237
  heading.map do |left|
208
238
  right = " #{left.reverse}"
209
- [left = Str.new("#{left} ", true), Str.new(right, left.size)]
239
+ [left = Str.new("#{left} ", true), Str.new(right, left.width)]
210
240
  end
211
241
  end
212
242
 
@@ -215,7 +245,7 @@ module NattyUI
215
245
  right = Ansi.decorate(left.reverse, *style)
216
246
  [
217
247
  left = Str.new("#{Ansi.decorate(left, *style)} ", true),
218
- Str.new(" #{right}", left.size)
248
+ Str.new(" #{right}", left.width)
219
249
  ]
220
250
  end
221
251
  end
@@ -278,6 +308,7 @@ module NattyUI
278
308
  warning: '!',
279
309
  error: '𝙓',
280
310
  failed: '𝑭',
311
+ current: '➔',
281
312
  choice: '◦',
282
313
  current_choice: '◉'
283
314
  }