tty-prompt 0.8.0 → 0.9.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 +12 -0
- data/README.md +66 -6
- data/appveyor.yml +23 -0
- data/examples/enum_paged.rb +9 -0
- data/examples/select_paginated.rb +9 -0
- data/lib/tty-prompt.rb +2 -0
- data/lib/tty/prompt/enum_list.rb +127 -28
- data/lib/tty/prompt/enum_paginator.rb +54 -0
- data/lib/tty/prompt/list.rb +55 -9
- data/lib/tty/prompt/multi_list.rb +3 -3
- data/lib/tty/prompt/paginator.rb +88 -0
- data/lib/tty/prompt/reader.rb +15 -35
- data/lib/tty/prompt/version.rb +1 -1
- data/spec/unit/enum_paginator_spec.rb +49 -0
- data/spec/unit/enum_select_spec.rb +161 -7
- data/spec/unit/multi_select_spec.rb +41 -0
- data/spec/unit/paginator_spec.rb +47 -0
- data/spec/unit/reader/read_keypress_spec.rb +10 -0
- data/spec/unit/reader/read_line_spec.rb +9 -2
- data/spec/unit/reader/read_multiline_spec.rb +8 -0
- data/spec/unit/select_spec.rb +43 -2
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ef2f5ff49f413f853a8cb33f8894189fb36f728
|
4
|
+
data.tar.gz: cbcd8a42cfefbfbaad8d2028fc5847ce55a20443
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b6e8c1ef4460ce0e6ac1ce17d018bd737d98290163293b5d229b7d65cc38c8656784ffbd2b3e13c275f672f145ba22cbe31e74302de0dc0f757d7605f6d22971
|
7
|
+
data.tar.gz: 029244b6acd770bc6ba0836bf85f01f12d3ec80523bd43a5532826516a80ee44937292408f5e12a7657058db8466a0ec29aed9c5054adf9afd65d09e63816dd5
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## [v0.9.0] - 2016-12-20
|
4
|
+
|
5
|
+
### Added
|
6
|
+
* Add ability to paginate choices list for #select, #multi_select & #enum_select
|
7
|
+
with :per_page, :page_info and :default options
|
8
|
+
* Add ability to switch through options in #select & #multi_select using the tab key
|
9
|
+
|
10
|
+
### Fixed
|
11
|
+
* Fix readers to accept multibyte characters reported by Jaehyun Shin(@keepcosmos)
|
12
|
+
|
3
13
|
## [v0.8.0] - 2016-11-29
|
4
14
|
|
5
15
|
### Added
|
@@ -114,6 +124,8 @@
|
|
114
124
|
|
115
125
|
* Initial implementation and release
|
116
126
|
|
127
|
+
[v0.9.0]: https://github.com/piotrmurach/tty-prompt/compare/v0.8.0...v0.9.0
|
128
|
+
[v0.8.0]: https://github.com/piotrmurach/tty-prompt/compare/v0.7.1...v0.8.0
|
117
129
|
[v0.7.1]: https://github.com/piotrmurach/tty-prompt/compare/v0.7.0...v0.7.1
|
118
130
|
[v0.7.0]: https://github.com/piotrmurach/tty-prompt/compare/v0.6.0...v0.7.0
|
119
131
|
[v0.6.0]: https://github.com/piotrmurach/tty-prompt/compare/v0.5.0...v0.6.0
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# TTY::Prompt [![Gitter](https://badges.gitter.im/Join%20Chat.svg)][gitter]
|
2
2
|
[![Gem Version](https://badge.fury.io/rb/tty-prompt.svg)][gem]
|
3
3
|
[![Build Status](https://secure.travis-ci.org/piotrmurach/tty-prompt.svg?branch=master)][travis]
|
4
|
+
[![Build status](https://ci.appveyor.com/api/projects/status/4cguoiah5dprbq7n?svg=true)][appveyor]
|
4
5
|
[![Code Climate](https://codeclimate.com/github/piotrmurach/tty-prompt/badges/gpa.svg)][codeclimate]
|
5
6
|
[![Coverage Status](https://coveralls.io/repos/github/piotrmurach/tty-prompt/badge.svg)][coverage]
|
6
7
|
[![Inline docs](http://inch-ci.org/github/piotrmurach/tty-prompt.svg?branch=master)][inchpages]
|
@@ -8,6 +9,7 @@
|
|
8
9
|
[gitter]: https://gitter.im/piotrmurach/tty
|
9
10
|
[gem]: http://badge.fury.io/rb/tty-prompt
|
10
11
|
[travis]: http://travis-ci.org/piotrmurach/tty-prompt
|
12
|
+
[appveyor]: https://ci.appveyor.com/project/piotrmurach/tty-prompt
|
11
13
|
[codeclimate]: https://codeclimate.com/github/piotrmurach/tty-prompt
|
12
14
|
[coverage]: https://coveralls.io/github/piotrmurach/tty-prompt
|
13
15
|
[inchpages]: http://inch-ci.org/github/piotrmurach/tty-prompt
|
@@ -21,6 +23,8 @@
|
|
21
23
|
* Number of prompt types for gathering user input
|
22
24
|
* A robust API for validating complex inputs
|
23
25
|
* User friendly error feedback
|
26
|
+
* Intuitive DSL for creating complex menus
|
27
|
+
* Ability to page long menus
|
24
28
|
|
25
29
|
## Installation
|
26
30
|
|
@@ -60,9 +64,10 @@ Or install it yourself as:
|
|
60
64
|
* [2.4 multiline](#24-multiline)
|
61
65
|
* [2.5 mask](#25-mask)
|
62
66
|
* [2.6 yes?/no?](#26-yesno)
|
63
|
-
* [2.7
|
64
|
-
* [2.7.1
|
65
|
-
* [2.7.2
|
67
|
+
* [2.7 menu](#27-menu)
|
68
|
+
* [2.7.1 select](#271-select)
|
69
|
+
* [2.7.2 multi_select](#272-multi_select)
|
70
|
+
* [2.7.3 enum_select](#273-enum_select)
|
66
71
|
* [2.8 expand](#28-expand)
|
67
72
|
* [2.9 collect](#29-collect)
|
68
73
|
* [2.10 suggest](#210-suggest)
|
@@ -488,7 +493,9 @@ prompt.no?('Do you hate Ruby?')
|
|
488
493
|
|
489
494
|
Similarly to `yes?` method, you can supply the same options to customize the question.
|
490
495
|
|
491
|
-
### 2.7
|
496
|
+
### 2.7 menu
|
497
|
+
|
498
|
+
### 2.7.1 select
|
492
499
|
|
493
500
|
For asking questions involving list of options use `select` method by passing the question and possible choices:
|
494
501
|
|
@@ -584,7 +591,31 @@ prompt.select("Choose your destiny?", choices, help: "(Bash keyboard)", marker:
|
|
584
591
|
# Jax
|
585
592
|
```
|
586
593
|
|
587
|
-
|
594
|
+
By default the menu is paginated if selection grows beyond `6` items. To change this setting use `:per_page` configuration.
|
595
|
+
|
596
|
+
```ruby
|
597
|
+
letters = ('A'..'Z').to_a
|
598
|
+
prompt.select("Choose your letter?", letters, per_page: 4)
|
599
|
+
# =>
|
600
|
+
# Which letter? (Use arrow keys, press Enter to select)
|
601
|
+
# ‣ A
|
602
|
+
# B
|
603
|
+
# C
|
604
|
+
# D
|
605
|
+
# (Move up or down to reveal more choices)
|
606
|
+
```
|
607
|
+
|
608
|
+
You can also customise page navigation text using `:page_help` option:
|
609
|
+
```ruby
|
610
|
+
letters = ('A'..'Z').to_a
|
611
|
+
prompt.select("Choose your letter?") do |menu|
|
612
|
+
menu.per_page 4
|
613
|
+
menu.page_help '(Wiggle thy finger up or down to see more)'
|
614
|
+
menu.choices letters, per_page: 4)
|
615
|
+
end
|
616
|
+
```
|
617
|
+
|
618
|
+
### 2.7.2 multi_select
|
588
619
|
|
589
620
|
For asking questions involving multiple selection list use `multi_select` method by passing the question and possible choices:
|
590
621
|
|
@@ -685,7 +716,21 @@ prompt.multi_select("Select drinks?", choices, help: 'Press beer can against key
|
|
685
716
|
# ⬡ bourbon
|
686
717
|
```
|
687
718
|
|
688
|
-
|
719
|
+
By default the menu is paginated if selection grows beyond `6` items. To change this setting use `:per_page` configuration.
|
720
|
+
|
721
|
+
```ruby
|
722
|
+
letters = ('A'..'Z').to_a
|
723
|
+
prompt.multi_select("Choose your letter?", letters, per_page: 4)
|
724
|
+
# =>
|
725
|
+
# Which letter? (Use arrow keys, press Space to select and Enter to finish)
|
726
|
+
# ‣ ⬡ A
|
727
|
+
# ⬡ B
|
728
|
+
# ⬡ C
|
729
|
+
# ⬡ D
|
730
|
+
# (Move up or down to reveal more choices)
|
731
|
+
```
|
732
|
+
|
733
|
+
### 2.7.3 enum_select
|
689
734
|
|
690
735
|
In order to ask for standard selection from indexed list you can use `enum_select` and pass question together with possible choices:
|
691
736
|
|
@@ -744,6 +789,21 @@ end
|
|
744
789
|
# Select an editor? /usr/bin/vim
|
745
790
|
```
|
746
791
|
|
792
|
+
By default the menu is paginated if selection grows beyond `6` items. To change this setting use `:per_page` configuration.
|
793
|
+
|
794
|
+
```ruby
|
795
|
+
letters = ('A'..'Z').to_a
|
796
|
+
prompt.enum_select("Choose your letter?", letters, per_page: 4)
|
797
|
+
# =>
|
798
|
+
# Which letter?
|
799
|
+
# 1) A
|
800
|
+
# 2) B
|
801
|
+
# 3) C
|
802
|
+
# 4) D
|
803
|
+
# Choose 1-26 [1]:
|
804
|
+
# (Press tab/right or left to reveal more choices)
|
805
|
+
```
|
806
|
+
|
747
807
|
### 2.8 expand
|
748
808
|
|
749
809
|
The `expand` provides a compact way to ask a question with many options.
|
data/appveyor.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
---
|
2
|
+
install:
|
3
|
+
- SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
|
4
|
+
- ruby --version
|
5
|
+
- gem --version
|
6
|
+
- bundle install
|
7
|
+
build: off
|
8
|
+
test_script:
|
9
|
+
- bundle exec rake ci
|
10
|
+
environment:
|
11
|
+
matrix:
|
12
|
+
- ruby_version: "193"
|
13
|
+
- ruby_version: "200"
|
14
|
+
- ruby_version: "200-x64"
|
15
|
+
- ruby_version: "21"
|
16
|
+
- ruby_version: "21-x64"
|
17
|
+
- ruby_version: "22"
|
18
|
+
- ruby_version: "22-x64"
|
19
|
+
- ruby_version: "23"
|
20
|
+
- ruby_version: "23-x64"
|
21
|
+
matrix:
|
22
|
+
allow_failures:
|
23
|
+
- ruby_version: "193"
|
data/lib/tty-prompt.rb
CHANGED
@@ -20,6 +20,8 @@ require 'tty/prompt/slider'
|
|
20
20
|
require 'tty/prompt/statement'
|
21
21
|
require 'tty/prompt/suggestion'
|
22
22
|
require 'tty/prompt/answers_collector'
|
23
|
+
require 'tty/prompt/paginator'
|
24
|
+
require 'tty/prompt/enum_paginator'
|
23
25
|
require 'tty/prompt/symbols'
|
24
26
|
require 'tty/prompt/test'
|
25
27
|
require 'tty/prompt/utils'
|
data/lib/tty/prompt/enum_list.rb
CHANGED
@@ -7,6 +7,8 @@ module TTY
|
|
7
7
|
#
|
8
8
|
# @api private
|
9
9
|
class EnumList
|
10
|
+
PAGE_HELP = '(Press tab/right or left to reveal more choices)'.freeze
|
11
|
+
|
10
12
|
# Create instance of EnumList menu.
|
11
13
|
#
|
12
14
|
# @api public
|
@@ -18,10 +20,16 @@ module TTY
|
|
18
20
|
@active_color = options.fetch(:active_color) { @prompt.active_color }
|
19
21
|
@help_color = options.fetch(:help_color) { @prompt.help_color }
|
20
22
|
@error_color = options.fetch(:error_color) { @prompt.error_color }
|
23
|
+
@input = nil
|
21
24
|
@done = false
|
25
|
+
@first_render = true
|
22
26
|
@failure = false
|
23
27
|
@active = @default
|
24
28
|
@choices = Choices.new
|
29
|
+
@per_page = options[:per_page]
|
30
|
+
@page_help = options[:page_help] || PAGE_HELP
|
31
|
+
@paginator = EnumPaginator.new
|
32
|
+
@page_active = @default
|
25
33
|
|
26
34
|
@prompt.subscribe(self)
|
27
35
|
end
|
@@ -33,6 +41,33 @@ module TTY
|
|
33
41
|
@default = default
|
34
42
|
end
|
35
43
|
|
44
|
+
# Set number of items per page
|
45
|
+
#
|
46
|
+
# @api public
|
47
|
+
def per_page(value)
|
48
|
+
@per_page = value
|
49
|
+
end
|
50
|
+
|
51
|
+
def page_size
|
52
|
+
(@per_page || Paginator::DEFAULT_PAGE_SIZE)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Check if list is paginated
|
56
|
+
#
|
57
|
+
# @return [Boolean]
|
58
|
+
#
|
59
|
+
# @api private
|
60
|
+
def paginated?
|
61
|
+
@choices.size >= page_size
|
62
|
+
end
|
63
|
+
|
64
|
+
# @param [String] text
|
65
|
+
# the help text to display per page
|
66
|
+
# @api pbulic
|
67
|
+
def page_help(text)
|
68
|
+
@page_help = text
|
69
|
+
end
|
70
|
+
|
36
71
|
# Set selecting active index using number pad
|
37
72
|
#
|
38
73
|
# @api public
|
@@ -70,14 +105,15 @@ module TTY
|
|
70
105
|
def call(question, possibilities, &block)
|
71
106
|
choices(possibilities)
|
72
107
|
@question = question
|
73
|
-
block
|
108
|
+
block[self] if block
|
74
109
|
setup_defaults
|
75
110
|
render
|
76
111
|
end
|
77
112
|
|
78
113
|
def keypress(event)
|
79
114
|
if [:backspace, :delete].include?(event.key.name)
|
80
|
-
|
115
|
+
return if @input.empty?
|
116
|
+
@input.chop!
|
81
117
|
mark_choice_as_active
|
82
118
|
elsif event.value =~ /^\d+$/
|
83
119
|
@input += event.value
|
@@ -94,24 +130,39 @@ module TTY
|
|
94
130
|
@failure = true
|
95
131
|
end
|
96
132
|
end
|
97
|
-
|
133
|
+
alias keyenter keyreturn
|
98
134
|
|
99
|
-
|
135
|
+
def keyright(*)
|
136
|
+
if (@page_active + page_size) <= @choices.size
|
137
|
+
@page_active += page_size
|
138
|
+
else
|
139
|
+
@page_active = 1
|
140
|
+
end
|
141
|
+
end
|
142
|
+
alias keytab keyright
|
100
143
|
|
101
|
-
def
|
102
|
-
if
|
103
|
-
@
|
144
|
+
def keyleft(*)
|
145
|
+
if (@page_active - page_size) >= 0
|
146
|
+
@page_active -= page_size
|
104
147
|
else
|
105
|
-
@
|
148
|
+
@page_active = @choices.size - 1
|
106
149
|
end
|
107
150
|
end
|
108
151
|
|
109
|
-
|
152
|
+
private
|
153
|
+
|
154
|
+
# Find active choice or set to default
|
155
|
+
#
|
156
|
+
# @return [nil]
|
110
157
|
#
|
111
158
|
# @api private
|
112
|
-
def
|
113
|
-
|
114
|
-
|
159
|
+
def mark_choice_as_active
|
160
|
+
if (@input.to_i > 1) && !@choices[@input.to_i - 1].nil?
|
161
|
+
@active = @input.to_i
|
162
|
+
else
|
163
|
+
@active = @default
|
164
|
+
end
|
165
|
+
@page_active = @active
|
115
166
|
end
|
116
167
|
|
117
168
|
# Validate default indexes to be within range
|
@@ -119,8 +170,16 @@ module TTY
|
|
119
170
|
# @api private
|
120
171
|
def validate_defaults
|
121
172
|
return if @default >= 1 && @default <= @choices.size
|
122
|
-
|
123
|
-
|
173
|
+
raise PromptConfigurationError,
|
174
|
+
"default index `#{d}` out of range (1 - #{@choices.size})"
|
175
|
+
end
|
176
|
+
|
177
|
+
# Setup default option and active selection
|
178
|
+
#
|
179
|
+
# @api private
|
180
|
+
def setup_defaults
|
181
|
+
validate_defaults
|
182
|
+
mark_choice_as_active
|
124
183
|
end
|
125
184
|
|
126
185
|
# Render a selection list.
|
@@ -134,9 +193,9 @@ module TTY
|
|
134
193
|
def render
|
135
194
|
@input = ''
|
136
195
|
until @done
|
137
|
-
render_question
|
196
|
+
lines = render_question
|
138
197
|
@prompt.read_keypress
|
139
|
-
refresh
|
198
|
+
refresh(lines)
|
140
199
|
end
|
141
200
|
render_question
|
142
201
|
render_answer
|
@@ -153,9 +212,11 @@ module TTY
|
|
153
212
|
|
154
213
|
# Determine area of the screen to clear
|
155
214
|
#
|
215
|
+
# @param [Integer] lines
|
216
|
+
# the lines to clear
|
217
|
+
#
|
156
218
|
# @api private
|
157
|
-
def refresh
|
158
|
-
lines = @question.scan("\n").length + @choices.length + 2
|
219
|
+
def refresh(lines)
|
159
220
|
@prompt.print(@prompt.clear_lines(lines))
|
160
221
|
@prompt.print(@prompt.cursor.clear_screen_down)
|
161
222
|
end
|
@@ -166,18 +227,34 @@ module TTY
|
|
166
227
|
def render_question
|
167
228
|
header = "#{@prefix}#{@question} #{render_header}"
|
168
229
|
@prompt.puts(header)
|
169
|
-
|
170
|
-
@
|
171
|
-
|
230
|
+
lines = header.lines.count
|
231
|
+
unless @done
|
232
|
+
menu = render_menu + render_footer
|
233
|
+
lines += menu.lines.count
|
234
|
+
@prompt.print(menu)
|
235
|
+
end
|
172
236
|
render_error if @failure
|
237
|
+
render_page_help if paginated? && !@done
|
238
|
+
lines
|
173
239
|
end
|
174
240
|
|
241
|
+
# Error message when incorrect index chosen
|
242
|
+
#
|
243
|
+
# @api private
|
244
|
+
def error_message
|
245
|
+
error = 'Please enter a valid number'
|
246
|
+
"\n" + @prompt.decorate('>>', @error_color) + ' ' + error
|
247
|
+
end
|
248
|
+
|
249
|
+
# Render error message and return cursor to position of input
|
250
|
+
#
|
175
251
|
# @api private
|
176
252
|
def render_error
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
253
|
+
@prompt.print(error_message)
|
254
|
+
if !paginated?
|
255
|
+
@prompt.print(@prompt.cursor.prev_line)
|
256
|
+
@prompt.print(@prompt.cursor.forward(render_footer.size))
|
257
|
+
end
|
181
258
|
end
|
182
259
|
|
183
260
|
# Render chosen option
|
@@ -188,7 +265,7 @@ module TTY
|
|
188
265
|
def render_header
|
189
266
|
return '' unless @done
|
190
267
|
return '' unless @active
|
191
|
-
selected_item =
|
268
|
+
selected_item = @choices[@active - 1].name.to_s
|
192
269
|
@prompt.decorate(selected_item, @active_color)
|
193
270
|
end
|
194
271
|
|
@@ -201,6 +278,28 @@ module TTY
|
|
201
278
|
" Choose 1-#{@choices.size} [#{@default}]: #{@input}"
|
202
279
|
end
|
203
280
|
|
281
|
+
# Pagination help message
|
282
|
+
#
|
283
|
+
# @return [String]
|
284
|
+
#
|
285
|
+
# @api private
|
286
|
+
def page_help_message
|
287
|
+
return '' unless paginated?
|
288
|
+
"\n" + @prompt.decorate(@page_help, @help_color)
|
289
|
+
end
|
290
|
+
|
291
|
+
# Render page help
|
292
|
+
#
|
293
|
+
# @api private
|
294
|
+
def render_page_help
|
295
|
+
@prompt.print(page_help_message)
|
296
|
+
if @failure
|
297
|
+
@prompt.print(@prompt.cursor.prev_line)
|
298
|
+
end
|
299
|
+
@prompt.print(@prompt.cursor.prev_line)
|
300
|
+
@prompt.print(@prompt.cursor.forward(render_footer.size))
|
301
|
+
end
|
302
|
+
|
204
303
|
# Render menu with indexed choices to select from
|
205
304
|
#
|
206
305
|
# @return [String]
|
@@ -208,11 +307,11 @@ module TTY
|
|
208
307
|
# @api private
|
209
308
|
def render_menu
|
210
309
|
output = ''
|
211
|
-
@choices
|
310
|
+
@paginator.paginate(@choices, @page_active, @per_page) do |choice, index|
|
212
311
|
num = (index + 1).to_s + @enum + Symbols::SPACE
|
213
312
|
selected = Symbols::SPACE * 2 + num + choice.name
|
214
313
|
output << if index + 1 == @active
|
215
|
-
@prompt.decorate(
|
314
|
+
@prompt.decorate(selected.to_s, @active_color)
|
216
315
|
else
|
217
316
|
selected
|
218
317
|
end
|