tty-prompt 0.8.0 → 0.9.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 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