natty-ui 0.28.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/examples.rb +4 -5
- data/examples/options.rb +28 -0
- data/lib/natty-ui/attributes.rb +0 -3
- data/lib/natty-ui/choice.rb +21 -14
- data/lib/natty-ui/dumb_choice.rb +2 -1
- data/lib/natty-ui/dumb_options.rb +63 -0
- data/lib/natty-ui/element.rb +3 -4
- data/lib/natty-ui/features.rb +109 -29
- data/lib/natty-ui/ls_renderer.rb +0 -1
- data/lib/natty-ui/options.rb +77 -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 +0 -7
- data/lib/natty-ui/version.rb +1 -1
- data/lib/natty-ui.rb +1 -3
- metadata +9 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d1b81e5e7afebe8166a6532c00df911d53b189f6eb4b282e828492b0d4a123f
|
4
|
+
data.tar.gz: ef24f92d9c696f966e6dbe3fdcb7eba55c649099551b50dcb83922f1702a1d2a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 610d16c334a76042430e2cf9ff0ae876347ecb24417134adbda55dae569871b7e1e91408bab79770ba3da8ed9379dcf3834bc54aa6673d5081c376cc3c58778d
|
7
|
+
data.tar.gz: 024bc0a945ca27ec2379b7170343e40e23d555c65780b766c30751bc8c4e093766e79081bb6a5aae93cc3be8c9f8c474ca03b84fe1b5e4fa6307858d816a13bd
|
data/examples/examples.rb
CHANGED
@@ -16,11 +16,10 @@ EXAMPLES = {
|
|
16
16
|
'vbars' => 'Print Vertical Bars',
|
17
17
|
'hbars' => 'Print Horizontal Bars',
|
18
18
|
'sections' => 'Sections',
|
19
|
-
'tasks' => 'Tasks'
|
19
|
+
'tasks' => 'Tasks',
|
20
|
+
'options' => 'Options and Selections'
|
20
21
|
}.freeze
|
21
22
|
|
22
|
-
DEFAULT_MODE = NattyUI.input_mode == :default
|
23
|
-
|
24
23
|
ui.space
|
25
24
|
|
26
25
|
while true
|
@@ -34,12 +33,12 @@ while true
|
|
34
33
|
ui.div('[faint](Abort with [\\ESC])', padding: [1, 0, 1])
|
35
34
|
end
|
36
35
|
|
37
|
-
ui.space unless
|
36
|
+
ui.space unless Terminal.ansi?
|
38
37
|
break unless selected
|
39
38
|
|
40
39
|
ui.temporary do
|
41
40
|
load("#{__dir__}/#{selected}.rb")
|
42
|
-
if
|
41
|
+
if Terminal.ansi?
|
43
42
|
ui.await { ui.puts '[faint][\\Press ENTER to continue...]' }
|
44
43
|
else
|
45
44
|
ui.space
|
data/examples/options.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../lib/natty-ui'
|
4
|
+
|
5
|
+
ui.message '[b]ᓚᕠᗢ NattyUI[/b] [i green]Options and Selections[/]' do
|
6
|
+
ui.space
|
7
|
+
ui.puts <<~INFO, eol: false
|
8
|
+
[i]Options[/i] and [i]selections[/i] allow the user to select from several
|
9
|
+
options interactively.
|
10
|
+
If ANSI is available the user can use [b][Up][/b] and [b][Down][/b] keys to
|
11
|
+
navigate, switch the state of selected item with [b][Space][/b] and complete
|
12
|
+
the selection with [b][Enter][/b].
|
13
|
+
INFO
|
14
|
+
|
15
|
+
ui.space
|
16
|
+
options =
|
17
|
+
ui.select %w[Kitty iTerm2 Ghostty Tabby Rio] do
|
18
|
+
ui.puts '[i]Which terminal applications did you already tested?[/i]'
|
19
|
+
end
|
20
|
+
case options.size
|
21
|
+
when 0
|
22
|
+
ui.puts 'You selected nothing – test more in future!'
|
23
|
+
when 1
|
24
|
+
ui.puts "#{options.first} is indeed a nice terminal."
|
25
|
+
else
|
26
|
+
ui.puts "#{options.join(', ')} are worth to test!"
|
27
|
+
end
|
28
|
+
end
|
data/lib/natty-ui/attributes.rb
CHANGED
@@ -29,7 +29,6 @@ module NattyUI
|
|
29
29
|
def _init = nil
|
30
30
|
def _assign(_opt) = self
|
31
31
|
def _store(opt) = opt
|
32
|
-
|
33
32
|
def as_uint(value) = [0, value.to_i].max
|
34
33
|
def as_nint(value) = ([0, value.to_i].max if value)
|
35
34
|
|
@@ -555,9 +554,7 @@ module NattyUI
|
|
555
554
|
|
556
555
|
module TextWithAttributes
|
557
556
|
include WithAttributes
|
558
|
-
|
559
557
|
attr_reader :text
|
560
|
-
|
561
558
|
def empty? = @text.empty?
|
562
559
|
alias _to_s to_s
|
563
560
|
private :_to_s
|
data/lib/natty-ui/choice.rb
CHANGED
@@ -7,24 +7,31 @@ module NattyUI
|
|
7
7
|
def select
|
8
8
|
yield(self) if block_given?
|
9
9
|
pin_line = NattyUI.lines_written
|
10
|
-
draw
|
10
|
+
draw
|
11
|
+
last = @current
|
11
12
|
while (event = Terminal.read_key_event)
|
12
13
|
case event.name
|
13
14
|
when 'Esc', 'Ctrl+c'
|
14
15
|
break nil if @abortable
|
15
|
-
when 'Enter', '
|
16
|
-
break @ret[current]
|
16
|
+
when 'Enter', 'Space'
|
17
|
+
break @ret[@current]
|
17
18
|
when 'Home'
|
18
|
-
current = 0
|
19
|
+
@current = 0
|
19
20
|
when 'End'
|
20
|
-
current = @texts.size - 1
|
21
|
-
when 'Up', 'Back', 'Shift+Tab', 'i'
|
22
|
-
current = @texts.size - 1 if (current -= 1) < 0
|
23
|
-
when 'Down', 'Tab', 'k'
|
24
|
-
current = 0 if (current += 1) == @texts.size
|
21
|
+
@current = @texts.size - 1
|
22
|
+
when 'Up', 'Back', 'Shift+Tab', 'i', 'w'
|
23
|
+
@current = @texts.size - 1 if (@current -= 1) < 0
|
24
|
+
when 'Down', 'Tab', 'k', 's'
|
25
|
+
@current = 0 if (@current += 1) == @texts.size
|
26
|
+
else
|
27
|
+
next unless event.simple?
|
28
|
+
c = event.key.ord
|
29
|
+
@current = (c - 48).clamp(0, @texts.size - 1) if c.between?(48, 57)
|
25
30
|
end
|
31
|
+
next if last == @current
|
26
32
|
pin_line = NattyUI.back_to_line(pin_line, erase: false)
|
27
|
-
draw
|
33
|
+
draw
|
34
|
+
last = @current
|
28
35
|
end
|
29
36
|
ensure
|
30
37
|
NattyUI.back_to_line(@start_line)
|
@@ -38,17 +45,17 @@ module NattyUI
|
|
38
45
|
@texts = args + kwargs.values
|
39
46
|
@ret = Array.new(args.size, &:itself) + kwargs.keys
|
40
47
|
@abortable = abortable
|
41
|
-
@
|
48
|
+
@current = @ret.index(selected) || 0
|
42
49
|
theme = Theme.current
|
43
50
|
@mark = [theme.mark(:choice), theme.choice_style]
|
44
51
|
@mark_current = [theme.mark(:current_choice), theme.choice_current_style]
|
45
52
|
end
|
46
53
|
|
47
|
-
def draw
|
54
|
+
def draw
|
48
55
|
@texts.each_with_index do |str, idx|
|
49
|
-
mark,
|
56
|
+
mark, style = idx == @current ? @mark_current : @mark
|
50
57
|
@parent.puts(
|
51
|
-
"#{
|
58
|
+
"#{style}#{str}",
|
52
59
|
first_line_prefix: mark,
|
53
60
|
first_line_prefix_width: mark.width
|
54
61
|
)
|
data/lib/natty-ui/dumb_choice.rb
CHANGED
@@ -11,7 +11,8 @@ module NattyUI
|
|
11
11
|
return if @abortable && %w[Esc Ctrl+c].include?(event.name)
|
12
12
|
next unless event.simple?
|
13
13
|
code = event.raw.upcase
|
14
|
-
if @ret.size <= 9
|
14
|
+
if @ret.size <= 9
|
15
|
+
next unless ('1'..'9').include?(code)
|
15
16
|
code = @ret[code.ord - 49] and break code
|
16
17
|
elsif ('A'..'Z').include?(code)
|
17
18
|
code = @ret[code.ord - 65] and break code
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'element'
|
4
|
+
|
5
|
+
module NattyUI
|
6
|
+
class DumbOptions < Element
|
7
|
+
def select
|
8
|
+
yield(self) if block_given?
|
9
|
+
draw
|
10
|
+
while (event = Terminal.read_key_event)
|
11
|
+
return if @abortable && %w[Esc Ctrl+c].include?(event.name)
|
12
|
+
return @opts.transform_values(&:last) if event.name == 'Enter'
|
13
|
+
next unless event.simple?
|
14
|
+
code = event.raw.upcase
|
15
|
+
if @opts.size <= 9
|
16
|
+
next unless ('1'..'9').include?(code)
|
17
|
+
offset = 49
|
18
|
+
elsif ('A'..'Z').include?(code)
|
19
|
+
offset = 65
|
20
|
+
else
|
21
|
+
next
|
22
|
+
end
|
23
|
+
key = @opts.keys[code.ord - offset] or next
|
24
|
+
@opts[key][-1] = !@opts[key][-1]
|
25
|
+
@parent.space
|
26
|
+
draw
|
27
|
+
end
|
28
|
+
ensure
|
29
|
+
@parent.space
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def initialize(parent, opts, abortable, selected)
|
35
|
+
super(parent)
|
36
|
+
@opts =
|
37
|
+
opts.to_h do |k, v|
|
38
|
+
v.is_a?(Enumerable) ? [k, [v[0], !!v[-1]]] : [k, [k, !!v]]
|
39
|
+
end
|
40
|
+
@abortable = abortable
|
41
|
+
@current = @opts.key?(selected) ? selected : @opts.first.first
|
42
|
+
theme = Theme.current
|
43
|
+
@marks = {
|
44
|
+
true => theme.mark(:checkmark),
|
45
|
+
false => theme.mark(:choice)
|
46
|
+
}.compare_by_identity
|
47
|
+
end
|
48
|
+
|
49
|
+
def draw
|
50
|
+
glyph = @opts.size <= 9 ? 1 : 'A'
|
51
|
+
@opts.each_pair do |_, (str, selected)|
|
52
|
+
mark = @marks[selected]
|
53
|
+
@parent.puts(
|
54
|
+
str,
|
55
|
+
first_line_prefix: "[\\#{glyph}] #{mark}",
|
56
|
+
first_line_prefix_width: mark.width + 2
|
57
|
+
)
|
58
|
+
glyph = glyph.succ
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
private_constant :DumbOptions
|
63
|
+
end
|
data/lib/natty-ui/element.rb
CHANGED
@@ -32,12 +32,12 @@ module NattyUI
|
|
32
32
|
self
|
33
33
|
end
|
34
34
|
|
35
|
-
alias _to_s to_s
|
36
|
-
private :_to_s
|
37
|
-
|
38
35
|
# @!visibility private
|
39
36
|
alias to_s inspect
|
40
37
|
|
38
|
+
alias _to_s to_s
|
39
|
+
private :_to_s
|
40
|
+
|
41
41
|
private
|
42
42
|
|
43
43
|
def initialize(parent)
|
@@ -48,7 +48,6 @@ module NattyUI
|
|
48
48
|
|
49
49
|
module WithStatus
|
50
50
|
attr_reader :status
|
51
|
-
|
52
51
|
def active? = @status.nil?
|
53
52
|
def closed? = !active?
|
54
53
|
def ok? = @state == :ok
|
data/lib/natty-ui/features.rb
CHANGED
@@ -38,8 +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
|
42
|
-
|
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
|
43
51
|
|
44
52
|
prefix_width =
|
45
53
|
if (prefix = options[:prefix])
|
@@ -90,7 +98,7 @@ module NattyUI
|
|
90
98
|
|
91
99
|
if (align = options[:align]).nil?
|
92
100
|
lines.each do |line|
|
93
|
-
Terminal.print(prefix, line, suffix,
|
101
|
+
Terminal.print(prefix, line, suffix, __eol, bbcode: false)
|
94
102
|
@lines_written += 1
|
95
103
|
prefix, prefix_next = prefix_next, nil if prefix_next
|
96
104
|
end
|
@@ -110,7 +118,7 @@ module NattyUI
|
|
110
118
|
' ' * (max_width - width),
|
111
119
|
line,
|
112
120
|
suffix,
|
113
|
-
|
121
|
+
__eol,
|
114
122
|
bbcode: false
|
115
123
|
)
|
116
124
|
@lines_written += 1
|
@@ -125,7 +133,7 @@ module NattyUI
|
|
125
133
|
line,
|
126
134
|
' ' * (space - lw),
|
127
135
|
suffix,
|
128
|
-
|
136
|
+
__eol,
|
129
137
|
bbcode: false
|
130
138
|
)
|
131
139
|
@lines_written += 1
|
@@ -138,7 +146,7 @@ module NattyUI
|
|
138
146
|
line,
|
139
147
|
' ' * (max_width - width),
|
140
148
|
suffix,
|
141
|
-
|
149
|
+
__eol,
|
142
150
|
bbcode: false
|
143
151
|
)
|
144
152
|
@lines_written += 1
|
@@ -148,6 +156,20 @@ module NattyUI
|
|
148
156
|
self
|
149
157
|
end
|
150
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
|
+
|
151
173
|
# Print given text as lines like {#puts}. Used in elements with temporary
|
152
174
|
# output like {#task} the text will be kept ("pinned").
|
153
175
|
#
|
@@ -169,21 +191,7 @@ module NattyUI
|
|
169
191
|
#
|
170
192
|
# @return (see puts)
|
171
193
|
def pin(*text, mark: nil, **options)
|
172
|
-
|
173
|
-
options[:first_line_prefix] = Theme.current.mark(mark) if mark
|
174
|
-
puts(*text, **options)
|
175
|
-
end
|
176
|
-
|
177
|
-
# Print given text with a decoration mark.
|
178
|
-
#
|
179
|
-
# @param text (see puts)
|
180
|
-
# @param mark [Symbol, #to_s]
|
181
|
-
# marker type
|
182
|
-
#
|
183
|
-
# @return (see puts)
|
184
|
-
def mark(*text, mark: :default)
|
185
|
-
mark = Theme.current.mark(mark)
|
186
|
-
puts(*text, first_line_prefix: mark, first_line_prefix_width: mark.width)
|
194
|
+
mark(*text, mark: mark, pin: true, **options)
|
187
195
|
end
|
188
196
|
|
189
197
|
# Print given text as a quotation.
|
@@ -198,7 +206,7 @@ module NattyUI
|
|
198
206
|
*text,
|
199
207
|
prefix: quote,
|
200
208
|
prefix_width: quote.width,
|
201
|
-
max_width: width < 20 ? nil : width.
|
209
|
+
max_width: width < 20 ? nil : width.round
|
202
210
|
)
|
203
211
|
end
|
204
212
|
|
@@ -735,7 +743,8 @@ module NattyUI
|
|
735
743
|
end
|
736
744
|
end
|
737
745
|
|
738
|
-
#
|
746
|
+
# Allows the user to select an option from a selection.
|
747
|
+
# The selected option is returned.
|
739
748
|
#
|
740
749
|
# @overload choice(*choices, abortable: false)
|
741
750
|
# @param [#to_s] choices
|
@@ -773,6 +782,8 @@ module NattyUI
|
|
773
782
|
# one or more alternatives to select from
|
774
783
|
# @param [true, false] abortable
|
775
784
|
# whether the user is allowed to abort with 'Esc' or 'Ctrl+c'
|
785
|
+
# @param [#to_s, nil] selected
|
786
|
+
# optionally pre-selected option
|
776
787
|
#
|
777
788
|
# @return [Object]
|
778
789
|
# key for selected choice
|
@@ -795,6 +806,8 @@ module NattyUI
|
|
795
806
|
# one or more alternatives to select from
|
796
807
|
# @param [true, false] abortable
|
797
808
|
# whether the user is allowed to abort with 'Esc' or 'Ctrl+c'
|
809
|
+
# @param [Integer] selected
|
810
|
+
# pre-selected option index
|
798
811
|
#
|
799
812
|
# @yieldparam temp [Temporary]
|
800
813
|
# temporary displayed section (section will be erased after input)
|
@@ -807,17 +820,79 @@ module NattyUI
|
|
807
820
|
def choice(*choices, abortable: false, selected: nil, **kwchoices, &block)
|
808
821
|
return if choices.empty? && kwchoices.empty?
|
809
822
|
choice =
|
810
|
-
|
811
|
-
when :default
|
823
|
+
if Terminal.ansi?
|
812
824
|
Choice.new(self, choices, kwchoices, abortable, selected)
|
813
|
-
when :dumb
|
814
|
-
DumbChoice.new(self, choices, kwchoices, abortable)
|
815
825
|
else
|
816
|
-
|
826
|
+
DumbChoice.new(self, choices, kwchoices, abortable)
|
817
827
|
end
|
818
828
|
__with(choice) { choice.select(&block) }
|
819
829
|
end
|
820
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
|
+
|
821
896
|
#
|
822
897
|
# @!endgroup
|
823
898
|
#
|
@@ -871,17 +946,20 @@ module NattyUI
|
|
871
946
|
end
|
872
947
|
end
|
873
948
|
|
874
|
-
|
875
|
-
|
949
|
+
def __eol
|
950
|
+
@__eol ||= Terminal.ansi? ? "\e[m\n" : "\n"
|
951
|
+
end
|
876
952
|
end
|
877
953
|
|
878
954
|
dir = __dir__
|
879
955
|
autoload :Choice, "#{dir}/choice.rb"
|
880
956
|
autoload :DumbChoice, "#{dir}/dumb_choice.rb"
|
957
|
+
autoload :DumbOptions, "#{dir}/dumb_options.rb"
|
881
958
|
autoload :CompactLSRenderer, "#{dir}/ls_renderer.rb"
|
882
959
|
autoload :Framed, "#{dir}/framed.rb"
|
883
960
|
autoload :HBarsRenderer, "#{dir}/hbars_renderer.rb"
|
884
961
|
autoload :LSRenderer, "#{dir}/ls_renderer.rb"
|
962
|
+
autoload :Options, "#{dir}/options.rb"
|
885
963
|
autoload :Progress, "#{dir}/progress.rb"
|
886
964
|
autoload :DumbProgress, "#{dir}/progress.rb"
|
887
965
|
autoload :Section, "#{dir}/section.rb"
|
@@ -895,10 +973,12 @@ module NattyUI
|
|
895
973
|
private_constant(
|
896
974
|
:Choice,
|
897
975
|
:DumbChoice,
|
976
|
+
:DumbOptions,
|
898
977
|
:CompactLSRenderer,
|
899
978
|
:Framed,
|
900
979
|
:HBarsRenderer,
|
901
980
|
:LSRenderer,
|
981
|
+
:Options,
|
902
982
|
:Progress,
|
903
983
|
:DumbProgress,
|
904
984
|
:Utils,
|
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
|
data/lib/natty-ui/theme.rb
CHANGED
@@ -55,7 +55,7 @@ module NattyUI
|
|
55
55
|
failed: '[bright_red]𝑭[/fg]',
|
56
56
|
current: '[bright_green]➔[/fg]',
|
57
57
|
choice: '[bright_white]◦[/fg]',
|
58
|
-
current_choice: '[bright_green]
|
58
|
+
current_choice: '[bright_green]➔[/fg]'
|
59
59
|
)
|
60
60
|
theme.define_section(
|
61
61
|
default: :bright_blue,
|
@@ -166,11 +166,13 @@ module NattyUI
|
|
166
166
|
end
|
167
167
|
|
168
168
|
class Compiled
|
169
|
-
attr_reader :task_style,
|
169
|
+
attr_reader :task_style,
|
170
|
+
:choice_current_style,
|
171
|
+
:choice_style,
|
172
|
+
:option_states
|
170
173
|
|
171
174
|
def defined_marks = @mark.keys.sort!
|
172
175
|
def defined_borders = @border.keys.sort!
|
173
|
-
|
174
176
|
def heading(index) = @heading[index.to_i.clamp(1, 6) - 1]
|
175
177
|
|
176
178
|
def mark(value)
|
@@ -208,12 +210,25 @@ module NattyUI
|
|
208
210
|
SectionBorder.create(border(theme.section_border)),
|
209
211
|
theme.section_styles.dup.compare_by_identity
|
210
212
|
)
|
213
|
+
@option_states = create_option_states
|
211
214
|
end
|
212
215
|
|
213
216
|
private
|
214
217
|
|
215
218
|
def as_style(value) = (Ansi[*value].freeze if value)
|
216
219
|
|
220
|
+
def create_option_states
|
221
|
+
# [current?][selected?]
|
222
|
+
c = @mark[:current_choice]
|
223
|
+
n = @mark[:none]
|
224
|
+
sel = @mark[:checkmark]
|
225
|
+
uns = @mark[:choice]
|
226
|
+
{
|
227
|
+
false => { false => n + uns, true => n + sel }.compare_by_identity,
|
228
|
+
true => { false => c + uns, true => c + sel }.compare_by_identity
|
229
|
+
}.compare_by_identity.freeze
|
230
|
+
end
|
231
|
+
|
217
232
|
def create_sections(template, styles)
|
218
233
|
Hash
|
219
234
|
.new do |h, kind|
|
@@ -224,7 +239,9 @@ module NattyUI
|
|
224
239
|
|
225
240
|
def create_mark(mark)
|
226
241
|
return {} if mark.empty?
|
227
|
-
|
242
|
+
mark = mark.to_h { |n, e| [n.to_sym, Str.new("#{e} ")] }
|
243
|
+
mark[:none] ||= Str.new(' ', 2)
|
244
|
+
with_default(mark)
|
228
245
|
end
|
229
246
|
|
230
247
|
def create_border(border)
|
@@ -294,6 +311,7 @@ module NattyUI
|
|
294
311
|
|
295
312
|
private_constant :SectionBorder
|
296
313
|
end
|
314
|
+
# private_constant :Compiled
|
297
315
|
|
298
316
|
private
|
299
317
|
|
data/lib/natty-ui/utils.rb
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
module NattyUI
|
4
4
|
module Utils
|
5
5
|
class << self
|
6
|
-
# @!visibility private
|
7
6
|
def style(value)
|
8
7
|
value =
|
9
8
|
case value
|
@@ -22,27 +21,22 @@ module NattyUI
|
|
22
21
|
value.keep_if { Ansi.valid?(_1) }.empty? ? nil : value
|
23
22
|
end
|
24
23
|
|
25
|
-
# @!visibility private
|
26
24
|
def align(value)
|
27
25
|
POS_ALI.include?(value) ? value : :left
|
28
26
|
end
|
29
27
|
|
30
|
-
# @!visibility private
|
31
28
|
def position(value)
|
32
29
|
value if POS_ALI.include?(value)
|
33
30
|
end
|
34
31
|
|
35
|
-
# @!visibility private
|
36
32
|
def vertical(value)
|
37
33
|
VERT.include?(value) ? value : :top
|
38
34
|
end
|
39
35
|
|
40
|
-
# @!visibility private
|
41
36
|
def split_table_attr(values)
|
42
37
|
[values.slice(*TAB_ATTR), values.except(*TAB_ATTR)]
|
43
38
|
end
|
44
39
|
|
45
|
-
# @!visibility private
|
46
40
|
def padding(*value)
|
47
41
|
value = value.flatten.take(4).map! { [0, _1.to_i].max }
|
48
42
|
case value.size
|
@@ -60,7 +54,6 @@ module NattyUI
|
|
60
54
|
end
|
61
55
|
alias margin padding
|
62
56
|
|
63
|
-
# @!visibility private
|
64
57
|
def as_size(range, value)
|
65
58
|
return range.begin if value == :min
|
66
59
|
return range.end if value.nil? || value.is_a?(Symbol)
|
data/lib/natty-ui/version.rb
CHANGED
data/lib/natty-ui.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: natty-ui
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.29.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Blumtritt
|
@@ -15,14 +15,14 @@ dependencies:
|
|
15
15
|
requirements:
|
16
16
|
- - ">="
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version:
|
18
|
+
version: 0.12.1
|
19
19
|
type: :runtime
|
20
20
|
prerelease: false
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
22
22
|
requirements:
|
23
23
|
- - ">="
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version:
|
25
|
+
version: 0.12.1
|
26
26
|
description: |
|
27
27
|
This is the beautiful, nice, nifty, fancy, neat, pretty, cool, rich, lovely,
|
28
28
|
natty user interface tool you like to have for your command line applications.
|
@@ -50,6 +50,7 @@ files:
|
|
50
50
|
- examples/key-codes.rb
|
51
51
|
- examples/ls.rb
|
52
52
|
- examples/named-colors.rb
|
53
|
+
- examples/options.rb
|
53
54
|
- examples/sections.rb
|
54
55
|
- examples/tables.rb
|
55
56
|
- examples/tasks.rb
|
@@ -58,11 +59,13 @@ files:
|
|
58
59
|
- lib/natty-ui/attributes.rb
|
59
60
|
- lib/natty-ui/choice.rb
|
60
61
|
- lib/natty-ui/dumb_choice.rb
|
62
|
+
- lib/natty-ui/dumb_options.rb
|
61
63
|
- lib/natty-ui/element.rb
|
62
64
|
- lib/natty-ui/features.rb
|
63
65
|
- lib/natty-ui/framed.rb
|
64
66
|
- lib/natty-ui/hbars_renderer.rb
|
65
67
|
- lib/natty-ui/ls_renderer.rb
|
68
|
+
- lib/natty-ui/options.rb
|
66
69
|
- lib/natty-ui/progress.rb
|
67
70
|
- lib/natty-ui/section.rb
|
68
71
|
- lib/natty-ui/table.rb
|
@@ -79,11 +82,11 @@ homepage: https://github.com/mblumtritt/natty-ui
|
|
79
82
|
licenses:
|
80
83
|
- BSD-3-Clause
|
81
84
|
metadata:
|
82
|
-
rubygems_mfa_required: 'true'
|
83
|
-
yard.run: yard
|
84
85
|
source_code_uri: https://github.com/mblumtritt/natty-ui
|
85
86
|
bug_tracker_uri: https://github.com/mblumtritt/natty-ui/issues
|
86
|
-
documentation_uri: https://rubydoc.info/gems/natty-ui
|
87
|
+
documentation_uri: https://rubydoc.info/gems/natty-ui
|
88
|
+
rubygems_mfa_required: 'true'
|
89
|
+
yard.run: yard
|
87
90
|
rdoc_options: []
|
88
91
|
require_paths:
|
89
92
|
- lib
|