tty-prompt 0.22.0 → 0.23.0
Sign up to get free protection for your applications and to get access to all the features.
- 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](https://badges.gitter.im/Join%20Chat.svg)][gitter]
|
6
6
|
|
7
7
|
[![Gem Version](https://badge.fury.io/rb/tty-prompt.svg)][gem]
|
8
|
-
[![
|
8
|
+
[![Actions CI](https://github.com/piotrmurach/tty-prompt/workflows/CI/badge.svg?branch=master)][gh_actions_ci]
|
9
9
|
[![Build status](https://ci.appveyor.com/api/projects/status/4cguoiah5dprbq7n?svg=true)][appveyor]
|
10
10
|
[![Code Climate](https://codeclimate.com/github/piotrmurach/tty-prompt/badges/gpa.svg)][codeclimate]
|
11
11
|
[![Coverage Status](https://coveralls.io/repos/github/piotrmurach/tty-prompt/badge.svg)][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
|