tty-prompt 0.22.0 → 0.23.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 +13 -1
- data/README.md +68 -27
- data/lib/tty/prompt.rb +6 -2
- data/lib/tty/prompt/choice.rb +4 -3
- data/lib/tty/prompt/choices.rb +2 -1
- data/lib/tty/prompt/confirm_question.rb +4 -0
- data/lib/tty/prompt/enum_list.rb +31 -6
- data/lib/tty/prompt/evaluator.rb +1 -1
- data/lib/tty/prompt/expander.rb +7 -3
- data/lib/tty/prompt/keypress.rb +2 -0
- data/lib/tty/prompt/list.rb +44 -13
- data/lib/tty/prompt/mask_question.rb +7 -3
- data/lib/tty/prompt/multi_list.rb +16 -4
- data/lib/tty/prompt/multiline.rb +2 -1
- data/lib/tty/prompt/question.rb +11 -5
- data/lib/tty/prompt/question/checks.rb +3 -3
- data/lib/tty/prompt/question/modifier.rb +4 -2
- data/lib/tty/prompt/selected_choices.rb +1 -0
- data/lib/tty/prompt/slider.rb +50 -22
- data/lib/tty/prompt/suggestion.rb +1 -0
- data/lib/tty/prompt/test.rb +2 -2
- data/lib/tty/prompt/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3dcdfb83f0945b162d19c5a068386009fbc5cc2f90969374018ee9aad72bd116
|
4
|
+
data.tar.gz: 004ebca9f017ea58bca8d4400e61d4817394b55343c0ecc3a3727f8818103d8f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e9fe7560e4dd4aca6e47d6ca67dca40079b4350ac97834d9bdca8c21254048097b338092177bebe5a1a2da1609fce1e155ee4a373c3d16c6979fc261a02dcc52
|
7
|
+
data.tar.gz: eff0e563cde0179831056cf107f61e17681269b705f7d499a657d84f365197500c5ea0220aad8b3959ef3d82bd0ac1db49d8beb4566881cb257112b2f69beafa
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## [v0.23.0] - 2020-12-14
|
4
|
+
|
5
|
+
### Added
|
6
|
+
* Add the ability to provide an arbitrary array of values to Prompt::Slider by Katelyn Schiesser (@slowbro)
|
7
|
+
|
8
|
+
### Changed
|
9
|
+
* Change to allow default option to be choice name as well as index in select, multi_select and enum_select prompts
|
10
|
+
|
11
|
+
### Fixed
|
12
|
+
* Fix left and right key navigation while filtering choices in the #select and #multi_select prompts
|
13
|
+
|
3
14
|
## [v0.22.0] - 2020-07-20
|
4
15
|
|
5
16
|
### Added
|
@@ -43,7 +54,7 @@
|
|
43
54
|
* Change gemspec to remove test artifacts
|
44
55
|
|
45
56
|
### Fixed
|
46
|
-
* Fix :help_color option for
|
57
|
+
* Fix :help_color option for multi_select prompt by @robbystk
|
47
58
|
|
48
59
|
## [v0.20.0] - 2019-11-24
|
49
60
|
|
@@ -383,6 +394,7 @@
|
|
383
394
|
|
384
395
|
* Initial implementation and release
|
385
396
|
|
397
|
+
[v0.23.0]: https://github.com/piotrmurach/tty-prompt/compare/v0.22.0...v0.23.0
|
386
398
|
[v0.22.0]: https://github.com/piotrmurach/tty-prompt/compare/v0.21.0...v0.22.0
|
387
399
|
[v0.21.0]: https://github.com/piotrmurach/tty-prompt/compare/v0.20.0...v0.21.0
|
388
400
|
[v0.20.0]: https://github.com/piotrmurach/tty-prompt/compare/v0.19.0...v0.20.0
|
data/README.md
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
<div align="center">
|
2
|
-
<a href="https://
|
2
|
+
<a href="https://ttytoolkit.org"><img width="130" src="https://github.com/piotrmurach/tty/raw/master/images/tty.png" alt="TTY Toolkit logo" /></a>
|
3
3
|
</div>
|
4
4
|
|
5
5
|
# TTY::Prompt [][gitter]
|
6
6
|
|
7
7
|
[][gem]
|
8
|
-
[][gh_actions_ci]
|
9
9
|
[][appveyor]
|
10
10
|
[][codeclimate]
|
11
11
|
[][coverage]
|
@@ -13,6 +13,7 @@
|
|
13
13
|
|
14
14
|
[gitter]: https://gitter.im/piotrmurach/tty
|
15
15
|
[gem]: http://badge.fury.io/rb/tty-prompt
|
16
|
+
[gh_actions_ci]: https://github.com/piotrmurach/tty-prompt/actions?query=workflow%3ACI
|
16
17
|
[travis]: http://travis-ci.org/piotrmurach/tty-prompt
|
17
18
|
[appveyor]: https://ci.appveyor.com/project/piotrmurach/tty-prompt
|
18
19
|
[codeclimate]: https://codeclimate.com/github/piotrmurach/tty-prompt
|
@@ -23,10 +24,6 @@
|
|
23
24
|
|
24
25
|
**TTY::Prompt** provides independent prompt component for [TTY](https://github.com/piotrmurach/tty) toolkit.
|
25
26
|
|
26
|
-
<div align="center">
|
27
|
-
<img alt="Available prompts demo" src="assets/demo.gif" width="562" height="226">
|
28
|
-
</div>
|
29
|
-
|
30
27
|
## Features
|
31
28
|
|
32
29
|
* Number of prompt types for gathering user input
|
@@ -118,7 +115,7 @@ Or install it yourself as:
|
|
118
115
|
* [3. settings](#3-settings)
|
119
116
|
* [3.1 :symbols](#31-symbols)
|
120
117
|
* [3.2 :active_color](#32-active_color)
|
121
|
-
* [3.3 :enable_color](#33-
|
118
|
+
* [3.3 :enable_color](#33-enable_color)
|
122
119
|
* [3.4 :help_color](#34-help_color)
|
123
120
|
* [3.5 :interrupt](#35-interrupt)
|
124
121
|
* [3.6 :prefix](#36-prefix)
|
@@ -304,7 +301,7 @@ prompt.ask("Provide keys and values:", convert: :int_map)
|
|
304
301
|
If a user provides a wrong type for conversion an error message will be printed in the console:
|
305
302
|
|
306
303
|
```ruby
|
307
|
-
prompt.ask("Provide digit:", convert: float)
|
304
|
+
prompt.ask("Provide digit:", convert: :float)
|
308
305
|
# Provide digit: x
|
309
306
|
# >> Cannot convert `x` into 'float' type
|
310
307
|
```
|
@@ -312,8 +309,8 @@ prompt.ask("Provide digit:", convert: float)
|
|
312
309
|
You can further customize error message:
|
313
310
|
|
314
311
|
```ruby
|
315
|
-
prompt.ask("Provide digit:", convert: float) do |q|
|
316
|
-
q.convert(:float, "Wrong value of %{value} for %{type} conversion"
|
312
|
+
prompt.ask("Provide digit:", convert: :float) do |q|
|
313
|
+
q.convert(:float, "Wrong value of %{value} for %{type} conversion")
|
317
314
|
# or
|
318
315
|
q.convert :float
|
319
316
|
q.messages[:convert?] = "Wrong value of %{value} for %{type} conversion"
|
@@ -384,7 +381,7 @@ To change default range validation error message do:
|
|
384
381
|
```ruby
|
385
382
|
prompt.ask("How spicy on scale (1-5)? ") do |q|
|
386
383
|
q.in "1-5"
|
387
|
-
q.messages[:range?] = "%{value} out of expected range
|
384
|
+
q.messages[:range?] = "%{value} out of expected range %{in}"
|
388
385
|
end
|
389
386
|
```
|
390
387
|
|
@@ -393,7 +390,7 @@ end
|
|
393
390
|
In order to check that provided input falls inside a range of inputs use the `in` option. For example, if we wanted to ask a user for a single digit in given range we may do following:
|
394
391
|
|
395
392
|
```ruby
|
396
|
-
ask("Provide number in range: 0-9?") { |q| q.in("0-9") }
|
393
|
+
prompt.ask("Provide number in range: 0-9?") { |q| q.in("0-9") }
|
397
394
|
```
|
398
395
|
|
399
396
|
#### 2.1.7 `:modify`
|
@@ -439,13 +436,13 @@ In order to validate that input matches a given pattern you can pass the `valida
|
|
439
436
|
|
440
437
|
```ruby
|
441
438
|
prompt.ask("What is your username?") do |q|
|
442
|
-
q.validate
|
439
|
+
q.validate(/\A[^.]+\.[^.]+\Z/)
|
443
440
|
end
|
444
441
|
```
|
445
442
|
|
446
443
|
```ruby
|
447
444
|
prompt.ask("What is your username?") do |q|
|
448
|
-
q.validate {
|
445
|
+
q.validate ->(input) { input =~ /\A[^.]+\.[^.]+\Z/ }
|
449
446
|
end
|
450
447
|
```
|
451
448
|
|
@@ -495,7 +492,8 @@ prompt.multiline("Description?")
|
|
495
492
|
# I know not all that may be coming,
|
496
493
|
# but be it what it will,
|
497
494
|
# I'll go to it laughing.
|
498
|
-
# =>
|
495
|
+
# =>
|
496
|
+
# ["I know not all that may be coming,\n", "but be it what it will,\n", "I'll go to it laughing.\n"]
|
499
497
|
```
|
500
498
|
|
501
499
|
The `multiline` uses similar options to those supported by `ask` prompt. For example, to provide default description:
|
@@ -522,11 +520,11 @@ prompt.mask("What is your secret?")
|
|
522
520
|
# => What is your secret? ••••
|
523
521
|
```
|
524
522
|
|
525
|
-
The masking character can be changed by passing
|
523
|
+
The masking character can be changed by passing the `:mask` key:
|
526
524
|
|
527
525
|
```ruby
|
528
526
|
heart = prompt.decorate(prompt.symbols[:heart] + " ", :magenta)
|
529
|
-
prompt.mask("What is your secret?",
|
527
|
+
prompt.mask("What is your secret?", mask: heart)
|
530
528
|
# => What is your secret? ❤ ❤ ❤ ❤ ❤
|
531
529
|
```
|
532
530
|
|
@@ -615,6 +613,12 @@ By default the choice name is also the value the prompt will return when selecte
|
|
615
613
|
|
616
614
|
```ruby
|
617
615
|
choices = {small: 1, medium: 2, large: 3}
|
616
|
+
prompt.select("What size?", choices)
|
617
|
+
# =>
|
618
|
+
# What size? (Press ↑/↓ arrow to move and Enter to select)
|
619
|
+
# ‣ small
|
620
|
+
# medium
|
621
|
+
# large
|
618
622
|
```
|
619
623
|
|
620
624
|
Finally, you can define an array of choices where each choice is a hash value with `:name` & `:value` keys which can include other options for customising individual choices:
|
@@ -637,6 +641,11 @@ prompt.select("What size?") do |menu|
|
|
637
641
|
menu.choice name: "medium", value: 2, disabled: "(out of stock)"
|
638
642
|
menu.choice name: "large", value: 3
|
639
643
|
end
|
644
|
+
# =>
|
645
|
+
# What size? (Press ↑/↓ arrow to move and Enter to select)
|
646
|
+
# ‣ small
|
647
|
+
# ✘ medium (out of stock)
|
648
|
+
# large
|
640
649
|
```
|
641
650
|
|
642
651
|
or in a more compact way:
|
@@ -711,11 +720,12 @@ choices = {"Scorpion" => 1, "Kano" => 2, "Jax" => 3}
|
|
711
720
|
prompt.select("Choose your destiny?", choices)
|
712
721
|
```
|
713
722
|
|
714
|
-
To mark particular answer as selected use `default` with index of the
|
723
|
+
To mark particular answer as selected use `default` with either an index of the choice starting from `1` or a choice's name:
|
715
724
|
|
716
725
|
```ruby
|
717
726
|
prompt.select("Choose your destiny?") do |menu|
|
718
727
|
menu.default 3
|
728
|
+
# or menu.default "Jax"
|
719
729
|
|
720
730
|
menu.choice "Scorpion", 1
|
721
731
|
menu.choice "Kano", 2
|
@@ -728,7 +738,6 @@ end
|
|
728
738
|
# ‣ Jax
|
729
739
|
```
|
730
740
|
|
731
|
-
|
732
741
|
#### 2.6.2.1 `:cycle`
|
733
742
|
|
734
743
|
You can navigate the choices using the arrow keys or define your own key mappings (see [keyboard events](#212-keyboard-events). When reaching the top/bottom of the list, the selection does not cycle around by default. If you wish to enable cycling, you can pass `cycle: true` to `select` and `multi_select`:
|
@@ -924,11 +933,12 @@ prompt.multi_select("Select drinks?") do |menu|
|
|
924
933
|
end
|
925
934
|
```
|
926
935
|
|
927
|
-
To mark choice(s) as selected use the `default` option with index(s) of the
|
936
|
+
To mark choice(s) as selected use the `default` option with either index(s) of the choice(s) starting from `1` or choice name(s):
|
928
937
|
|
929
938
|
```ruby
|
930
939
|
prompt.multi_select("Select drinks?") do |menu|
|
931
940
|
menu.default 2, 5
|
941
|
+
# or menu.default :beer, :whisky
|
932
942
|
|
933
943
|
menu.choice :vodka, {score: 10}
|
934
944
|
menu.choice :beer, {score: 20}
|
@@ -1158,12 +1168,13 @@ end
|
|
1158
1168
|
# Select an editor? /bin/nano
|
1159
1169
|
```
|
1160
1170
|
|
1161
|
-
You can change the indexed numbers by passing `enum` option
|
1171
|
+
You can change the indexed numbers formatting by passing `enum` option. The `default` option lets you specify which choice to mark as selected by default. It accepts an index of the choice starting from `1` or a choice name:
|
1162
1172
|
|
1163
1173
|
```ruby
|
1164
1174
|
choices = %w(nano vim emacs)
|
1165
1175
|
prompt.enum_select("Select an editor?") do |menu|
|
1166
1176
|
menu.default 2
|
1177
|
+
# or menu.defualt "/usr/bin/vim"
|
1167
1178
|
menu.enum "."
|
1168
1179
|
|
1169
1180
|
menu.choice :nano, "/bin/nano"
|
@@ -1377,17 +1388,26 @@ prompt.suggest("b", possible, indent: 4, single_text: "Perhaps you meant?")
|
|
1377
1388
|
|
1378
1389
|
### 2.10 slider
|
1379
1390
|
|
1380
|
-
If you
|
1391
|
+
If you'd rather not display all possible values in a vertical list, you may consider using `slider`. The slider provides easy visual way of picking a value marked by `●` symbol.
|
1381
1392
|
|
1382
|
-
|
1393
|
+
For integers, you can set `:min`(defaults to 0), `:max` and `:step`(defaults to 1) options to configure slider range:
|
1383
1394
|
|
1384
1395
|
```ruby
|
1385
|
-
prompt.slider("Volume", max: 100, step: 5)
|
1396
|
+
prompt.slider("Volume", min: 0, max: 100, step: 5)
|
1386
1397
|
# =>
|
1387
1398
|
# Volume ──────────●────────── 50
|
1388
1399
|
# (Use ←/→ arrow keys, press Enter to select)
|
1389
1400
|
```
|
1390
1401
|
|
1402
|
+
For everything else, you can provide an array of your desired choices:
|
1403
|
+
|
1404
|
+
```ruby
|
1405
|
+
prompt.slider("Letter", ('a'..'z').to_a)
|
1406
|
+
# =>
|
1407
|
+
# Letter ────────────●───────────── m
|
1408
|
+
# (Use ←/→ arrow keys, press Enter to select)
|
1409
|
+
```
|
1410
|
+
|
1391
1411
|
By default the slider is configured to pick middle of the range as a start value, you can change this by using the `:default` option:
|
1392
1412
|
|
1393
1413
|
```ruby
|
@@ -1397,6 +1417,15 @@ prompt.slider("Volume", max: 100, step: 5, default: 75)
|
|
1397
1417
|
# (Use ←/→ arrow keys, press Enter to select)
|
1398
1418
|
```
|
1399
1419
|
|
1420
|
+
You can also select the default value by name:
|
1421
|
+
|
1422
|
+
```ruby
|
1423
|
+
prompt.slider("Letter", ('a'..'z').to_a, default: 'q')
|
1424
|
+
# =>
|
1425
|
+
# Letter ──────────────────●─────── q
|
1426
|
+
# (Use ←/→ arrow keys, press Enter to select)
|
1427
|
+
```
|
1428
|
+
|
1400
1429
|
You can also change the default slider formatting using the `:format`. The value must contain the `:slider` token to show current value and any `sprintf` compatible flag for number display, in our case `%d`:
|
1401
1430
|
|
1402
1431
|
```ruby
|
@@ -1450,13 +1479,25 @@ prompt.slider("What size?") do |range|
|
|
1450
1479
|
range.max 100
|
1451
1480
|
range.step 5
|
1452
1481
|
range.default 75
|
1453
|
-
range.format "|:slider| %d
|
1482
|
+
range.format "|:slider| %d%%"
|
1454
1483
|
end
|
1455
1484
|
# =>
|
1456
1485
|
# Volume |───────────────●──────| 75%
|
1457
1486
|
# (Use ←/→ arrow keys, press Enter to select)
|
1458
1487
|
```
|
1459
1488
|
|
1489
|
+
```ruby
|
1490
|
+
prompt.slider("What letter?") do |range|
|
1491
|
+
range.choices ('a'..'z').to_a
|
1492
|
+
range.format "|:slider| %s"
|
1493
|
+
range.default 'q'
|
1494
|
+
end
|
1495
|
+
# =>
|
1496
|
+
# What letter? |──────────────────●───────| q
|
1497
|
+
# (Use ←/→ arrow keys, press Enter to select)
|
1498
|
+
```
|
1499
|
+
|
1500
|
+
|
1460
1501
|
### 2.11 say
|
1461
1502
|
|
1462
1503
|
To simply print message out to standard output use `say` like so:
|
@@ -1640,7 +1681,7 @@ prompt = TTY::Prompt.new(help_color: notice)
|
|
1640
1681
|
|
1641
1682
|
Or use coloring of your own choice:
|
1642
1683
|
|
1643
|
-
```
|
1684
|
+
```ruby
|
1644
1685
|
prompt = TTY::Prompt.new(help_color: ->(str) { my-color-gem(str) })
|
1645
1686
|
```
|
1646
1687
|
|
@@ -1657,7 +1698,7 @@ Please [see pastel](https://github.com/piotrmurach/pastel#3-supported-colors) fo
|
|
1657
1698
|
By default `InputInterrupt` error will be raised when the user hits the interrupt key(Control-C). However, you can customise this behaviour by passing the `:interrupt` option. The available options are:
|
1658
1699
|
|
1659
1700
|
* `:signal` - sends interrupt signal
|
1660
|
-
* `:exit` -
|
1701
|
+
* `:exit` - exits with status code
|
1661
1702
|
* `:noop` - skips handler
|
1662
1703
|
* custom proc
|
1663
1704
|
|
data/lib/tty/prompt.rb
CHANGED
@@ -388,16 +388,20 @@ module TTY
|
|
388
388
|
# @example
|
389
389
|
# prompt = TTY::Prompt.new
|
390
390
|
# prompt.slider("What size?", min: 32, max: 54, step: 2)
|
391
|
+
# prompt.slider("What size?", [ 'xs', 's', 'm', 'l', 'xl' ])
|
391
392
|
#
|
392
393
|
# @param [String] question
|
393
394
|
# the question to ask
|
394
395
|
#
|
396
|
+
# @param [Array] choices
|
397
|
+
# the choices to display
|
398
|
+
#
|
395
399
|
# @return [String]
|
396
400
|
#
|
397
401
|
# @api public
|
398
|
-
def slider(question, **options, &block)
|
402
|
+
def slider(question, choices = nil, **options, &block)
|
399
403
|
slider = Slider.new(self, **options)
|
400
|
-
slider.call(question, &block)
|
404
|
+
slider.call(question, choices, &block)
|
401
405
|
end
|
402
406
|
|
403
407
|
# Print statement out. If the supplied message ends with a space or
|
data/lib/tty/prompt/choice.rb
CHANGED
@@ -111,9 +111,10 @@ module TTY
|
|
111
111
|
# @api public
|
112
112
|
def ==(other)
|
113
113
|
return false unless other.is_a?(self.class)
|
114
|
+
|
114
115
|
name == other.name &&
|
115
|
-
|
116
|
-
|
116
|
+
value == other.value &&
|
117
|
+
key == other.key
|
117
118
|
end
|
118
119
|
|
119
120
|
# Object string representation
|
@@ -122,7 +123,7 @@ module TTY
|
|
122
123
|
#
|
123
124
|
# @api public
|
124
125
|
def to_s
|
125
|
-
|
126
|
+
name.to_s
|
126
127
|
end
|
127
128
|
end # Choice
|
128
129
|
end # Prompt
|
data/lib/tty/prompt/choices.rb
CHANGED
@@ -62,6 +62,7 @@ module TTY
|
|
62
62
|
# @api public
|
63
63
|
def each(&block)
|
64
64
|
return to_enum unless block_given?
|
65
|
+
|
65
66
|
choices.each(&block)
|
66
67
|
end
|
67
68
|
|
@@ -100,7 +101,7 @@ module TTY
|
|
100
101
|
|
101
102
|
# Find a matching choice
|
102
103
|
#
|
103
|
-
# @
|
104
|
+
# @example
|
104
105
|
# choices.find_by(:name, "small")
|
105
106
|
#
|
106
107
|
# @param [Symbol] attr
|
@@ -38,6 +38,7 @@ module TTY
|
|
38
38
|
# @api public
|
39
39
|
def suffix(value = (not_set = true))
|
40
40
|
return @negative if not_set
|
41
|
+
|
41
42
|
@suffix = value
|
42
43
|
end
|
43
44
|
|
@@ -46,6 +47,7 @@ module TTY
|
|
46
47
|
# @api public
|
47
48
|
def positive(value = (not_set = true))
|
48
49
|
return @positive if not_set
|
50
|
+
|
49
51
|
@positive = value
|
50
52
|
end
|
51
53
|
|
@@ -54,11 +56,13 @@ module TTY
|
|
54
56
|
# @api public
|
55
57
|
def negative(value = (not_set = true))
|
56
58
|
return @negative if not_set
|
59
|
+
|
57
60
|
@negative = value
|
58
61
|
end
|
59
62
|
|
60
63
|
def call(message, &block)
|
61
64
|
return if Utils.blank?(message)
|
65
|
+
|
62
66
|
@message = message
|
63
67
|
block.call(self) if block
|
64
68
|
setup_defaults
|
data/lib/tty/prompt/enum_list.rb
CHANGED
@@ -15,6 +15,9 @@ module TTY
|
|
15
15
|
class EnumList
|
16
16
|
PAGE_HELP = "(Press tab/right or left to reveal more choices)"
|
17
17
|
|
18
|
+
# Checks type of default parameter to be integer
|
19
|
+
INTEGER_MATCHER = /\A[-+]?\d+\Z/.freeze
|
20
|
+
|
18
21
|
# Create instance of EnumList menu.
|
19
22
|
#
|
20
23
|
# @api public
|
@@ -22,11 +25,11 @@ module TTY
|
|
22
25
|
@prompt = prompt
|
23
26
|
@prefix = options.fetch(:prefix) { @prompt.prefix }
|
24
27
|
@enum = options.fetch(:enum) { ")" }
|
25
|
-
@default = options.fetch(:default)
|
28
|
+
@default = options.fetch(:default, nil)
|
26
29
|
@active_color = options.fetch(:active_color) { @prompt.active_color }
|
27
30
|
@help_color = options.fetch(:help_color) { @prompt.help_color }
|
28
31
|
@error_color = options.fetch(:error_color) { @prompt.error_color }
|
29
|
-
@cycle = options.fetch(:cycle
|
32
|
+
@cycle = options.fetch(:cycle, false)
|
30
33
|
@quiet = options.fetch(:quiet) { @prompt.quiet }
|
31
34
|
@symbols = @prompt.symbols.merge(options.fetch(:symbols, {}))
|
32
35
|
@input = nil
|
@@ -49,6 +52,7 @@ module TTY
|
|
49
52
|
# @api public
|
50
53
|
def symbols(new_symbols = (not_set = true))
|
51
54
|
return @symbols if not_set
|
55
|
+
|
52
56
|
@symbols.merge!(new_symbols)
|
53
57
|
end
|
54
58
|
|
@@ -65,7 +69,7 @@ module TTY
|
|
65
69
|
#
|
66
70
|
# @api public
|
67
71
|
def default?
|
68
|
-
|
72
|
+
!@default.to_s.empty?
|
69
73
|
end
|
70
74
|
|
71
75
|
# Set number of items per page
|
@@ -153,6 +157,7 @@ module TTY
|
|
153
157
|
def keypress(event)
|
154
158
|
if %i[backspace delete].include?(event.key.name)
|
155
159
|
return if @input.empty?
|
160
|
+
|
156
161
|
@input.chop!
|
157
162
|
mark_choice_as_active
|
158
163
|
elsif event.value =~ /^\d+$/
|
@@ -195,7 +200,6 @@ module TTY
|
|
195
200
|
|
196
201
|
private
|
197
202
|
|
198
|
-
|
199
203
|
# Find active choice or set to default
|
200
204
|
#
|
201
205
|
# @return [nil]
|
@@ -220,6 +224,8 @@ module TTY
|
|
220
224
|
def validate_defaults
|
221
225
|
msg = if @default.nil? || @default.to_s.empty?
|
222
226
|
"default index must be an integer in range (1 - #{choices.size})"
|
227
|
+
elsif @default.to_s !~ INTEGER_MATCHER
|
228
|
+
validate_default_name
|
223
229
|
elsif @default < 1 || @default > @choices.size
|
224
230
|
"default index #{@default} out of range (1 - #{@choices.size})"
|
225
231
|
elsif choices[@default - 1] && choices[@default - 1].disabled?
|
@@ -229,14 +235,31 @@ module TTY
|
|
229
235
|
raise(ConfigurationError, msg) if msg
|
230
236
|
end
|
231
237
|
|
238
|
+
# Validate default choice name
|
239
|
+
#
|
240
|
+
# @return [String]
|
241
|
+
#
|
242
|
+
# @api private
|
243
|
+
def validate_default_name
|
244
|
+
default_choice = choices.find_by(:name, @default.to_s)
|
245
|
+
if default_choice.nil?
|
246
|
+
"no choice found for the default name: #{@default.inspect}"
|
247
|
+
elsif default_choice.disabled?
|
248
|
+
"default name #{@default.inspect} matches disabled choice"
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
232
252
|
# Setup default option and active selection
|
233
253
|
#
|
234
254
|
# @api private
|
235
255
|
def setup_defaults
|
236
|
-
if
|
237
|
-
@default = (0..choices.length).find {|i| !choices[i].disabled? } + 1
|
256
|
+
if @default.to_s.empty?
|
257
|
+
@default = (0..choices.length).find { |i| !choices[i].disabled? } + 1
|
238
258
|
end
|
239
259
|
validate_defaults
|
260
|
+
if default_choice = choices.find_by(:name, @default)
|
261
|
+
@default = choices.index(default_choice) + 1
|
262
|
+
end
|
240
263
|
mark_choice_as_active
|
241
264
|
end
|
242
265
|
|
@@ -342,6 +365,7 @@ module TTY
|
|
342
365
|
def render_header
|
343
366
|
return "" unless @done
|
344
367
|
return "" unless @active
|
368
|
+
|
345
369
|
selected_item = @choices[@active - 1].name.to_s
|
346
370
|
@prompt.decorate(selected_item, @active_color)
|
347
371
|
end
|
@@ -362,6 +386,7 @@ module TTY
|
|
362
386
|
# @api private
|
363
387
|
def page_help_message
|
364
388
|
return "" unless paginated?
|
389
|
+
|
365
390
|
"\n" + @prompt.decorate(@page_help, @help_color)
|
366
391
|
end
|
367
392
|
|
data/lib/tty/prompt/evaluator.rb
CHANGED
data/lib/tty/prompt/expander.rb
CHANGED
@@ -15,14 +15,17 @@ module TTY
|
|
15
15
|
value: :help
|
16
16
|
}.freeze
|
17
17
|
|
18
|
+
# Names for delete keys
|
19
|
+
DELETE_KEYS = %i[backspace delete].freeze
|
20
|
+
|
18
21
|
# Create instance of Expander
|
19
22
|
#
|
20
23
|
# @api public
|
21
24
|
def initialize(prompt, options = {})
|
22
25
|
@prompt = prompt
|
23
26
|
@prefix = options.fetch(:prefix) { @prompt.prefix }
|
24
|
-
@default = options.fetch(:default
|
25
|
-
@auto_hint = options.fetch(:auto_hint
|
27
|
+
@default = options.fetch(:default, 1)
|
28
|
+
@auto_hint = options.fetch(:auto_hint, false)
|
26
29
|
@active_color = options.fetch(:active_color) { @prompt.active_color }
|
27
30
|
@help_color = options.fetch(:help_color) { @prompt.help_color }
|
28
31
|
@quiet = options.fetch(:quiet) { @prompt.quiet }
|
@@ -75,7 +78,7 @@ module TTY
|
|
75
78
|
#
|
76
79
|
# @api public
|
77
80
|
def keypress(event)
|
78
|
-
if
|
81
|
+
if DELETE_KEYS.include?(event.key.name)
|
79
82
|
@input.chop! unless @input.empty?
|
80
83
|
elsif event.value =~ /^[^\e\n\r]/
|
81
84
|
@input += event.value
|
@@ -101,6 +104,7 @@ module TTY
|
|
101
104
|
# @api public
|
102
105
|
def default(value = (not_set = true))
|
103
106
|
return @default if not_set
|
107
|
+
|
104
108
|
@default = value
|
105
109
|
end
|
106
110
|
|
data/lib/tty/prompt/keypress.rb
CHANGED
@@ -30,6 +30,7 @@ module TTY
|
|
30
30
|
|
31
31
|
def countdown(value = (not_set = true))
|
32
32
|
return @countdown if not_set
|
33
|
+
|
33
34
|
@countdown = value
|
34
35
|
end
|
35
36
|
|
@@ -81,6 +82,7 @@ module TTY
|
|
81
82
|
|
82
83
|
@timer.while_remaining do |remaining|
|
83
84
|
break if @done
|
85
|
+
|
84
86
|
@input = @prompt.read_keypress(nonblock: true)
|
85
87
|
end
|
86
88
|
countdown(0) unless @done
|
data/lib/tty/prompt/list.rb
CHANGED
@@ -16,6 +16,9 @@ module TTY
|
|
16
16
|
# Allowed keys for filter, along with backspace and canc.
|
17
17
|
FILTER_KEYS_MATCHER = /\A([[:alnum:]]|[[:punct:]])\Z/.freeze
|
18
18
|
|
19
|
+
# Checks type of default parameter to be integer
|
20
|
+
INTEGER_MATCHER = /\A\d+\Z/.freeze
|
21
|
+
|
19
22
|
# Create instance of TTY::Prompt::List menu.
|
20
23
|
#
|
21
24
|
# @param Hash options
|
@@ -65,6 +68,7 @@ module TTY
|
|
65
68
|
# @api public
|
66
69
|
def symbols(new_symbols = (not_set = true))
|
67
70
|
return @symbols if not_set
|
71
|
+
|
68
72
|
@symbols.merge!(new_symbols)
|
69
73
|
end
|
70
74
|
|
@@ -255,6 +259,7 @@ module TTY
|
|
255
259
|
value = event.value.to_i
|
256
260
|
return unless (1..choices.count).cover?(value)
|
257
261
|
return if choices[value - 1].disabled?
|
262
|
+
|
258
263
|
@active = value
|
259
264
|
end
|
260
265
|
|
@@ -308,17 +313,19 @@ module TTY
|
|
308
313
|
# When the choice on a page is outside of next page range then
|
309
314
|
# adjust it to the last item, otherwise leave unchanged.
|
310
315
|
def keyright(*)
|
311
|
-
|
312
|
-
|
316
|
+
choices_size = choices.size
|
317
|
+
if (@active + page_size) <= choices_size
|
318
|
+
searchable = ((@active + page_size)..choices_size)
|
313
319
|
@active = search_choice_in(searchable)
|
314
|
-
elsif @active <=
|
320
|
+
elsif @active <= choices_size # last page shorter
|
315
321
|
current = @active % page_size
|
316
|
-
remaining =
|
322
|
+
remaining = choices_size % page_size
|
323
|
+
|
317
324
|
if current.zero? || (remaining > 0 && current > remaining)
|
318
|
-
searchable =
|
325
|
+
searchable = choices_size.downto(0).to_a
|
319
326
|
@active = search_choice_in(searchable)
|
320
327
|
elsif @cycle
|
321
|
-
searchable = ((current.zero? ? page_size : current)..
|
328
|
+
searchable = ((current.zero? ? page_size : current)..choices_size)
|
322
329
|
@active = search_choice_in(searchable)
|
323
330
|
end
|
324
331
|
end
|
@@ -330,10 +337,10 @@ module TTY
|
|
330
337
|
|
331
338
|
def keyleft(*)
|
332
339
|
if (@active - page_size) > 0
|
333
|
-
searchable = ((@active - page_size)..choices.
|
340
|
+
searchable = ((@active - page_size)..choices.size)
|
334
341
|
@active = search_choice_in(searchable)
|
335
342
|
elsif @cycle
|
336
|
-
searchable =
|
343
|
+
searchable = choices.size.downto(1).to_a
|
337
344
|
@active = search_choice_in(searchable)
|
338
345
|
end
|
339
346
|
@paging_changed = !@by_page
|
@@ -375,14 +382,19 @@ module TTY
|
|
375
382
|
|
376
383
|
# Setup default option and active selection
|
377
384
|
#
|
385
|
+
# @return [Integer]
|
386
|
+
#
|
378
387
|
# @api private
|
379
388
|
def setup_defaults
|
380
389
|
validate_defaults
|
381
390
|
|
382
|
-
if
|
391
|
+
if @default.empty?
|
392
|
+
# no default, pick the first non-disabled choice
|
393
|
+
@active = choices.index { |choice| !choice.disabled? } + 1
|
394
|
+
elsif @default.first.to_s =~ INTEGER_MATCHER
|
383
395
|
@active = @default.first
|
384
|
-
|
385
|
-
@active =
|
396
|
+
elsif default_choice = choices.find_by(:name, @default.first)
|
397
|
+
@active = choices.index(default_choice) + 1
|
386
398
|
end
|
387
399
|
end
|
388
400
|
|
@@ -397,16 +409,35 @@ module TTY
|
|
397
409
|
@default.each do |d|
|
398
410
|
msg = if d.nil? || d.to_s.empty?
|
399
411
|
"default index must be an integer in range (1 - #{choices.size})"
|
412
|
+
elsif d.to_s !~ INTEGER_MATCHER
|
413
|
+
validate_default_name(d)
|
400
414
|
elsif d < 1 || d > choices.size
|
401
415
|
"default index `#{d}` out of range (1 - #{choices.size})"
|
402
|
-
elsif choices[d - 1] &&
|
403
|
-
"default index `#{d}` matches disabled choice
|
416
|
+
elsif (dflt_choice = choices[d - 1]) && dflt_choice.disabled?
|
417
|
+
"default index `#{d}` matches disabled choice"
|
404
418
|
end
|
405
419
|
|
406
420
|
raise(ConfigurationError, msg) if msg
|
407
421
|
end
|
408
422
|
end
|
409
423
|
|
424
|
+
# Validate default choice name
|
425
|
+
#
|
426
|
+
# @param [String] name
|
427
|
+
# the name to verify
|
428
|
+
#
|
429
|
+
# @return [String]
|
430
|
+
#
|
431
|
+
# @api private
|
432
|
+
def validate_default_name(name)
|
433
|
+
default_choice = choices.find_by(:name, name.to_s)
|
434
|
+
if default_choice.nil?
|
435
|
+
"no choice found for the default name: #{name.inspect}"
|
436
|
+
elsif default_choice.disabled?
|
437
|
+
"default name #{name.inspect} matches disabled choice"
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
410
441
|
# Render a selection list.
|
411
442
|
#
|
412
443
|
# By default the result is printed out.
|
@@ -5,6 +5,9 @@ require_relative "question"
|
|
5
5
|
module TTY
|
6
6
|
class Prompt
|
7
7
|
class MaskQuestion < Question
|
8
|
+
# Names for delete keys
|
9
|
+
DELETE_KEYS = %i[backspace delete].freeze
|
10
|
+
|
8
11
|
# Create masked question
|
9
12
|
#
|
10
13
|
# @param [Hash] options
|
@@ -27,19 +30,20 @@ module TTY
|
|
27
30
|
# @api public
|
28
31
|
def mask(char = (not_set = true))
|
29
32
|
return @mask if not_set
|
33
|
+
|
30
34
|
@mask = char
|
31
35
|
end
|
32
36
|
|
33
|
-
def keyreturn(
|
37
|
+
def keyreturn(_event)
|
34
38
|
@done_masked = true
|
35
39
|
end
|
36
40
|
|
37
|
-
def keyenter(
|
41
|
+
def keyenter(_event)
|
38
42
|
@done_masked = true
|
39
43
|
end
|
40
44
|
|
41
45
|
def keypress(event)
|
42
|
-
if
|
46
|
+
if DELETE_KEYS.include?(event.key.name)
|
43
47
|
@input.chop! unless @input.empty?
|
44
48
|
elsif event.value =~ /^[^\e\n\r]/
|
45
49
|
@input += event.value
|
@@ -60,6 +60,7 @@ module TTY
|
|
60
60
|
@selected.delete_at(@active - 1)
|
61
61
|
else
|
62
62
|
return if @max && @selected.size >= @max
|
63
|
+
|
63
64
|
@selected.insert(@active - 1, active_choice)
|
64
65
|
end
|
65
66
|
end
|
@@ -69,6 +70,7 @@ module TTY
|
|
69
70
|
# @api private
|
70
71
|
def keyctrl_a(*)
|
71
72
|
return if @max && @max < choices.size
|
73
|
+
|
72
74
|
@selected = SelectedChoices.new(choices.enabled, choices.enabled_indexes)
|
73
75
|
end
|
74
76
|
|
@@ -77,6 +79,7 @@ module TTY
|
|
77
79
|
# @api private
|
78
80
|
def keyctrl_r(*)
|
79
81
|
return if @max && @max < choices.size
|
82
|
+
|
80
83
|
indexes = choices.each_with_index.reduce([]) do |acc, (choice, idx)|
|
81
84
|
acc << idx if !choice.disabled? && !@selected.include?(choice)
|
82
85
|
acc
|
@@ -92,14 +95,23 @@ module TTY
|
|
92
95
|
def setup_defaults
|
93
96
|
validate_defaults
|
94
97
|
# At this stage, @choices matches all the visible choices.
|
95
|
-
default_indexes = @default.map
|
98
|
+
default_indexes = @default.map do |d|
|
99
|
+
if d.to_s =~ INTEGER_MATCHER
|
100
|
+
d - 1
|
101
|
+
else
|
102
|
+
choices.index(choices.find_by(:name, d.to_s))
|
103
|
+
end
|
104
|
+
end
|
96
105
|
@selected = SelectedChoices.new(@choices.values_at(*default_indexes),
|
97
106
|
default_indexes)
|
98
107
|
|
99
|
-
if
|
108
|
+
if @default.empty?
|
109
|
+
# no default, pick the first non-disabled choice
|
110
|
+
@active = choices.index { |choice| !choice.disabled? } + 1
|
111
|
+
elsif @default.last.to_s =~ INTEGER_MATCHER
|
100
112
|
@active = @default.last
|
101
|
-
|
102
|
-
@active =
|
113
|
+
elsif default_choice = choices.find_by(:name, @default.last.to_s)
|
114
|
+
@active = choices.index(default_choice) + 1
|
103
115
|
end
|
104
116
|
end
|
105
117
|
|
data/lib/tty/prompt/multiline.rb
CHANGED
@@ -25,6 +25,7 @@ module TTY
|
|
25
25
|
# @api public
|
26
26
|
def help(value = (not_set = true))
|
27
27
|
return @help if not_set
|
28
|
+
|
28
29
|
@help = value
|
29
30
|
end
|
30
31
|
|
@@ -42,7 +43,7 @@ module TTY
|
|
42
43
|
if !echo?
|
43
44
|
header
|
44
45
|
elsif @done
|
45
|
-
header << @prompt.decorate(
|
46
|
+
header << @prompt.decorate(@input.to_s, @active_color)
|
46
47
|
elsif @first_render
|
47
48
|
header << @prompt.decorate(help, @help_color)
|
48
49
|
@first_render = false
|
data/lib/tty/prompt/question.rb
CHANGED
@@ -55,7 +55,7 @@ module TTY
|
|
55
55
|
@error_color = options.fetch(:error_color) { :red }
|
56
56
|
@value = options.fetch(:value) { UndefinedSetting }
|
57
57
|
@quiet = options.fetch(:quiet) { @prompt.quiet }
|
58
|
-
@messages = Utils.deep_copy(options.fetch(:messages) { {
|
58
|
+
@messages = Utils.deep_copy(options.fetch(:messages) { {} })
|
59
59
|
@done = false
|
60
60
|
@first_render = true
|
61
61
|
@input = nil
|
@@ -170,7 +170,7 @@ module TTY
|
|
170
170
|
#
|
171
171
|
# @api private
|
172
172
|
def read_input(question)
|
173
|
-
options = {echo: echo}
|
173
|
+
options = { echo: echo }
|
174
174
|
if value? && @first_render
|
175
175
|
options[:value] = @value
|
176
176
|
@first_render = false
|
@@ -257,6 +257,7 @@ module TTY
|
|
257
257
|
# @api public
|
258
258
|
def default(value = (not_set = true))
|
259
259
|
return @default if not_set
|
260
|
+
|
260
261
|
@default = value
|
261
262
|
end
|
262
263
|
|
@@ -277,9 +278,10 @@ module TTY
|
|
277
278
|
def required(value = (not_set = true), message = nil)
|
278
279
|
messages[:required?] = message if message
|
279
280
|
return @required if not_set
|
281
|
+
|
280
282
|
@required = value
|
281
283
|
end
|
282
|
-
|
284
|
+
alias required? required
|
283
285
|
|
284
286
|
# Set validation rule for an argument
|
285
287
|
#
|
@@ -298,6 +300,7 @@ module TTY
|
|
298
300
|
# @api public
|
299
301
|
def value(val)
|
300
302
|
return @value if val.nil?
|
303
|
+
|
301
304
|
@value = val
|
302
305
|
end
|
303
306
|
|
@@ -327,18 +330,20 @@ module TTY
|
|
327
330
|
# @api public
|
328
331
|
def echo(value = nil)
|
329
332
|
return @echo if value.nil?
|
333
|
+
|
330
334
|
@echo = value
|
331
335
|
end
|
332
|
-
|
336
|
+
alias echo? echo
|
333
337
|
|
334
338
|
# Turn raw mode on or off. This enables character-based input.
|
335
339
|
#
|
336
340
|
# @api public
|
337
341
|
def raw(value = nil)
|
338
342
|
return @raw if value.nil?
|
343
|
+
|
339
344
|
@raw = value
|
340
345
|
end
|
341
|
-
|
346
|
+
alias raw? raw
|
342
347
|
|
343
348
|
# Set expected range of values
|
344
349
|
#
|
@@ -351,6 +356,7 @@ module TTY
|
|
351
356
|
@in = Converters.convert(:range, @in)
|
352
357
|
end
|
353
358
|
return @in if not_set
|
359
|
+
|
354
360
|
@in = Converters.convert(:range, value)
|
355
361
|
end
|
356
362
|
|
@@ -42,7 +42,7 @@ module TTY
|
|
42
42
|
(question.in? && question.in.include?(cast(value)))
|
43
43
|
[value]
|
44
44
|
else
|
45
|
-
tokens = {value: value, in: question.in}
|
45
|
+
tokens = { value: value, in: question.in }
|
46
46
|
[value, question.message_for(:range?, tokens)]
|
47
47
|
end
|
48
48
|
end
|
@@ -56,7 +56,7 @@ module TTY
|
|
56
56
|
Validation.new(question.validation).call(value))
|
57
57
|
[value]
|
58
58
|
else
|
59
|
-
tokens = {valid: question.validation.inspect}
|
59
|
+
tokens = { valid: question.validation.inspect }
|
60
60
|
[value, question.message_for(:valid?, tokens)]
|
61
61
|
end
|
62
62
|
end
|
@@ -89,7 +89,7 @@ module TTY
|
|
89
89
|
if question.convert? && !Utils.blank?(value)
|
90
90
|
result = question.convert_result(value)
|
91
91
|
if result == Const::Undefined
|
92
|
-
tokens = {value: value, type: question.convert}
|
92
|
+
tokens = { value: value, type: question.convert }
|
93
93
|
[value, question.message_for(:convert?, tokens)]
|
94
94
|
else
|
95
95
|
[result]
|
@@ -49,6 +49,7 @@ module TTY
|
|
49
49
|
# @api public
|
50
50
|
def self.letter_case(mod, value)
|
51
51
|
return value unless value.is_a?(String)
|
52
|
+
|
52
53
|
case mod
|
53
54
|
when :up, :upcase, :uppercase
|
54
55
|
value.upcase
|
@@ -75,15 +76,16 @@ module TTY
|
|
75
76
|
# @api public
|
76
77
|
def self.whitespace(mod, value)
|
77
78
|
return value unless value.is_a?(String)
|
79
|
+
|
78
80
|
case mod
|
79
81
|
when :trim, :strip
|
80
82
|
value.strip
|
81
83
|
when :chomp
|
82
84
|
value.chomp
|
83
85
|
when :collapse
|
84
|
-
value.gsub(/\s+/,
|
86
|
+
value.gsub(/\s+/, " ")
|
85
87
|
when :remove
|
86
|
-
value.gsub(/\s+/,
|
88
|
+
value.gsub(/\s+/, "")
|
87
89
|
else
|
88
90
|
value
|
89
91
|
end
|
data/lib/tty/prompt/slider.rb
CHANGED
@@ -9,7 +9,7 @@ module TTY
|
|
9
9
|
class Slider
|
10
10
|
HELP = "(Use %s arrow keys, press Enter to select)"
|
11
11
|
|
12
|
-
FORMAT = ":slider %
|
12
|
+
FORMAT = ":slider %s"
|
13
13
|
|
14
14
|
# Initailize a Slider
|
15
15
|
#
|
@@ -26,9 +26,10 @@ module TTY
|
|
26
26
|
def initialize(prompt, **options)
|
27
27
|
@prompt = prompt
|
28
28
|
@prefix = options.fetch(:prefix) { @prompt.prefix }
|
29
|
-
@
|
30
|
-
@
|
31
|
-
@
|
29
|
+
@choices = Choices.new
|
30
|
+
@min = options.fetch(:min, 0)
|
31
|
+
@max = options.fetch(:max, 10)
|
32
|
+
@step = options.fetch(:step, 1)
|
32
33
|
@default = options[:default]
|
33
34
|
@active_color = options.fetch(:active_color) { @prompt.active_color }
|
34
35
|
@help_color = options.fetch(:help_color) { @prompt.help_color }
|
@@ -60,9 +61,14 @@ module TTY
|
|
60
61
|
# @api private
|
61
62
|
def initial
|
62
63
|
if @default.nil?
|
63
|
-
|
64
|
+
# no default - choose the middle option
|
65
|
+
choices.size / 2
|
66
|
+
elsif default_choice = choices.find_by(:name, @default)
|
67
|
+
# found a Choice by name - use it
|
68
|
+
choices.index(default_choice)
|
64
69
|
else
|
65
|
-
|
70
|
+
# default is the index number
|
71
|
+
@default - 1
|
66
72
|
end
|
67
73
|
end
|
68
74
|
|
@@ -94,15 +100,6 @@ module TTY
|
|
94
100
|
@show_help = value
|
95
101
|
end
|
96
102
|
|
97
|
-
# Range of numbers to render
|
98
|
-
#
|
99
|
-
# @return [Array[Integer]]
|
100
|
-
#
|
101
|
-
# @api private
|
102
|
-
def range
|
103
|
-
(@min..@max).step(@step).to_a
|
104
|
-
end
|
105
|
-
|
106
103
|
# @api public
|
107
104
|
def default(value)
|
108
105
|
@default = value
|
@@ -123,6 +120,32 @@ module TTY
|
|
123
120
|
@step = value
|
124
121
|
end
|
125
122
|
|
123
|
+
# Add a single choice
|
124
|
+
#
|
125
|
+
# @api public
|
126
|
+
def choice(*value, &block)
|
127
|
+
if block
|
128
|
+
@choices << (value << block)
|
129
|
+
else
|
130
|
+
@choices << value
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Add multiple choices
|
135
|
+
#
|
136
|
+
# @param [Array[Object]] values
|
137
|
+
# the values to add as choices
|
138
|
+
#
|
139
|
+
# @api public
|
140
|
+
def choices(values = (not_set = true))
|
141
|
+
if not_set
|
142
|
+
@choices
|
143
|
+
else
|
144
|
+
values.each { |val| @choices << val }
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# @api public
|
126
149
|
def format(value)
|
127
150
|
@format = value
|
128
151
|
end
|
@@ -140,9 +163,14 @@ module TTY
|
|
140
163
|
# the question to ask
|
141
164
|
#
|
142
165
|
# @apu public
|
143
|
-
def call(question, &block)
|
166
|
+
def call(question, possibilities = nil, &block)
|
144
167
|
@question = question
|
168
|
+
choices(possibilities) if possibilities
|
145
169
|
block.call(self) if block
|
170
|
+
# set up a Choices collection for min, max, step
|
171
|
+
# if no possibilities were supplied
|
172
|
+
choices((@min..@max).step(@step).to_a) if @choices.empty?
|
173
|
+
|
146
174
|
@active = initial
|
147
175
|
@prompt.subscribe(self) do
|
148
176
|
render
|
@@ -155,7 +183,7 @@ module TTY
|
|
155
183
|
alias keydown keyleft
|
156
184
|
|
157
185
|
def keyright(*)
|
158
|
-
@active += 1 if (@active + 1) <
|
186
|
+
@active += 1 if (@active + 1) < choices.size
|
159
187
|
end
|
160
188
|
alias keyup keyright
|
161
189
|
|
@@ -208,11 +236,11 @@ module TTY
|
|
208
236
|
@prompt.print(@prompt.clear_lines(lines))
|
209
237
|
end
|
210
238
|
|
211
|
-
# @return [Integer]
|
239
|
+
# @return [Integer, String]
|
212
240
|
#
|
213
241
|
# @api private
|
214
242
|
def answer
|
215
|
-
|
243
|
+
choices[@active].value
|
216
244
|
end
|
217
245
|
|
218
246
|
# Render question with the slider
|
@@ -223,7 +251,7 @@ module TTY
|
|
223
251
|
def render_question
|
224
252
|
header = ["#{@prefix}#{@question} "]
|
225
253
|
if @done
|
226
|
-
header << @prompt.decorate(
|
254
|
+
header << @prompt.decorate(choices[@active].to_s, @active_color)
|
227
255
|
header << "\n"
|
228
256
|
else
|
229
257
|
header << render_slider
|
@@ -244,8 +272,8 @@ module TTY
|
|
244
272
|
def render_slider
|
245
273
|
slider = (@symbols[:line] * @active) +
|
246
274
|
@prompt.decorate(@symbols[:bullet], @active_color) +
|
247
|
-
(@symbols[:line] * (
|
248
|
-
value =
|
275
|
+
(@symbols[:line] * (choices.size - @active - 1))
|
276
|
+
value = choices[@active].name
|
249
277
|
case @format
|
250
278
|
when Proc
|
251
279
|
@format.call(slider, value)
|
data/lib/tty/prompt/test.rb
CHANGED
@@ -19,7 +19,7 @@ module TTY
|
|
19
19
|
|
20
20
|
class Test < TTY::Prompt
|
21
21
|
def initialize(**options)
|
22
|
-
@input
|
22
|
+
@input = StringIO.new
|
23
23
|
@input.extend(StringIOExtensions)
|
24
24
|
@output = StringIO.new
|
25
25
|
|
@@ -27,7 +27,7 @@ module TTY
|
|
27
27
|
input: @input,
|
28
28
|
output: @output,
|
29
29
|
env: { "TTY_TEST" => true },
|
30
|
-
enable_color: options.fetch(:enable_color
|
30
|
+
enable_color: options.fetch(:enable_color, true)
|
31
31
|
})
|
32
32
|
super(**options)
|
33
33
|
end
|
data/lib/tty/prompt/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tty-prompt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.23.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Murach
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-12-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pastel
|