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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f9a360c4b3a7cd670868b20f7b220223274f555b
4
- data.tar.gz: 17667527540e13b4e91eca3c042c9fcc5cb24b86
3
+ metadata.gz: 2ef2f5ff49f413f853a8cb33f8894189fb36f728
4
+ data.tar.gz: cbcd8a42cfefbfbaad8d2028fc5847ce55a20443
5
5
  SHA512:
6
- metadata.gz: e7489d7dcde47bad702c66740391db047b17d94eedb9c110de0b77ffc59ba6c4cca83f95d2e5dc85417b6e1e5f409d0bd88c5a00367e260b29ea48f3efe7c798
7
- data.tar.gz: ef5bec91d62387297bbc29b947bb39d014e3a2239d5679a9175e6944520d490caca7f327abf695c3b27f42055169c89cd7b924522dec1a55e61e94ed2e9e379b
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 select](#27-select)
64
- * [2.7.1 multi_select](#271-multi_select)
65
- * [2.7.2 enum_select](#272-enum_select)
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 select
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
- ### 2.7.1 multi_select
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
- ### 2.7.2 enum_select
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"
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ require 'tty-prompt'
4
+
5
+ prompt = TTY::Prompt.new
6
+
7
+ alfabet = ('A'..'Z').to_a
8
+
9
+ prompt.enum_select('Which letter?', alfabet, per_page: 4)
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ require 'tty-prompt'
4
+
5
+ prompt = TTY::Prompt.new
6
+
7
+ alfabet = ('A'..'Z').to_a
8
+
9
+ prompt.select('Which letter?', alfabet, per_page: 8)
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'
@@ -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.call(self) if 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
- @input.chop! unless @input.empty?
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
- alias_method :keyenter, :keyreturn
133
+ alias keyenter keyreturn
98
134
 
99
- private
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 mark_choice_as_active
102
- if !@choices[@input.to_i - 1].nil?
103
- @active = @input.to_i
144
+ def keyleft(*)
145
+ if (@page_active - page_size) >= 0
146
+ @page_active -= page_size
104
147
  else
105
- @active = nil
148
+ @page_active = @choices.size - 1
106
149
  end
107
150
  end
108
151
 
109
- # Setup default option and active selection
152
+ private
153
+
154
+ # Find active choice or set to default
155
+ #
156
+ # @return [nil]
110
157
  #
111
158
  # @api private
112
- def setup_defaults
113
- validate_defaults
114
- @active = @default
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
- fail PromptConfigurationError,
123
- "default index `#{d}` out of range (1 - #{@choices.size})"
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
- return if @done
170
- @prompt.print(render_menu)
171
- @prompt.print(render_footer)
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
- error = 'Please enter a valid index'
178
- @prompt.print("\n" + @prompt.decorate('>>', @error_color) + ' ' + error)
179
- @prompt.print(@prompt.cursor.prev_line)
180
- @prompt.print(@prompt.cursor.forward(render_footer.size))
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 = "#{@choices[@active - 1].name}"
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.each_with_index do |choice, index|
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("#{selected}", @active_color)
314
+ @prompt.decorate(selected.to_s, @active_color)
216
315
  else
217
316
  selected
218
317
  end