tty-prompt 0.21.0 → 0.22.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/CHANGELOG.md +37 -1
- data/README.md +372 -215
- data/lib/tty-prompt.rb +1 -2
- data/lib/tty/prompt.rb +145 -142
- data/lib/tty/prompt/answers_collector.rb +2 -2
- data/lib/tty/prompt/block_paginator.rb +1 -1
- data/lib/tty/prompt/choice.rb +1 -1
- data/lib/tty/prompt/choices.rb +28 -11
- data/lib/tty/prompt/confirm_question.rb +23 -12
- data/lib/tty/prompt/const.rb +17 -0
- data/lib/tty/prompt/converter_dsl.rb +6 -7
- data/lib/tty/prompt/converter_registry.rb +31 -26
- data/lib/tty/prompt/converters.rb +139 -32
- data/lib/tty/prompt/enum_list.rb +27 -19
- data/lib/tty/prompt/errors.rb +31 -0
- data/lib/tty/prompt/evaluator.rb +1 -1
- data/lib/tty/prompt/expander.rb +20 -12
- data/lib/tty/prompt/keypress.rb +3 -3
- data/lib/tty/prompt/list.rb +57 -25
- data/lib/tty/prompt/mask_question.rb +2 -2
- data/lib/tty/prompt/multi_list.rb +71 -27
- data/lib/tty/prompt/multiline.rb +6 -5
- data/lib/tty/prompt/paginator.rb +1 -1
- data/lib/tty/prompt/question.rb +56 -31
- data/lib/tty/prompt/question/checks.rb +18 -0
- data/lib/tty/prompt/selected_choices.rb +76 -0
- data/lib/tty/prompt/slider.rb +67 -8
- data/lib/tty/prompt/statement.rb +3 -3
- data/lib/tty/prompt/suggestion.rb +5 -5
- data/lib/tty/prompt/symbols.rb +58 -58
- data/lib/tty/prompt/test.rb +36 -0
- data/lib/tty/prompt/utils.rb +1 -3
- data/lib/tty/prompt/version.rb +1 -1
- metadata +12 -24
- data/lib/tty/prompt/messages.rb +0 -49
- data/lib/tty/test_prompt.rb +0 -20
data/lib/tty/prompt/enum_list.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "English"
|
4
4
|
|
5
|
-
require_relative
|
6
|
-
require_relative
|
7
|
-
require_relative
|
5
|
+
require_relative "choices"
|
6
|
+
require_relative "block_paginator"
|
7
|
+
require_relative "paginator"
|
8
8
|
|
9
9
|
module TTY
|
10
10
|
class Prompt
|
@@ -13,7 +13,7 @@ module TTY
|
|
13
13
|
#
|
14
14
|
# @api private
|
15
15
|
class EnumList
|
16
|
-
PAGE_HELP =
|
16
|
+
PAGE_HELP = "(Press tab/right or left to reveal more choices)"
|
17
17
|
|
18
18
|
# Create instance of EnumList menu.
|
19
19
|
#
|
@@ -21,12 +21,13 @@ module TTY
|
|
21
21
|
def initialize(prompt, **options)
|
22
22
|
@prompt = prompt
|
23
23
|
@prefix = options.fetch(:prefix) { @prompt.prefix }
|
24
|
-
@enum = options.fetch(:enum) {
|
24
|
+
@enum = options.fetch(:enum) { ")" }
|
25
25
|
@default = options.fetch(:default) { -1 }
|
26
26
|
@active_color = options.fetch(:active_color) { @prompt.active_color }
|
27
27
|
@help_color = options.fetch(:help_color) { @prompt.help_color }
|
28
28
|
@error_color = options.fetch(:error_color) { @prompt.error_color }
|
29
29
|
@cycle = options.fetch(:cycle) { false }
|
30
|
+
@quiet = options.fetch(:quiet) { @prompt.quiet }
|
30
31
|
@symbols = @prompt.symbols.merge(options.fetch(:symbols, {}))
|
31
32
|
@input = nil
|
32
33
|
@done = false
|
@@ -101,6 +102,13 @@ module TTY
|
|
101
102
|
@enum = value
|
102
103
|
end
|
103
104
|
|
105
|
+
# Set quiet mode
|
106
|
+
#
|
107
|
+
# @api public
|
108
|
+
def quiet(value)
|
109
|
+
@quiet = value
|
110
|
+
end
|
111
|
+
|
104
112
|
# Add a single choice
|
105
113
|
#
|
106
114
|
# @api public
|
@@ -162,7 +170,7 @@ module TTY
|
|
162
170
|
if choice_in_range && !choice_disabled || @input.empty?
|
163
171
|
@done = true
|
164
172
|
else
|
165
|
-
@input =
|
173
|
+
@input = ""
|
166
174
|
@failure = true
|
167
175
|
end
|
168
176
|
end
|
@@ -241,7 +249,7 @@ module TTY
|
|
241
249
|
#
|
242
250
|
# @api private
|
243
251
|
def render
|
244
|
-
@input =
|
252
|
+
@input = ""
|
245
253
|
until @done
|
246
254
|
question = render_question
|
247
255
|
@prompt.print(question)
|
@@ -253,7 +261,7 @@ module TTY
|
|
253
261
|
question_lines = question.split($INPUT_RECORD_SEPARATOR, -1)
|
254
262
|
@prompt.print(refresh(question_lines_count(question_lines)))
|
255
263
|
end
|
256
|
-
@prompt.print(render_question)
|
264
|
+
@prompt.print(render_question) unless @quiet
|
257
265
|
answer
|
258
266
|
end
|
259
267
|
|
@@ -308,8 +316,8 @@ module TTY
|
|
308
316
|
#
|
309
317
|
# @api private
|
310
318
|
def error_message
|
311
|
-
error =
|
312
|
-
"\n" + @prompt.decorate(
|
319
|
+
error = "Please enter a valid number"
|
320
|
+
"\n" + @prompt.decorate(">>", @error_color) + " " + error
|
313
321
|
end
|
314
322
|
|
315
323
|
# Render error message and return cursor to position of input
|
@@ -332,8 +340,8 @@ module TTY
|
|
332
340
|
#
|
333
341
|
# @api private
|
334
342
|
def render_header
|
335
|
-
return
|
336
|
-
return
|
343
|
+
return "" unless @done
|
344
|
+
return "" unless @active
|
337
345
|
selected_item = @choices[@active - 1].name.to_s
|
338
346
|
@prompt.decorate(selected_item, @active_color)
|
339
347
|
end
|
@@ -353,7 +361,7 @@ module TTY
|
|
353
361
|
#
|
354
362
|
# @api private
|
355
363
|
def page_help_message
|
356
|
-
return
|
364
|
+
return "" unless paginated?
|
357
365
|
"\n" + @prompt.decorate(@page_help, @help_color)
|
358
366
|
end
|
359
367
|
|
@@ -380,15 +388,15 @@ module TTY
|
|
380
388
|
output = []
|
381
389
|
|
382
390
|
@paginator.paginate(@choices, @page_active, @per_page) do |choice, index|
|
383
|
-
num = (index + 1).to_s + @enum +
|
391
|
+
num = (index + 1).to_s + @enum + " "
|
384
392
|
selected = num.to_s + choice.name.to_s
|
385
393
|
output << if index + 1 == @active && !choice.disabled?
|
386
|
-
(
|
394
|
+
(" " * 2) + @prompt.decorate(selected, @active_color)
|
387
395
|
elsif choice.disabled?
|
388
|
-
@prompt.decorate(@symbols[:cross], :red) +
|
389
|
-
selected +
|
396
|
+
@prompt.decorate(@symbols[:cross], :red) + " " +
|
397
|
+
selected + " " + choice.disabled.to_s
|
390
398
|
else
|
391
|
-
(
|
399
|
+
(" " * 2) + selected
|
392
400
|
end
|
393
401
|
output << "\n"
|
394
402
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
class Prompt
|
5
|
+
Error = Class.new(StandardError)
|
6
|
+
|
7
|
+
# Raised when wrong parameter is used to configure prompt
|
8
|
+
ConfigurationError = Class.new(Error)
|
9
|
+
|
10
|
+
# Raised when type conversion cannot be performed
|
11
|
+
ConversionError = Class.new(Error)
|
12
|
+
|
13
|
+
# Raised when the passed in validation argument is of wrong type
|
14
|
+
ValidationCoercion = Class.new(Error)
|
15
|
+
|
16
|
+
# Raised when the required argument is not supplied
|
17
|
+
ArgumentRequired = Class.new(Error)
|
18
|
+
|
19
|
+
# Raised when the argument validation fails
|
20
|
+
ArgumentValidation = Class.new(Error)
|
21
|
+
|
22
|
+
# Raised when the argument is not expected
|
23
|
+
InvalidArgument = Class.new(Error)
|
24
|
+
|
25
|
+
# Raised when overriding already defined conversion
|
26
|
+
ConversionAlreadyDefined = Class.new(Error)
|
27
|
+
|
28
|
+
# Raised when conversion type isn't registered
|
29
|
+
UnsupportedConversion = Class.new(Error)
|
30
|
+
end # Prompt
|
31
|
+
end # TTY
|
data/lib/tty/prompt/evaluator.rb
CHANGED
data/lib/tty/prompt/expander.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "choices"
|
4
4
|
|
5
5
|
module TTY
|
6
6
|
class Prompt
|
@@ -10,8 +10,8 @@ module TTY
|
|
10
10
|
# @api private
|
11
11
|
class Expander
|
12
12
|
HELP_CHOICE = {
|
13
|
-
key:
|
14
|
-
name:
|
13
|
+
key: "h",
|
14
|
+
name: "print help",
|
15
15
|
value: :help
|
16
16
|
}.freeze
|
17
17
|
|
@@ -25,6 +25,7 @@ module TTY
|
|
25
25
|
@auto_hint = options.fetch(:auto_hint) { false }
|
26
26
|
@active_color = options.fetch(:active_color) { @prompt.active_color }
|
27
27
|
@help_color = options.fetch(:help_color) { @prompt.help_color }
|
28
|
+
@quiet = options.fetch(:quiet) { @prompt.quiet }
|
28
29
|
@choices = Choices.new
|
29
30
|
@selected = nil
|
30
31
|
@done = false
|
@@ -56,16 +57,16 @@ module TTY
|
|
56
57
|
|
57
58
|
selected = select_choice(@input)
|
58
59
|
|
59
|
-
if selected && selected.key.to_s ==
|
60
|
+
if selected && selected.key.to_s == "h"
|
60
61
|
expand
|
61
62
|
@selected = nil
|
62
|
-
@input =
|
63
|
+
@input = ""
|
63
64
|
elsif selected
|
64
65
|
@done = true
|
65
66
|
@selected = selected
|
66
67
|
@hint = nil
|
67
68
|
else
|
68
|
-
@input =
|
69
|
+
@input = ""
|
69
70
|
end
|
70
71
|
end
|
71
72
|
alias keyreturn keyenter
|
@@ -103,6 +104,13 @@ module TTY
|
|
103
104
|
@default = value
|
104
105
|
end
|
105
106
|
|
107
|
+
# Set quiet mode.
|
108
|
+
#
|
109
|
+
# @api public
|
110
|
+
def quiet(value)
|
111
|
+
@quiet = value
|
112
|
+
end
|
113
|
+
|
106
114
|
# Add a single choice
|
107
115
|
#
|
108
116
|
# @api public
|
@@ -154,19 +162,19 @@ module TTY
|
|
154
162
|
elsif @input.to_s.empty? && default_key
|
155
163
|
keys[@default - 1] = @prompt.decorate(default_key, @active_color)
|
156
164
|
end
|
157
|
-
keys.join(
|
165
|
+
keys.join(",")
|
158
166
|
end
|
159
167
|
|
160
168
|
# @api private
|
161
169
|
def render
|
162
|
-
@input =
|
170
|
+
@input = ""
|
163
171
|
until @done
|
164
172
|
question = render_question
|
165
173
|
@prompt.print(question)
|
166
174
|
read_input
|
167
175
|
@prompt.print(refresh(question.lines.count))
|
168
176
|
end
|
169
|
-
@prompt.print(render_question)
|
177
|
+
@prompt.print(render_question) unless @quiet
|
170
178
|
answer
|
171
179
|
end
|
172
180
|
|
@@ -199,7 +207,7 @@ module TTY
|
|
199
207
|
#
|
200
208
|
# @api private
|
201
209
|
def render_hint
|
202
|
-
"\n" + @prompt.decorate(
|
210
|
+
"\n" + @prompt.decorate(">> ", @active_color) +
|
203
211
|
@hint +
|
204
212
|
@prompt.cursor.prev_line +
|
205
213
|
@prompt.cursor.forward(@prompt.strip(render_header).size)
|
@@ -274,7 +282,7 @@ module TTY
|
|
274
282
|
if @selected && @selected.key == choice.key
|
275
283
|
chosen = @prompt.decorate(chosen, @active_color)
|
276
284
|
end
|
277
|
-
output <<
|
285
|
+
output << " " + chosen + "\n"
|
278
286
|
end
|
279
287
|
output.join
|
280
288
|
end
|
@@ -294,7 +302,7 @@ module TTY
|
|
294
302
|
if choice.key.length != 1
|
295
303
|
errors << "Choice key `#{choice.key}` is more than one character long."
|
296
304
|
end
|
297
|
-
if choice.key.to_s ==
|
305
|
+
if choice.key.to_s == "h"
|
298
306
|
errors << "Choice key `#{choice.key}` is reserved for help menu."
|
299
307
|
end
|
300
308
|
if keys.include?(choice.key)
|
data/lib/tty/prompt/keypress.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
3
|
+
require_relative "question"
|
4
|
+
require_relative "timer"
|
5
5
|
|
6
6
|
module TTY
|
7
7
|
class Prompt
|
@@ -20,7 +20,7 @@ module TTY
|
|
20
20
|
@interval = options.fetch(:interval) {
|
21
21
|
(@timeout != UndefinedSetting && @timeout < 1) ? @timeout : 1
|
22
22
|
}
|
23
|
-
@decimals = (@interval.to_s.split(
|
23
|
+
@decimals = (@interval.to_s.split(".")[1] || []).size
|
24
24
|
@countdown = @timeout
|
25
25
|
time = timeout? ? Float(@timeout) : nil
|
26
26
|
@timer = Timer.new(time, Float(@interval))
|
data/lib/tty/prompt/list.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "English"
|
4
4
|
|
5
|
-
require_relative
|
6
|
-
require_relative
|
7
|
-
require_relative
|
5
|
+
require_relative "choices"
|
6
|
+
require_relative "paginator"
|
7
|
+
require_relative "block_paginator"
|
8
8
|
|
9
9
|
module TTY
|
10
10
|
class Prompt
|
@@ -13,8 +13,6 @@ module TTY
|
|
13
13
|
#
|
14
14
|
# @api private
|
15
15
|
class List
|
16
|
-
HELP = '(Use %s arrow%s keys, press Enter to select%s)'
|
17
|
-
|
18
16
|
# Allowed keys for filter, along with backspace and canc.
|
19
17
|
FILTER_KEYS_MATCHER = /\A([[:alnum:]]|[[:punct:]])\Z/.freeze
|
20
18
|
|
@@ -45,9 +43,11 @@ module TTY
|
|
45
43
|
@cycle = options.fetch(:cycle) { false }
|
46
44
|
@filterable = options.fetch(:filter) { false }
|
47
45
|
@symbols = @prompt.symbols.merge(options.fetch(:symbols, {}))
|
46
|
+
@quiet = options.fetch(:quiet) { @prompt.quiet }
|
48
47
|
@filter = []
|
49
48
|
@filter_cache = {}
|
50
49
|
@help = options[:help]
|
50
|
+
@show_help = options.fetch(:show_help) { :start }
|
51
51
|
@first_render = true
|
52
52
|
@done = false
|
53
53
|
@per_page = options[:per_page]
|
@@ -135,6 +135,15 @@ module TTY
|
|
135
135
|
@help = (@help.nil? && !not_set) ? value : default_help
|
136
136
|
end
|
137
137
|
|
138
|
+
# Change when help is displayed
|
139
|
+
#
|
140
|
+
# @api public
|
141
|
+
def show_help(value = (not_set = true))
|
142
|
+
return @show_ehlp if not_set
|
143
|
+
|
144
|
+
@show_help = value
|
145
|
+
end
|
146
|
+
|
138
147
|
# Information about arrow keys
|
139
148
|
#
|
140
149
|
# @return [String]
|
@@ -145,25 +154,27 @@ module TTY
|
|
145
154
|
left_right = @symbols[:arrow_left] + "/" + @symbols[:arrow_right]
|
146
155
|
|
147
156
|
arrows = [up_down]
|
148
|
-
arrows << "
|
157
|
+
arrows << "/" if paginated?
|
149
158
|
arrows << left_right if paginated?
|
150
159
|
arrows.join
|
151
160
|
end
|
152
161
|
|
153
162
|
# Default help text
|
154
163
|
#
|
155
|
-
#
|
164
|
+
# Note that enumeration and filter are mutually exclusive
|
165
|
+
#
|
166
|
+
# @a public
|
156
167
|
def default_help
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
168
|
+
str = []
|
169
|
+
str << "(Press "
|
170
|
+
str << "#{arrows_help} arrow"
|
171
|
+
str << " or 1-#{choices.size} number" if enumerate?
|
172
|
+
str << " to move"
|
173
|
+
str << (filterable? ? "," : " and")
|
174
|
+
str << " Enter to select"
|
175
|
+
str << " and letters to filter" if filterable?
|
176
|
+
str << ")"
|
177
|
+
str.join
|
167
178
|
end
|
168
179
|
|
169
180
|
# Set selecting active index using number pad
|
@@ -173,6 +184,13 @@ module TTY
|
|
173
184
|
@enum = value
|
174
185
|
end
|
175
186
|
|
187
|
+
# Set whether selected answers are echoed
|
188
|
+
#
|
189
|
+
# @api public
|
190
|
+
def quiet(value)
|
191
|
+
@quiet = value
|
192
|
+
end
|
193
|
+
|
176
194
|
# Add a single choice
|
177
195
|
#
|
178
196
|
# @api public
|
@@ -198,9 +216,8 @@ module TTY
|
|
198
216
|
@choices
|
199
217
|
else
|
200
218
|
filter_value = @filter.join.downcase
|
201
|
-
@filter_cache[filter_value] ||= @choices.select do |choice|
|
202
|
-
|
203
|
-
choice.name.downcase.include?(filter_value)
|
219
|
+
@filter_cache[filter_value] ||= @choices.enabled.select do |choice|
|
220
|
+
choice.name.to_s.downcase.include?(filter_value)
|
204
221
|
end
|
205
222
|
end
|
206
223
|
else
|
@@ -411,7 +428,7 @@ module TTY
|
|
411
428
|
|
412
429
|
@prompt.print(refresh(question_lines_count(question_lines)))
|
413
430
|
end
|
414
|
-
@prompt.print(render_question)
|
431
|
+
@prompt.print(render_question) unless @quiet
|
415
432
|
answer
|
416
433
|
ensure
|
417
434
|
@prompt.print(@prompt.show)
|
@@ -478,6 +495,20 @@ module TTY
|
|
478
495
|
"(Filter: #{@filter.join.inspect})"
|
479
496
|
end
|
480
497
|
|
498
|
+
# Check if help is shown only on start
|
499
|
+
#
|
500
|
+
# @api private
|
501
|
+
def help_start?
|
502
|
+
@show_help =~ /start/i
|
503
|
+
end
|
504
|
+
|
505
|
+
# Check if help is always displayed
|
506
|
+
#
|
507
|
+
# @api private
|
508
|
+
def help_always?
|
509
|
+
@show_help =~ /always/i
|
510
|
+
end
|
511
|
+
|
481
512
|
# Render initial help and selected choice
|
482
513
|
#
|
483
514
|
# @return [String]
|
@@ -487,7 +518,8 @@ module TTY
|
|
487
518
|
if @done
|
488
519
|
selected_item = choices[@active - 1].name
|
489
520
|
@prompt.decorate(selected_item.to_s, @active_color)
|
490
|
-
elsif @first_render
|
521
|
+
elsif (@first_render && (help_start? || help_always?)) ||
|
522
|
+
(help_always? && !@filter.any?)
|
491
523
|
@prompt.decorate(help, @help_color)
|
492
524
|
elsif filterable? && @filter.any?
|
493
525
|
@prompt.decorate(filter_help, @help_color)
|
@@ -504,7 +536,7 @@ module TTY
|
|
504
536
|
|
505
537
|
sync_paginators if @paging_changed
|
506
538
|
paginator.paginate(choices, @active, @per_page) do |choice, index|
|
507
|
-
num = enumerate? ? (index + 1).to_s + @enum +
|
539
|
+
num = enumerate? ? (index + 1).to_s + @enum + " " : ""
|
508
540
|
message = if index + 1 == @active && !choice.disabled?
|
509
541
|
selected = "#{@symbols[:marker]} #{num}#{choice.name}"
|
510
542
|
@prompt.decorate(selected.to_s, @active_color)
|
@@ -515,7 +547,7 @@ module TTY
|
|
515
547
|
" #{num}#{choice.name}"
|
516
548
|
end
|
517
549
|
end_index = paginated? ? paginator.end_index : choices.size - 1
|
518
|
-
newline = (index == end_index) ?
|
550
|
+
newline = (index == end_index) ? "" : "\n"
|
519
551
|
output << (message + newline)
|
520
552
|
end
|
521
553
|
|