natty-ui 0.27.0 → 0.29.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.
- checksums.yaml +4 -4
- data/examples/8bit-colors.rb +2 -2
- data/examples/elements.rb +6 -6
- data/examples/examples.rb +7 -6
- data/examples/hbars.rb +18 -0
- data/examples/illustration.rb +1 -1
- data/examples/info.rb +20 -19
- data/examples/key-codes.rb +17 -15
- data/examples/options.rb +28 -0
- data/examples/tasks.rb +1 -1
- data/examples/vbars.rb +39 -0
- data/lib/natty-ui/attributes.rb +0 -3
- data/lib/natty-ui/choice.rb +27 -17
- data/lib/natty-ui/dumb_choice.rb +6 -5
- data/lib/natty-ui/dumb_options.rb +63 -0
- data/lib/natty-ui/element.rb +3 -4
- data/lib/natty-ui/features.rb +237 -56
- data/lib/natty-ui/hbars_renderer.rb +58 -0
- data/lib/natty-ui/ls_renderer.rb +0 -1
- data/lib/natty-ui/options.rb +77 -0
- data/lib/natty-ui/table_renderer.rb +1 -0
- data/lib/natty-ui/task.rb +1 -1
- data/lib/natty-ui/temporary.rb +5 -6
- data/lib/natty-ui/theme.rb +22 -4
- data/lib/natty-ui/utils.rb +31 -11
- data/lib/natty-ui/vbars_renderer.rb +48 -0
- data/lib/natty-ui/version.rb +1 -1
- data/lib/natty-ui.rb +1 -3
- metadata +13 -5
data/lib/natty-ui/features.rb
CHANGED
@@ -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
|
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
|
23
|
+
# ui.puts "Two lines", "of nice text", prefix: ': '
|
24
24
|
# # => : Two lines
|
25
25
|
# # => : of nice text
|
26
26
|
#
|
@@ -38,7 +38,16 @@ module NattyUI
|
|
38
38
|
# itself
|
39
39
|
def puts(*text, **options)
|
40
40
|
bbcode = true if (bbcode = options[:bbcode]).nil?
|
41
|
+
|
41
42
|
max_width = options[:max_width] || Terminal.columns
|
43
|
+
return self if max_width == 0
|
44
|
+
if max_width < 1
|
45
|
+
if max_width > 0
|
46
|
+
max_width *= Terminal.columns
|
47
|
+
elsif max_width < 0
|
48
|
+
max_width += Terminal.columns
|
49
|
+
end
|
50
|
+
end
|
42
51
|
|
43
52
|
prefix_width =
|
44
53
|
if (prefix = options[:prefix])
|
@@ -89,7 +98,7 @@ module NattyUI
|
|
89
98
|
|
90
99
|
if (align = options[:align]).nil?
|
91
100
|
lines.each do |line|
|
92
|
-
Terminal.print(prefix, line, suffix,
|
101
|
+
Terminal.print(prefix, line, suffix, __eol, bbcode: false)
|
93
102
|
@lines_written += 1
|
94
103
|
prefix, prefix_next = prefix_next, nil if prefix_next
|
95
104
|
end
|
@@ -109,7 +118,7 @@ module NattyUI
|
|
109
118
|
' ' * (max_width - width),
|
110
119
|
line,
|
111
120
|
suffix,
|
112
|
-
|
121
|
+
__eol,
|
113
122
|
bbcode: false
|
114
123
|
)
|
115
124
|
@lines_written += 1
|
@@ -124,7 +133,7 @@ module NattyUI
|
|
124
133
|
line,
|
125
134
|
' ' * (space - lw),
|
126
135
|
suffix,
|
127
|
-
|
136
|
+
__eol,
|
128
137
|
bbcode: false
|
129
138
|
)
|
130
139
|
@lines_written += 1
|
@@ -137,7 +146,7 @@ module NattyUI
|
|
137
146
|
line,
|
138
147
|
' ' * (max_width - width),
|
139
148
|
suffix,
|
140
|
-
|
149
|
+
__eol,
|
141
150
|
bbcode: false
|
142
151
|
)
|
143
152
|
@lines_written += 1
|
@@ -147,6 +156,20 @@ module NattyUI
|
|
147
156
|
self
|
148
157
|
end
|
149
158
|
|
159
|
+
# Print given text with a decoration mark.
|
160
|
+
#
|
161
|
+
# @param text (see puts)
|
162
|
+
# @param mark [Symbol, #to_s]
|
163
|
+
# marker type
|
164
|
+
#
|
165
|
+
# @return (see puts)
|
166
|
+
def mark(*text, mark: :default, **options)
|
167
|
+
mark = Theme.current.mark(mark)
|
168
|
+
options[:first_line_prefix] = mark
|
169
|
+
options[:first_line_prefix_width] = mark.width
|
170
|
+
puts(*text, **options)
|
171
|
+
end
|
172
|
+
|
150
173
|
# Print given text as lines like {#puts}. Used in elements with temporary
|
151
174
|
# output like {#task} the text will be kept ("pinned").
|
152
175
|
#
|
@@ -168,21 +191,7 @@ module NattyUI
|
|
168
191
|
#
|
169
192
|
# @return (see puts)
|
170
193
|
def pin(*text, mark: nil, **options)
|
171
|
-
|
172
|
-
options[:first_line_prefix] = Theme.current.mark(mark) if mark
|
173
|
-
puts(*text, **options)
|
174
|
-
end
|
175
|
-
|
176
|
-
# Print given text with a decoration mark.
|
177
|
-
#
|
178
|
-
# @param text (see puts)
|
179
|
-
# @param mark [Symbol, #to_s]
|
180
|
-
# marker type
|
181
|
-
#
|
182
|
-
# @return (see puts)
|
183
|
-
def mark(*text, mark: :default)
|
184
|
-
mark = Theme.current.mark(mark)
|
185
|
-
puts(*text, first_line_prefix: mark, first_line_prefix_width: mark.width)
|
194
|
+
mark(*text, mark: mark, pin: true, **options)
|
186
195
|
end
|
187
196
|
|
188
197
|
# Print given text as a quotation.
|
@@ -197,7 +206,7 @@ module NattyUI
|
|
197
206
|
*text,
|
198
207
|
prefix: quote,
|
199
208
|
prefix_width: quote.width,
|
200
|
-
max_width: width < 20 ? nil : width.
|
209
|
+
max_width: width < 20 ? nil : width.round
|
201
210
|
)
|
202
211
|
end
|
203
212
|
|
@@ -272,8 +281,8 @@ module NattyUI
|
|
272
281
|
|
273
282
|
# Print a horizontal rule.
|
274
283
|
#
|
275
|
-
# @example
|
276
|
-
# ui.hr
|
284
|
+
# @example Print double line
|
285
|
+
# ui.hr :double
|
277
286
|
#
|
278
287
|
# @param type [Symbol]
|
279
288
|
# border type
|
@@ -305,10 +314,10 @@ module NattyUI
|
|
305
314
|
# - any text as prefix
|
306
315
|
#
|
307
316
|
# @example Print all Ruby files as a numbered list
|
308
|
-
# ui.ls
|
317
|
+
# ui.ls Dir['*/**/*.rb'], glyph: 1
|
309
318
|
#
|
310
319
|
# @example Print all Ruby files as a bullet point list (with green bullets)
|
311
|
-
# ui.ls
|
320
|
+
# ui.ls Dir['*/**/*.rb'], glyph: '[green]•[/fg]'
|
312
321
|
#
|
313
322
|
# @param items [#to_s]
|
314
323
|
# one or more convertible objects to list
|
@@ -416,6 +425,86 @@ module NattyUI
|
|
416
425
|
table(**tab_att) { |table| table.add { _1.add(*text, **att) } }
|
417
426
|
end
|
418
427
|
|
428
|
+
# Dump given values as vertical bars.
|
429
|
+
#
|
430
|
+
# @example Draw green bars
|
431
|
+
# ui.vbars 1..10, style: :green
|
432
|
+
#
|
433
|
+
# @example Draw very big bars
|
434
|
+
# ui.vbars 1..10, bar_width: 5, height: 20
|
435
|
+
#
|
436
|
+
# @param values [#to_a, Array<Numeric>] values to print
|
437
|
+
# @param normalize [true, false] whether the values should be normalized
|
438
|
+
# @param height [Integer] output height
|
439
|
+
# @param bar_width [:auto, :min, Integer] with of each bar
|
440
|
+
# @param style [Symbol, Array<Symbol>, nil] drawing style
|
441
|
+
#
|
442
|
+
# @raise [ArgumentError] if any value is negative
|
443
|
+
#
|
444
|
+
# @return (see puts)
|
445
|
+
def vbars(
|
446
|
+
values,
|
447
|
+
normalize: false,
|
448
|
+
height: 10,
|
449
|
+
bar_width: :auto,
|
450
|
+
style: nil
|
451
|
+
)
|
452
|
+
return self if (values = values.to_a).empty?
|
453
|
+
if values.any?(&:negative?)
|
454
|
+
raise(ArgumentError, 'values can not be negative')
|
455
|
+
end
|
456
|
+
puts(
|
457
|
+
*VBarsRenderer.lines(
|
458
|
+
values,
|
459
|
+
columns,
|
460
|
+
height,
|
461
|
+
normalize,
|
462
|
+
bar_width,
|
463
|
+
Terminal.ansi? ? style : nil
|
464
|
+
)
|
465
|
+
)
|
466
|
+
end
|
467
|
+
|
468
|
+
# Dump given values as horizontal bars.
|
469
|
+
#
|
470
|
+
# @example Draw green bars
|
471
|
+
# ui.hbars 1..10, style: :green
|
472
|
+
#
|
473
|
+
# @example Draw bars in half sreen width
|
474
|
+
# ui.hbars 1..10, style: :blue, width: 0.5
|
475
|
+
#
|
476
|
+
# @param values [#to_a, Array<Numeric>] values to print
|
477
|
+
# @param with_values [true, false] whether the values should be printed too
|
478
|
+
# @param normalize [true, false] whether the values should be normalized
|
479
|
+
# @param height [Integer] output height
|
480
|
+
# @param bar_width [:auto, :min, Integer] with of each bar
|
481
|
+
# @param style [Symbol, Array<Symbol>, nil] bar drawing style
|
482
|
+
# @param text_style [Symbol, Array<Symbol>, nil] text style
|
483
|
+
#
|
484
|
+
# @raise [ArgumentError] if any value is negative
|
485
|
+
#
|
486
|
+
# @return (see puts)
|
487
|
+
def hbars(
|
488
|
+
values,
|
489
|
+
with_values: true,
|
490
|
+
normalize: false,
|
491
|
+
width: :auto,
|
492
|
+
style: nil,
|
493
|
+
text_style: nil
|
494
|
+
)
|
495
|
+
return self if (values = values.to_a).empty?
|
496
|
+
if values.any?(&:negative?)
|
497
|
+
raise(ArgumentError, 'values can not be negative')
|
498
|
+
end
|
499
|
+
style = text_style = nil unless Terminal.ansi?
|
500
|
+
size = Utils.as_size(3..columns, width)
|
501
|
+
if with_values
|
502
|
+
puts(*HBarsRenderer.lines(values, size, normalize, style, text_style))
|
503
|
+
else
|
504
|
+
puts(*HBarsRenderer.lines_bars_only(values, size, normalize, style))
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
419
508
|
# Dynamically display a task progress.
|
420
509
|
# When a `max` parameter is given the progress will be displayed as a
|
421
510
|
# progress bar below the `title`. Otherwise the progress is displayed just
|
@@ -434,15 +523,15 @@ module NattyUI
|
|
434
523
|
# end
|
435
524
|
#
|
436
525
|
# @example Display simple progress
|
437
|
-
# progress = ui.progress
|
526
|
+
# progress = ui.progress 'Check some stuff'
|
438
527
|
# 10.times do
|
439
528
|
# # simulate some work
|
440
|
-
# sleep
|
529
|
+
# sleep 0.1
|
441
530
|
#
|
442
531
|
# # here we actualize the progress
|
443
532
|
# progress.step
|
444
533
|
# end
|
445
|
-
# progress.ok
|
534
|
+
# progress.ok 'Stuff checked ok'
|
446
535
|
#
|
447
536
|
# @overload progress(title, max: nil, pin: false)
|
448
537
|
# @param title [#to_s]
|
@@ -491,10 +580,10 @@ module NattyUI
|
|
491
580
|
#
|
492
581
|
# @example
|
493
582
|
# ui.section do |section|
|
494
|
-
# section.h1
|
583
|
+
# section.h1 'About Sections'
|
495
584
|
# section.space
|
496
|
-
# section.puts
|
497
|
-
# section.puts
|
585
|
+
# section.puts 'Sections are areas of text elements.'
|
586
|
+
# section.puts 'You can use any other feature inside such an area.'
|
498
587
|
# end
|
499
588
|
# # => ╭────╶╶╶
|
500
589
|
# # => │ ╴╶╴╶─═══ About Sections ═══─╴╶╴╶
|
@@ -643,22 +732,19 @@ module NattyUI
|
|
643
732
|
#
|
644
733
|
# @return [true, false]
|
645
734
|
# wheter the user inputs a positive result
|
735
|
+
# @return nil
|
736
|
+
# in error case
|
646
737
|
#
|
647
738
|
def await(yes: 'Enter', no: 'Esc')
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
return false
|
653
|
-
end
|
654
|
-
if (yes == key) || (yes.is_a?(Enumerable) && yes.include?(key))
|
655
|
-
return true
|
656
|
-
end
|
657
|
-
end
|
739
|
+
return __await(yes, no) unless block_given?
|
740
|
+
temporary do |temp|
|
741
|
+
yield(temp)
|
742
|
+
__await(yes, no)
|
658
743
|
end
|
659
744
|
end
|
660
745
|
|
661
|
-
#
|
746
|
+
# Allows the user to select an option from a selection.
|
747
|
+
# The selected option is returned.
|
662
748
|
#
|
663
749
|
# @overload choice(*choices, abortable: false)
|
664
750
|
# @param [#to_s] choices
|
@@ -696,6 +782,8 @@ module NattyUI
|
|
696
782
|
# one or more alternatives to select from
|
697
783
|
# @param [true, false] abortable
|
698
784
|
# whether the user is allowed to abort with 'Esc' or 'Ctrl+c'
|
785
|
+
# @param [#to_s, nil] selected
|
786
|
+
# optionally pre-selected option
|
699
787
|
#
|
700
788
|
# @return [Object]
|
701
789
|
# key for selected choice
|
@@ -718,6 +806,8 @@ module NattyUI
|
|
718
806
|
# one or more alternatives to select from
|
719
807
|
# @param [true, false] abortable
|
720
808
|
# whether the user is allowed to abort with 'Esc' or 'Ctrl+c'
|
809
|
+
# @param [Integer] selected
|
810
|
+
# pre-selected option index
|
721
811
|
#
|
722
812
|
# @yieldparam temp [Temporary]
|
723
813
|
# temporary displayed section (section will be erased after input)
|
@@ -727,20 +817,82 @@ module NattyUI
|
|
727
817
|
# @return [nil]
|
728
818
|
# when user aborted the selection
|
729
819
|
#
|
730
|
-
def choice(*choices, abortable: false, **kwchoices, &block)
|
820
|
+
def choice(*choices, abortable: false, selected: nil, **kwchoices, &block)
|
731
821
|
return if choices.empty? && kwchoices.empty?
|
732
822
|
choice =
|
733
|
-
|
734
|
-
|
735
|
-
Choice.new(self, choices, kwchoices, abortable)
|
736
|
-
when :dumb
|
737
|
-
DumbChoice.new(self, choices, kwchoices, abortable)
|
823
|
+
if Terminal.ansi?
|
824
|
+
Choice.new(self, choices, kwchoices, abortable, selected)
|
738
825
|
else
|
739
|
-
|
826
|
+
DumbChoice.new(self, choices, kwchoices, abortable)
|
740
827
|
end
|
741
828
|
__with(choice) { choice.select(&block) }
|
742
829
|
end
|
743
830
|
|
831
|
+
# Allows the user to select from several options.
|
832
|
+
# All options are returned with their selection status.
|
833
|
+
#
|
834
|
+
# @param [{#to_s => [true,false]}] choices
|
835
|
+
# Hash of options and their selection state
|
836
|
+
# @param [true, false] abortable
|
837
|
+
# whether the user is allowed to abort with 'Esc' or 'Ctrl+c'
|
838
|
+
# @param [#to_s, nil] selected
|
839
|
+
# optionally pre-selected key
|
840
|
+
#
|
841
|
+
# @yieldparam temp [Temporary]
|
842
|
+
# temporary displayed section (section will be erased after input)
|
843
|
+
#
|
844
|
+
# @return [{#to_s => [true,false]}]
|
845
|
+
# Hash of options and their selection state
|
846
|
+
# @return [nil]
|
847
|
+
# when user aborted the selection
|
848
|
+
def options(abortable: false, selected: nil, **choices, &block)
|
849
|
+
return {} if choices.empty?
|
850
|
+
options =
|
851
|
+
if Terminal.ansi?
|
852
|
+
Options.new(self, choices, abortable, selected)
|
853
|
+
else
|
854
|
+
DumbOptions.new(self, choices, abortable, selected)
|
855
|
+
end
|
856
|
+
__with(options) { options.select(&block) }
|
857
|
+
end
|
858
|
+
|
859
|
+
# Allows the user to select from several options.
|
860
|
+
# The selected options are returned.
|
861
|
+
#
|
862
|
+
# @example Select a terminal
|
863
|
+
# ui.select %w[Kitty iTerm2 Ghostty Tabby Rio] do
|
864
|
+
# ui.puts '[i]Which terminal applications did you already tested?[/i]'
|
865
|
+
# end
|
866
|
+
#
|
867
|
+
# @param [Array<#to_s>] choices
|
868
|
+
# selectable options
|
869
|
+
# @param [true, false] abortable
|
870
|
+
# whether the user is allowed to abort with 'Esc' or 'Ctrl+c'
|
871
|
+
# @param [Integer, :all, nil] selected
|
872
|
+
# optionally pre-selected option index or `:all` to pre-select all items
|
873
|
+
# @yieldparam temp [Temporary]
|
874
|
+
# temporary displayed section (section will be erased after input)
|
875
|
+
#
|
876
|
+
# @return [Array<#to_s>]
|
877
|
+
# selected options
|
878
|
+
# @return [nil]
|
879
|
+
# when user aborted the selection
|
880
|
+
def select(*choices, abortable: false, selected: nil, &block)
|
881
|
+
return [] if choices.empty?
|
882
|
+
choices = choices[0] if choices.size == 1 && choices[0].is_a?(Enumerable)
|
883
|
+
if selected == :all
|
884
|
+
sel = true
|
885
|
+
elsif selected
|
886
|
+
selected = choices[selected.to_i]
|
887
|
+
end
|
888
|
+
options(
|
889
|
+
abortable: abortable,
|
890
|
+
selected: selected,
|
891
|
+
**choices.to_h { [_1, sel] },
|
892
|
+
&block
|
893
|
+
).filter_map { |key, selected| key if selected }
|
894
|
+
end
|
895
|
+
|
744
896
|
#
|
745
897
|
# @!endgroup
|
746
898
|
#
|
@@ -757,7 +909,7 @@ module NattyUI
|
|
757
909
|
#
|
758
910
|
# @example Show tempoary information
|
759
911
|
# ui.temporary do
|
760
|
-
# ui.info
|
912
|
+
# ui.info 'Information', 'This text will disappear when you pressed ENTER.'
|
761
913
|
# ui.await
|
762
914
|
# end
|
763
915
|
#
|
@@ -783,16 +935,31 @@ module NattyUI
|
|
783
935
|
__sec(color, "#{Theme.current.mark(color)}#{title}", text, &block)
|
784
936
|
end
|
785
937
|
|
786
|
-
|
787
|
-
|
938
|
+
def __await(yes, no)
|
939
|
+
while (event = Terminal.read_key_event&.name)
|
940
|
+
if (no == event) || (no.is_a?(Enumerable) && no.include?(event))
|
941
|
+
return false
|
942
|
+
end
|
943
|
+
if (yes == event) || (yes.is_a?(Enumerable) && yes.include?(event))
|
944
|
+
return true
|
945
|
+
end
|
946
|
+
end
|
947
|
+
end
|
948
|
+
|
949
|
+
def __eol
|
950
|
+
@__eol ||= Terminal.ansi? ? "\e[m\n" : "\n"
|
951
|
+
end
|
788
952
|
end
|
789
953
|
|
790
954
|
dir = __dir__
|
791
955
|
autoload :Choice, "#{dir}/choice.rb"
|
792
|
-
autoload :CompactLSRenderer, "#{dir}/ls_renderer.rb"
|
793
956
|
autoload :DumbChoice, "#{dir}/dumb_choice.rb"
|
957
|
+
autoload :DumbOptions, "#{dir}/dumb_options.rb"
|
958
|
+
autoload :CompactLSRenderer, "#{dir}/ls_renderer.rb"
|
794
959
|
autoload :Framed, "#{dir}/framed.rb"
|
960
|
+
autoload :HBarsRenderer, "#{dir}/hbars_renderer.rb"
|
795
961
|
autoload :LSRenderer, "#{dir}/ls_renderer.rb"
|
962
|
+
autoload :Options, "#{dir}/options.rb"
|
796
963
|
autoload :Progress, "#{dir}/progress.rb"
|
797
964
|
autoload :DumbProgress, "#{dir}/progress.rb"
|
798
965
|
autoload :Section, "#{dir}/section.rb"
|
@@ -801,6 +968,20 @@ module NattyUI
|
|
801
968
|
autoload :Temporary, "#{dir}/temporary.rb"
|
802
969
|
autoload :Theme, "#{dir}/theme.rb"
|
803
970
|
autoload :Utils, "#{dir}/utils.rb"
|
804
|
-
|
805
|
-
|
971
|
+
autoload :VBarsRenderer, "#{dir}/vbars_renderer.rb"
|
972
|
+
|
973
|
+
private_constant(
|
974
|
+
:Choice,
|
975
|
+
:DumbChoice,
|
976
|
+
:DumbOptions,
|
977
|
+
:CompactLSRenderer,
|
978
|
+
:Framed,
|
979
|
+
:HBarsRenderer,
|
980
|
+
:LSRenderer,
|
981
|
+
:Options,
|
982
|
+
:Progress,
|
983
|
+
:DumbProgress,
|
984
|
+
:Utils,
|
985
|
+
:VBarsRenderer
|
986
|
+
)
|
806
987
|
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
|
data/lib/natty-ui/ls_renderer.rb
CHANGED
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'element'
|
4
|
+
|
5
|
+
module NattyUI
|
6
|
+
class Options < Element
|
7
|
+
def select
|
8
|
+
yield(self) if block_given?
|
9
|
+
pin_line = NattyUI.lines_written
|
10
|
+
draw
|
11
|
+
last = @current
|
12
|
+
while (event = Terminal.read_key_event)
|
13
|
+
case event.name
|
14
|
+
when 'Esc', 'Ctrl+c'
|
15
|
+
return if @abortable
|
16
|
+
when 'Enter'
|
17
|
+
return @opts.transform_values(&:last)
|
18
|
+
when 'Space'
|
19
|
+
(last = @opts[@current])[-1] = !last[-1]
|
20
|
+
when 'a'
|
21
|
+
@opts.transform_values { _1[-1] = true }
|
22
|
+
last = nil
|
23
|
+
when 'n'
|
24
|
+
@opts.transform_values { _1[-1] = false }
|
25
|
+
last = nil
|
26
|
+
when 'Home'
|
27
|
+
@current = @opts.first.first
|
28
|
+
when 'End'
|
29
|
+
@current = @opts.keys.last
|
30
|
+
when 'Up', 'Back', 'Shift+Tab', 'i'
|
31
|
+
keys = @opts.keys
|
32
|
+
@current = keys[keys.index(@current) - 1]
|
33
|
+
when 'Down', 'Tab', 'k'
|
34
|
+
keys = @opts.keys
|
35
|
+
@current = keys[keys.index(@current) + 1] || keys[0]
|
36
|
+
end
|
37
|
+
next if last == @current
|
38
|
+
pin_line = NattyUI.back_to_line(pin_line, erase: false)
|
39
|
+
draw
|
40
|
+
last = @current
|
41
|
+
end
|
42
|
+
ensure
|
43
|
+
NattyUI.back_to_line(@start_line)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def initialize(parent, opts, abortable, selected)
|
49
|
+
super(parent)
|
50
|
+
@opts =
|
51
|
+
opts.to_h do |k, v|
|
52
|
+
v.is_a?(Enumerable) ? [k, [v[0], !!v[-1]]] : [k, [k, !!v]]
|
53
|
+
end
|
54
|
+
@abortable = abortable
|
55
|
+
@current = @opts.key?(selected) ? selected : @opts.first.first
|
56
|
+
@start_line = NattyUI.lines_written
|
57
|
+
theme = Theme.current
|
58
|
+
@style = {
|
59
|
+
false => theme.choice_style,
|
60
|
+
true => theme.choice_current_style
|
61
|
+
}.compare_by_identity
|
62
|
+
end
|
63
|
+
|
64
|
+
def draw
|
65
|
+
states = NattyUI::Theme.current.option_states
|
66
|
+
@opts.each_pair do |key, (str, selected)|
|
67
|
+
mark = states.dig(current = key == @current, selected)
|
68
|
+
@parent.puts(
|
69
|
+
"#{@style[current]}#{str}",
|
70
|
+
first_line_prefix: mark,
|
71
|
+
first_line_prefix_width: mark.width
|
72
|
+
)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
private_constant :Options
|
77
|
+
end
|
data/lib/natty-ui/task.rb
CHANGED
data/lib/natty-ui/temporary.rb
CHANGED
@@ -8,11 +8,10 @@ module NattyUI
|
|
8
8
|
#
|
9
9
|
class Temporary < Element
|
10
10
|
# @!visibility private
|
11
|
-
def puts(*objects, **
|
11
|
+
def puts(*objects, **opts)
|
12
12
|
return self if @state
|
13
|
-
if
|
14
|
-
@pins ||= []
|
15
|
-
@pins << [objects, options.except(:prefix_width, :suffix_width)]
|
13
|
+
if opts.delete(:pin)
|
14
|
+
(@pins ||= []) << [objects, opts.except(:prefix_width, :suffix_width)]
|
16
15
|
end
|
17
16
|
super
|
18
17
|
end
|
@@ -20,8 +19,8 @@ module NattyUI
|
|
20
19
|
# @!visibility private
|
21
20
|
def done
|
22
21
|
return self if @state
|
23
|
-
NattyUI.back_to_line(@start_line
|
24
|
-
@pins&.each { |objects,
|
22
|
+
NattyUI.back_to_line(@start_line) if @start_line
|
23
|
+
@pins&.each { |objects, opts| puts(*objects, **opts) }
|
25
24
|
@state = :ok
|
26
25
|
self
|
27
26
|
end
|