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.rb
CHANGED
@@ -1,2 +1 @@
|
|
1
|
-
require_relative
|
2
|
-
require_relative 'tty/test_prompt'
|
1
|
+
require_relative "tty/prompt"
|
data/lib/tty/prompt.rb
CHANGED
@@ -1,51 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
|
9
|
-
require_relative
|
10
|
-
require_relative
|
11
|
-
require_relative
|
12
|
-
require_relative
|
13
|
-
require_relative
|
14
|
-
require_relative
|
15
|
-
require_relative
|
16
|
-
require_relative
|
17
|
-
require_relative
|
18
|
-
require_relative
|
19
|
-
require_relative
|
20
|
-
require_relative
|
21
|
-
require_relative
|
22
|
-
require_relative
|
23
|
-
require_relative
|
24
|
-
require_relative
|
3
|
+
require "forwardable"
|
4
|
+
require "pastel"
|
5
|
+
require "tty-cursor"
|
6
|
+
require "tty-reader"
|
7
|
+
require "tty-screen"
|
8
|
+
|
9
|
+
require_relative "prompt/answers_collector"
|
10
|
+
require_relative "prompt/confirm_question"
|
11
|
+
require_relative "prompt/errors"
|
12
|
+
require_relative "prompt/expander"
|
13
|
+
require_relative "prompt/enum_list"
|
14
|
+
require_relative "prompt/keypress"
|
15
|
+
require_relative "prompt/list"
|
16
|
+
require_relative "prompt/multi_list"
|
17
|
+
require_relative "prompt/multiline"
|
18
|
+
require_relative "prompt/mask_question"
|
19
|
+
require_relative "prompt/question"
|
20
|
+
require_relative "prompt/slider"
|
21
|
+
require_relative "prompt/statement"
|
22
|
+
require_relative "prompt/suggestion"
|
23
|
+
require_relative "prompt/symbols"
|
24
|
+
require_relative "prompt/utils"
|
25
|
+
require_relative "prompt/version"
|
25
26
|
|
26
27
|
module TTY
|
27
28
|
# A main entry for asking prompt questions.
|
28
29
|
class Prompt
|
29
30
|
extend Forwardable
|
30
31
|
|
31
|
-
# Raised when wrong parameter is used to configure prompt
|
32
|
-
ConfigurationError = Class.new(StandardError)
|
33
|
-
|
34
|
-
# Raised when type conversion cannot be performed
|
35
|
-
ConversionError = Class.new(StandardError)
|
36
|
-
|
37
|
-
# Raised when the passed in validation argument is of wrong type
|
38
|
-
ValidationCoercion = Class.new(TypeError)
|
39
|
-
|
40
|
-
# Raised when the required argument is not supplied
|
41
|
-
ArgumentRequired = Class.new(ArgumentError)
|
42
|
-
|
43
|
-
# Raised when the argument validation fails
|
44
|
-
ArgumentValidation = Class.new(ArgumentError)
|
45
|
-
|
46
|
-
# Raised when the argument is not expected
|
47
|
-
InvalidArgument = Class.new(ArgumentError)
|
48
|
-
|
49
32
|
# @api private
|
50
33
|
attr_reader :input
|
51
34
|
|
@@ -71,22 +54,27 @@ module TTY
|
|
71
54
|
# @api private
|
72
55
|
attr_reader :active_color, :help_color, :error_color, :enabled_color
|
73
56
|
|
57
|
+
# Quiet mode
|
58
|
+
#
|
59
|
+
# @api private
|
60
|
+
attr_reader :quiet
|
61
|
+
|
74
62
|
# The collection of display symbols
|
75
63
|
#
|
76
64
|
# @example
|
77
|
-
# prompt = TTY::Prompt.new(symbols: {marker:
|
65
|
+
# prompt = TTY::Prompt.new(symbols: {marker: ">"})
|
78
66
|
#
|
79
67
|
# @return [Hash]
|
80
68
|
#
|
81
69
|
# @api private
|
82
70
|
attr_reader :symbols
|
83
71
|
|
84
|
-
def_delegators :@pastel, :
|
72
|
+
def_delegators :@pastel, :strip
|
85
73
|
|
86
74
|
def_delegators :@cursor, :clear_lines, :clear_line,
|
87
75
|
:show, :hide
|
88
76
|
|
89
|
-
def_delegators :@reader, :read_char, :read_keypress,
|
77
|
+
def_delegators :@reader, :read_char, :read_keypress, :read_line,
|
90
78
|
:read_multiline, :on, :subscribe, :unsubscribe, :trigger,
|
91
79
|
:count_screen_lines
|
92
80
|
|
@@ -94,69 +82,90 @@ module TTY
|
|
94
82
|
|
95
83
|
def self.messages
|
96
84
|
{
|
97
|
-
range?:
|
98
|
-
valid?:
|
99
|
-
required?:
|
85
|
+
range?: "Value %{value} must be within the range %{in}",
|
86
|
+
valid?: "Your answer is invalid (must match %{valid})",
|
87
|
+
required?: "Value must be provided",
|
88
|
+
convert?: "Cannot convert `%{value}` to '%{type}' type"
|
100
89
|
}
|
101
90
|
end
|
102
91
|
|
103
|
-
# This fixes Forwardable module keyword arguments warning
|
104
|
-
def read_line(message, **options)
|
105
|
-
@reader.read_line(message, **options)
|
106
|
-
end
|
107
|
-
|
108
92
|
# Initialize a Prompt
|
109
93
|
#
|
110
|
-
# @param [
|
111
|
-
# @option options [IO] :input
|
94
|
+
# @param [IO] :input
|
112
95
|
# the input stream
|
113
|
-
# @
|
96
|
+
# @param [IO] :output
|
114
97
|
# the output stream
|
115
|
-
# @
|
98
|
+
# @param [Hash] :env
|
116
99
|
# the environment variables
|
117
|
-
# @
|
100
|
+
# @param [Hash] :symbols
|
101
|
+
# the symbols displayed in prompts such as :marker, :cross
|
102
|
+
# @param options [Boolean] :quiet
|
103
|
+
# enable quiet mode, don't re-echo the question
|
104
|
+
# @param [String] :prefix
|
118
105
|
# the prompt prefix, by default empty
|
119
|
-
# @
|
106
|
+
# @param [Symbol] :interrupt
|
107
|
+
# handling of Ctrl+C key out of :signal, :exit, :noop
|
108
|
+
# @param [Boolean] :track_history
|
109
|
+
# disable line history tracking, true by default
|
110
|
+
# @param [Boolean] :enable_color
|
120
111
|
# enable color support, true by default
|
121
|
-
# @
|
112
|
+
# @param [String,Proc] :active_color
|
122
113
|
# the color used for selected option
|
123
|
-
# @
|
114
|
+
# @param [String,Proc] :help_color
|
124
115
|
# the color used for help text
|
125
|
-
# @
|
116
|
+
# @param [String] :error_color
|
126
117
|
# the color used for displaying error messages
|
127
|
-
# @option options [Symbol] :interrupt
|
128
|
-
# handling of Ctrl+C key out of :signal, :exit, :noop
|
129
|
-
# @option options [Boolean] :track_history
|
130
|
-
# disable line history tracking, true by default
|
131
|
-
# @option options [Hash] :symbols
|
132
|
-
# the symbols displayed in prompts such as :marker, :cross
|
133
118
|
#
|
134
119
|
# @api public
|
135
|
-
def initialize(
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
@
|
140
|
-
@
|
141
|
-
@
|
142
|
-
@
|
143
|
-
@
|
144
|
-
@
|
145
|
-
@
|
146
|
-
@
|
147
|
-
@
|
120
|
+
def initialize(input: $stdin, output: $stdout, env: ENV, symbols: {},
|
121
|
+
prefix: "", interrupt: :error, track_history: true,
|
122
|
+
quiet: false, enable_color: nil, active_color: :green,
|
123
|
+
help_color: :bright_black, error_color: :red)
|
124
|
+
@input = input
|
125
|
+
@output = output
|
126
|
+
@env = env
|
127
|
+
@prefix = prefix
|
128
|
+
@enabled_color = enable_color
|
129
|
+
@active_color = active_color
|
130
|
+
@help_color = help_color
|
131
|
+
@error_color = error_color
|
132
|
+
@interrupt = interrupt
|
133
|
+
@track_history = track_history
|
134
|
+
@symbols = Symbols.symbols.merge(symbols)
|
135
|
+
@quiet = quiet
|
148
136
|
|
149
137
|
@cursor = TTY::Cursor
|
150
|
-
@pastel =
|
138
|
+
@pastel = enabled_color.nil? ? Pastel.new : Pastel.new(enabled: enabled_color)
|
151
139
|
@reader = TTY::Reader.new(
|
152
|
-
input:
|
153
|
-
output:
|
154
|
-
interrupt:
|
155
|
-
track_history:
|
156
|
-
env:
|
140
|
+
input: input,
|
141
|
+
output: output,
|
142
|
+
interrupt: interrupt,
|
143
|
+
track_history: track_history,
|
144
|
+
env: env
|
157
145
|
)
|
158
146
|
end
|
159
147
|
|
148
|
+
# Decorate a string with colors
|
149
|
+
#
|
150
|
+
# @param [String] :string
|
151
|
+
# the string to color
|
152
|
+
# @param [Array<Proc|Symbol>] :colors
|
153
|
+
# collection of color symbols or callable object
|
154
|
+
#
|
155
|
+
# @api public
|
156
|
+
def decorate(string, *colors)
|
157
|
+
if Utils.blank?(string) || @enabled_color == false || colors.empty?
|
158
|
+
return string
|
159
|
+
end
|
160
|
+
|
161
|
+
coloring = colors.first
|
162
|
+
if coloring.respond_to?(:call)
|
163
|
+
coloring.call(string)
|
164
|
+
else
|
165
|
+
@pastel.decorate(string, *colors)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
160
169
|
# Invoke a question type of prompt
|
161
170
|
#
|
162
171
|
# @example
|
@@ -189,7 +198,7 @@ module TTY
|
|
189
198
|
# @return [TTY::Prompt::Question]
|
190
199
|
#
|
191
200
|
# @api public
|
192
|
-
def ask(message =
|
201
|
+
def ask(message = "", **options, &block)
|
193
202
|
invoke_question(Question, message, **options, &block)
|
194
203
|
end
|
195
204
|
|
@@ -198,19 +207,19 @@ module TTY
|
|
198
207
|
# @see #ask
|
199
208
|
#
|
200
209
|
# @api public
|
201
|
-
def keypress(message =
|
210
|
+
def keypress(message = "", **options, &block)
|
202
211
|
invoke_question(Keypress, message, **options, &block)
|
203
212
|
end
|
204
213
|
|
205
214
|
# Ask a question with a multiline answer
|
206
215
|
#
|
207
216
|
# @example
|
208
|
-
# prompt.multiline(
|
217
|
+
# prompt.multiline("Description?")
|
209
218
|
#
|
210
219
|
# @return [Array[String]]
|
211
220
|
#
|
212
221
|
# @api public
|
213
|
-
def multiline(message =
|
222
|
+
def multiline(message = "", **options, &block)
|
214
223
|
invoke_question(Multiline, message, **options, &block)
|
215
224
|
end
|
216
225
|
|
@@ -226,9 +235,7 @@ module TTY
|
|
226
235
|
# @api public
|
227
236
|
def invoke_select(object, question, *args, &block)
|
228
237
|
options = Utils.extract_options!(args)
|
229
|
-
choices = if block
|
230
|
-
[]
|
231
|
-
elsif args.empty?
|
238
|
+
choices = if args.empty? && !block
|
232
239
|
possible = options.dup
|
233
240
|
options = {}
|
234
241
|
possible
|
@@ -251,7 +258,7 @@ module TTY
|
|
251
258
|
# @return [TTY::Prompt::MaskQuestion]
|
252
259
|
#
|
253
260
|
# @api public
|
254
|
-
def mask(message =
|
261
|
+
def mask(message = "", **options, &block)
|
255
262
|
invoke_question(MaskQuestion, message, **options, &block)
|
256
263
|
end
|
257
264
|
|
@@ -320,42 +327,36 @@ module TTY
|
|
320
327
|
end
|
321
328
|
|
322
329
|
# A shortcut method to ask the user positive question and return
|
323
|
-
# true for
|
330
|
+
# true for "yes" reply, false for "no".
|
324
331
|
#
|
325
332
|
# @example
|
326
333
|
# prompt = TTY::Prompt.new
|
327
|
-
# prompt.yes?(
|
334
|
+
# prompt.yes?("Are you human?")
|
328
335
|
# # => Are you human? (Y/n)
|
329
336
|
#
|
330
337
|
# @return [Boolean]
|
331
338
|
#
|
332
339
|
# @api public
|
333
|
-
def yes?(message,
|
334
|
-
|
335
|
-
|
336
|
-
options.merge!(defaults.reject { |k, _| options.key?(k) })
|
337
|
-
|
338
|
-
question = ConfirmQuestion.new(self, **options)
|
340
|
+
def yes?(message, **options, &block)
|
341
|
+
opts = { default: true }.merge(options)
|
342
|
+
question = ConfirmQuestion.new(self, **opts)
|
339
343
|
question.call(message, &block)
|
340
344
|
end
|
341
345
|
|
342
346
|
# A shortcut method to ask the user negative question and return
|
343
|
-
# true for
|
347
|
+
# true for "no" reply.
|
344
348
|
#
|
345
349
|
# @example
|
346
350
|
# prompt = TTY::Prompt.new
|
347
|
-
# prompt.no?(
|
351
|
+
# prompt.no?("Are you alien?") # => true
|
348
352
|
# # => Are you human? (y/N)
|
349
353
|
#
|
350
354
|
# @return [Boolean]
|
351
355
|
#
|
352
356
|
# @api public
|
353
|
-
def no?(message,
|
354
|
-
|
355
|
-
|
356
|
-
options.merge!(defaults.reject { |k, _| options.key?(k) })
|
357
|
-
|
358
|
-
question = ConfirmQuestion.new(self, **options)
|
357
|
+
def no?(message, **options, &block)
|
358
|
+
opts = { default: false }.merge(options)
|
359
|
+
question = ConfirmQuestion.new(self, **opts)
|
359
360
|
!question.call(message, &block)
|
360
361
|
end
|
361
362
|
|
@@ -364,15 +365,15 @@ module TTY
|
|
364
365
|
# @example
|
365
366
|
# prompt = TTY::Prompt.new
|
366
367
|
# choices = [{
|
367
|
-
# key:
|
368
|
-
# name:
|
368
|
+
# key: "Y",
|
369
|
+
# name: "Overwrite",
|
369
370
|
# value: :yes
|
370
371
|
# }, {
|
371
|
-
# key:
|
372
|
-
# name:
|
372
|
+
# key: "n",
|
373
|
+
# name: "Skip",
|
373
374
|
# value: :no
|
374
375
|
# }]
|
375
|
-
# prompt.expand(
|
376
|
+
# prompt.expand("Overwirte Gemfile?", choices)
|
376
377
|
#
|
377
378
|
# @return [Object]
|
378
379
|
# the user specified value
|
@@ -386,7 +387,7 @@ module TTY
|
|
386
387
|
#
|
387
388
|
# @example
|
388
389
|
# prompt = TTY::Prompt.new
|
389
|
-
# prompt.slider(
|
390
|
+
# prompt.slider("What size?", min: 32, max: 54, step: 2)
|
390
391
|
#
|
391
392
|
# @param [String] question
|
392
393
|
# the question to ask
|
@@ -394,8 +395,7 @@ module TTY
|
|
394
395
|
# @return [String]
|
395
396
|
#
|
396
397
|
# @api public
|
397
|
-
def slider(question,
|
398
|
-
options = Utils.extract_options!(args)
|
398
|
+
def slider(question, **options, &block)
|
399
399
|
slider = Slider.new(self, **options)
|
400
400
|
slider.call(question, &block)
|
401
401
|
end
|
@@ -411,11 +411,11 @@ module TTY
|
|
411
411
|
# @return [String]
|
412
412
|
#
|
413
413
|
# @api public
|
414
|
-
def say(message =
|
414
|
+
def say(message = "", **options)
|
415
415
|
message = message.to_s
|
416
416
|
return if message.empty?
|
417
417
|
|
418
|
-
statement = Statement.new(self, options)
|
418
|
+
statement = Statement.new(self, **options)
|
419
419
|
statement.call(message)
|
420
420
|
end
|
421
421
|
|
@@ -430,9 +430,9 @@ module TTY
|
|
430
430
|
# @return [Array] messages
|
431
431
|
#
|
432
432
|
# @api public
|
433
|
-
def ok(*args)
|
434
|
-
|
435
|
-
args.each { |message| say
|
433
|
+
def ok(*args, **options)
|
434
|
+
opts = { color: :green }.merge(options)
|
435
|
+
args.each { |message| say(message, **opts) }
|
436
436
|
end
|
437
437
|
|
438
438
|
# Print statement(s) out in yellow color.
|
@@ -446,9 +446,9 @@ module TTY
|
|
446
446
|
# @return [Array] messages
|
447
447
|
#
|
448
448
|
# @api public
|
449
|
-
def warn(*args)
|
450
|
-
|
451
|
-
args.each { |message| say
|
449
|
+
def warn(*args, **options)
|
450
|
+
opts = { color: :yellow }.merge(options)
|
451
|
+
args.each { |message| say(message, **opts) }
|
452
452
|
end
|
453
453
|
|
454
454
|
# Print statement(s) out in red color.
|
@@ -462,9 +462,9 @@ module TTY
|
|
462
462
|
# @return [Array] messages
|
463
463
|
#
|
464
464
|
# @api public
|
465
|
-
def error(*args)
|
466
|
-
|
467
|
-
args.each { |message| say
|
465
|
+
def error(*args, **options)
|
466
|
+
opts = { color: :red }.merge(options)
|
467
|
+
args.each { |message| say(message, **opts) }
|
468
468
|
end
|
469
469
|
|
470
470
|
# Print debug information in terminal top right corner
|
@@ -481,7 +481,7 @@ module TTY
|
|
481
481
|
longest = messages.max_by(&:length).size
|
482
482
|
width = TTY::Screen.width - longest
|
483
483
|
print cursor.save
|
484
|
-
messages.reverse_each
|
484
|
+
messages.reverse_each do |msg|
|
485
485
|
print cursor.column(width) + cursor.up + cursor.clear_line_after
|
486
486
|
print msg
|
487
487
|
end
|
@@ -493,7 +493,7 @@ module TTY
|
|
493
493
|
# matches to suggest an unambigous string
|
494
494
|
#
|
495
495
|
# @example
|
496
|
-
# prompt.suggest(
|
496
|
+
# prompt.suggest("sta", ["status", "stage", "commit", "branch"])
|
497
497
|
# # => "status, stage"
|
498
498
|
#
|
499
499
|
# @param [String] message
|
@@ -520,7 +520,7 @@ module TTY
|
|
520
520
|
#
|
521
521
|
# @example
|
522
522
|
# prompt.collect do
|
523
|
-
# key(:name).ask(
|
523
|
+
# key(:name).ask("Name?")
|
524
524
|
# end
|
525
525
|
#
|
526
526
|
# @return [Hash]
|
@@ -562,21 +562,24 @@ module TTY
|
|
562
562
|
$stderr
|
563
563
|
end
|
564
564
|
|
565
|
-
# Inspect
|
565
|
+
# Inspect this instance public attributes
|
566
|
+
#
|
566
567
|
# @return [String]
|
567
568
|
#
|
568
569
|
# @api public
|
569
570
|
def inspect
|
570
|
-
attributes =
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
571
|
+
attributes = [
|
572
|
+
:prefix,
|
573
|
+
:quiet,
|
574
|
+
:enabled_color,
|
575
|
+
:active_color,
|
576
|
+
:error_color,
|
577
|
+
:help_color,
|
578
|
+
:input,
|
579
|
+
:output,
|
580
|
+
]
|
581
|
+
name = self.class.name
|
582
|
+
"#<#{name}#{attributes.map { |attr| " #{attr}=#{send(attr).inspect}" }.join}>"
|
580
583
|
end
|
581
584
|
end # Prompt
|
582
585
|
end # TTY
|