tty-prompt 0.13.2 → 0.14.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: 774726386ea09cc8c3fc2abd877e377eb3db3c3d
4
- data.tar.gz: 43ac05278ae482148a133e7b4ca1ad304e304189
3
+ metadata.gz: 914b91c8d5090e18ffa6da38c4e4ba7f26a7f50a
4
+ data.tar.gz: 0dea47a0af899dc93a532fc4371710807e8ef472
5
5
  SHA512:
6
- metadata.gz: d78bc4524d6e8183692e636d783d4c40c4666af82364084e67d3dae701dd9a2bd0695eeb4eac9925616bd054cf1edcca701307f016c3f9ea7a0756c6a0eedeac
7
- data.tar.gz: 6965d2d8df2dcffdfe33539d71da7426a185fca2a1649d665417cca03d4961edb20c45e2cd65c2f74784201b86ec3a4e7135b21de547f73db1e7da410b459f2f
6
+ metadata.gz: 9476326073c28e1c92c8b1a48fe66ce4769589ad44a15758ac376512a20f77065a5f78dc51a4b2c897f7825cf9d325d0c285700961c4a7f942c7a2bd8351bde8
7
+ data.tar.gz: 7206776eb52eb9451641be93db1de554bbbf94cdab014d8f5f21a4f46aa52acbd4cb50745806b6eb078f88eb863b97645483833d2df441cbb995245a64901912
data/.travis.yml CHANGED
@@ -2,17 +2,18 @@
2
2
  language: ruby
3
3
  sudo: false
4
4
  cache: bundler
5
+ before_install: "gem update bundler"
5
6
  bundler_args: --without tools
6
7
  script: "bundle exec rake ci"
7
8
  rvm:
8
- - 1.9.3
9
9
  - 2.0.0
10
10
  - 2.1.10
11
- - 2.2.6
12
- - 2.3.3
13
- - 2.4.1
11
+ - 2.2.8
12
+ - 2.3.6
13
+ - 2.4.3
14
14
  - ruby-head
15
15
  - jruby-9000
16
+ - jruby-9.1.1.0
16
17
  - jruby-head
17
18
  matrix:
18
19
  allow_failures:
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Change log
2
2
 
3
+ ## [v0.14.0] - 2018-01-01
4
+
5
+ ### Added
6
+ * Add :cycle option to #select, #multi_select & #enum_select prompts to allow toggling between infinite and bounded list by Jonas Müller(@muellerj)
7
+
8
+ ### Changed
9
+ * Change #multi_selct, #select & #enum_select to stop cycling options by default by Jona Müller(@muellerj)
10
+ * Change gemspec to require ruby >= 2.0.0
11
+ * Change #slider prompt to display slider next to query and help underneath
12
+ * Change to use tty-reader v0.2.0 with new line editing features for processing long inputs
13
+
14
+ ### Fixed
15
+ * Fix Paginator & EnumPaginator to allow only positive integer values by Andy Brody(@ab)
16
+ * Fix EnumSelect to report on default option out of range and raise correctly
17
+ * Fix #ask :file & :path converters to correctly locate the files
18
+ * Fix #ask, #multiline to correctly handle long strings that wrap around screen
19
+ * Fix #slider prompt to correctly scale sliding
20
+
3
21
  ## [v0.13.2] - 2017-08-30
4
22
 
5
23
  ### Changed
data/Gemfile CHANGED
@@ -6,7 +6,7 @@ gemspec
6
6
  # gem 'tty-reader', git: 'https://github.com/piotrmurach/tty-reader'
7
7
 
8
8
  group :test do
9
- gem 'benchmark-ips', '~> 2.0.0'
9
+ gem 'benchmark-ips', '~> 2.7.2'
10
10
  gem 'simplecov', '~> 0.10.0'
11
11
  gem 'coveralls', '~> 0.8.2'
12
12
  gem 'term-ansicolor', '=1.3.2'
@@ -17,6 +17,6 @@ group :tools do
17
17
  end
18
18
 
19
19
  group :metrics do
20
- gem 'yard', '~> 0.8.7'
20
+ gem 'yard', '~> 0.9.12'
21
21
  gem 'yardstick', '~> 0.9.9'
22
22
  end
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # TTY::Prompt [![Gitter](https://badges.gitter.im/Join%20Chat.svg)][gitter]
2
+
2
3
  [![Gem Version](https://badge.fury.io/rb/tty-prompt.svg)][gem]
3
4
  [![Build Status](https://secure.travis-ci.org/piotrmurach/tty-prompt.svg?branch=master)][travis]
4
5
  [![Build status](https://ci.appveyor.com/api/projects/status/4cguoiah5dprbq7n?svg=true)][appveyor]
@@ -25,6 +26,17 @@
25
26
  * User friendly error feedback
26
27
  * Intuitive DSL for creating complex menus
27
28
  * Ability to page long menus
29
+ * Support for Linux, OS X, FreeBSD and Windows systems
30
+
31
+ ## Windows support
32
+
33
+ `tty-prompt` works across all Unix and Windows systems in the "best possible" way. On Windows, it uses Win32 API in place of terminal device to provide matching functionality.
34
+
35
+ Since Unix terminals provide richer set of features than Windows PowerShell consoles, expect to have a better experience on Unix-like platform.
36
+
37
+ Some features like `select` or `multi_select` menus may not work on Windows when run from Git Bash. See GitHub suggested [fixes](https://github.com/git-for-windows/git/wiki/FAQ#some-native-console-programs-dont-work-when-run-from-git-bash-how-to-fix-it).
38
+
39
+ For Windows, consider installing [ConEmu](https://conemu.github.io/), [cmder](http://cmder.net/) or [PowerCmd](http://www.powercmd.com/).
28
40
 
29
41
  ## Installation
30
42
 
@@ -362,7 +374,7 @@ prompt.keypress("Press key ?")
362
374
  By default any key is accepted but you can limit keys by using `:keys` option. Any key event names such as `:space` or `:ctrl_k` are valid:
363
375
 
364
376
  ```ruby
365
- prompt.keypress("Press space or enter to continue, keys: [:space, :return])
377
+ prompt.keypress("Press space or enter to continue", keys: [:space, :return])
366
378
  ```
367
379
 
368
380
  #### 2.2.1 timeout
@@ -564,6 +576,17 @@ end
564
576
  # ‣ Jax
565
577
  ```
566
578
 
579
+ You can navigate the choices using the arrow keys or define your own keymappings (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 `mutli_select`:
580
+
581
+ ```ruby
582
+ prompt.select("Choose your destiny?", %w(Scorpion Kano Jax), cycle: true)
583
+ # =>
584
+ # Choose your destiny? (Use arrow keys, press Enter to select)
585
+ # ‣ Scorpion
586
+ # Kano
587
+ # Jax
588
+ ```
589
+
567
590
  For ordered choices set `enum` to any delimiter String. In that way, you can use arrows keys and numbers (0-9) to select the item.
568
591
 
569
592
  ```ruby
@@ -704,6 +727,12 @@ And when you press enter you will see the following selected:
704
727
  # => [{score: 20}, {score: 50}]
705
728
  ```
706
729
 
730
+ Also like, `select`, the method takes an option `cycle` (which defaults to `false`), which lets you configure whether the selection should cycle around when reaching the top/bottom of the list when navigating:
731
+
732
+ ```ruby
733
+ prompt.multi_select("Select drinks?", %w(vodka beer wine), cycle: true)
734
+ ```
735
+
707
736
  You can configure help message and/or marker like so
708
737
 
709
738
  ```ruby
@@ -933,29 +962,47 @@ prompt.suggest('b', possible, indent: 4, single_text: 'Perhaps you meant?')
933
962
 
934
963
  ### 2.10 slider
935
964
 
936
- If you have constrained range of numbers for user to choose from you may consider using `slider`. The slider provides easy visual way of picking a value marked by `O` marker.
965
+ If you have constrained range of numbers for user to choose from you may consider using `slider`.
966
+
967
+ The slider provides easy visual way of picking a value marked by `O` marker. You can set `:min`(defaults to 0), `:max` and `:step`(defaults to 1) options to configure slider range:
937
968
 
938
969
  ```ruby
939
- prompt.slider('What size?', min: 32, max: 54, step: 2)
970
+ prompt.slider('Volume', max: 100, step: 5)
940
971
  # =>
941
- #
942
- # What size? (User arrow keys, press Enter to select)
943
- # |------O-----| 44
972
+ # Volume ──────────O────────── 50
973
+ # (User arrow keys, press Enter to select)
974
+ ```
975
+
976
+ 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:
977
+
978
+ ```ruby
979
+ prompt.slider('Volume', max: 100, step: 5, default: 75)
980
+ # =>
981
+ # Volume ───────────────O───── 75
982
+ # (Use arrow keys, press Enter to select)
983
+ ```
984
+
985
+ You can also change the default slider formatting using the `:format`. The value must contain the `:slider` token for placing the actual animation and any `sprintf` compatible flag for number display, in our case `%d`:
986
+
987
+ ```ruby
988
+ prompt.slider('Volume', max: 100, step: 5, default: 75, format: "|:slider| %d%")
989
+ # =>
990
+ # Volume |───────────────O─────| 75%
991
+ # (Use arrow keys, press Enter to select)
944
992
  ```
945
993
 
946
994
  Slider can be configured through DSL as well:
947
995
 
948
996
  ```ruby
949
997
  prompt.slider('What size?') do |range|
950
- range.default 4
951
- range.min 0
952
- range.max 20
953
- range.step 2
998
+ range.max 100
999
+ range.step 5
1000
+ range.default 75
1001
+ range.format "|:slider| %d%"
954
1002
  end
955
1003
  # =>
956
- #
957
- # What size? (User arrow keys, press Enter to select)
958
- # |--O-------| 4
1004
+ # Volume |───────────────O─────| 75%
1005
+ # (Use arrow keys, press Enter to select)
959
1006
  ```
960
1007
 
961
1008
  ### 2.11 say
@@ -1129,4 +1176,4 @@ This project is intended to be a safe, welcoming space for collaboration, and co
1129
1176
 
1130
1177
  ## Copyright
1131
1178
 
1132
- Copyright (c) 2015-2017 Piotr Murach. See LICENSE for further details.
1179
+ Copyright (c) 2015-2018 Piotr Murach. See LICENSE for further details.
data/appveyor.yml CHANGED
@@ -9,7 +9,6 @@ test_script:
9
9
  - bundle exec rake ci
10
10
  environment:
11
11
  matrix:
12
- - ruby_version: "193"
13
12
  - ruby_version: "200"
14
13
  - ruby_version: "200-x64"
15
14
  - ruby_version: "21"
@@ -20,6 +19,3 @@ environment:
20
19
  - ruby_version: "23-x64"
21
20
  - ruby_version: "24"
22
21
  - ruby_version: "24-x64"
23
- matrix:
24
- allow_failures:
25
- - ruby_version: "193"
data/benchmarks/speed.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'tty-prompt'
4
3
  require 'benchmark/ips'
5
4
  require 'stringio'
5
+ require_relative '../lib/tty-prompt'
6
6
 
7
7
  input = ::StringIO.new
8
8
  output = ::StringIO.new
data/examples/ask.rb CHANGED
@@ -1,15 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt.new
6
6
 
7
7
  prompt.ask('What is your name?', default: ENV['USER'])
8
-
9
- prompt.ask('Folder name?') do |q|
10
- q.required(true)
11
- q.validate ->(v) { return !Dir.exist?(v) }
12
- q.messages[:valid?] = 'Folder already exists?'
13
- q.messages[:required?] = 'Folder name must not be empty'
14
- end
15
-
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative "../lib/tty-prompt"
4
+
5
+ prompt = TTY::Prompt.new
6
+
7
+ prompt.ask('Folder name?') do |q|
8
+ q.required(true)
9
+ q.validate ->(v) { return !Dir.exist?(v) }
10
+ q.messages[:valid?] = 'Folder already exists?'
11
+ q.messages[:required?] = 'Folder name must not be empty'
12
+ end
data/examples/collect.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require 'json'
4
+
5
+ require_relative "../lib/tty-prompt"
4
6
 
5
7
  prompt = TTY::Prompt.new(prefix: '[?] ')
6
8
 
@@ -16,4 +18,4 @@ result = prompt.collect do
16
18
  end
17
19
  end
18
20
 
19
- puts result
21
+ puts JSON.pretty_generate(result)
data/examples/echo.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt.new
6
6
 
@@ -8,4 +8,4 @@ answer = prompt.ask('Password?', echo: false) do |q|
8
8
  q.validate(/^[^\.]+\.[^\.]+/)
9
9
  end
10
10
 
11
- #puts answer
11
+ puts "Password: #{answer}"
data/examples/enum.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt.new
6
6
 
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt.new
6
6
 
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt.new
6
6
  choices = %w(/bin/nano /usr/bin/vim.basic /usr/bin/vim.tiny)
data/examples/expand.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  choices = [{
6
6
  key: 'y',
data/examples/in.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt.new
6
6
 
data/examples/inputs.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt.new
6
6
 
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt::new(interrupt: :exit)
6
6
 
data/examples/keypress.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt::new
6
6
 
data/examples/mask.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
  require 'pastel'
5
5
 
6
6
  prompt = TTY::Prompt.new
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt.new
6
6
 
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt.new
6
6
 
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt::new
6
6
 
data/examples/pause.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt::new
6
6
 
data/examples/select.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt.new
6
6
 
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt.new
6
6
 
data/examples/slider.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt.new
6
- prompt.slider("What size?", min: 0, max: 40, step: 1)
6
+ prompt.slider("Volume", max: 100, step: 5, default: 75, format: "|:slider| %d%")
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt.new
6
6
 
data/examples/yes_no.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty-prompt'
3
+ require_relative "../lib/tty-prompt"
4
4
 
5
5
  prompt = TTY::Prompt.new
6
6
 
data/lib/tty/prompt.rb CHANGED
@@ -75,7 +75,8 @@ module TTY
75
75
  :show, :hide
76
76
 
77
77
  def_delegators :@reader, :read_char, :read_line, :read_keypress,
78
- :read_multiline, :on, :subscribe, :trigger
78
+ :read_multiline, :on, :subscribe, :trigger,
79
+ :count_screen_lines
79
80
 
80
81
  def_delegators :@output, :print, :puts, :flush
81
82
 
@@ -127,8 +128,13 @@ module TTY
127
128
 
128
129
  @cursor = TTY::Cursor
129
130
  @pastel = Pastel.new(@enabled_color.nil? ? {} : { enabled: @enabled_color })
130
- @reader = TTY::Reader.new(@input, @output, interrupt: @interrupt,
131
- track_history: @track_history, env: @env)
131
+ @reader = TTY::Reader.new(
132
+ input: @input,
133
+ output: @output,
134
+ interrupt: @interrupt,
135
+ track_history: @track_history,
136
+ env: @env
137
+ )
132
138
  end
133
139
 
134
140
  # Invoke a question type of prompt
@@ -60,13 +60,11 @@ module TTY
60
60
  end
61
61
 
62
62
  converter(:file) do |input|
63
- directory = ::File.expand_path(::File.dirname($0))
64
- ::File.open(::File.join(directory, input))
63
+ ::File.open(::File.join(Dir.pwd, input))
65
64
  end
66
65
 
67
66
  converter(:path) do |input|
68
- directory = ::File.expand_path(::File.dirname($0))
69
- Pathname.new(::File.join(directory, input))
67
+ Pathname.new(::File.join(Dir.pwd, input))
70
68
  end
71
69
 
72
70
  converter(:char) do |input|
@@ -24,6 +24,7 @@ module TTY
24
24
  @active_color = options.fetch(:active_color) { @prompt.active_color }
25
25
  @help_color = options.fetch(:help_color) { @prompt.help_color }
26
26
  @error_color = options.fetch(:error_color) { @prompt.error_color }
27
+ @cycle = options.fetch(:cycle) { false }
27
28
  @input = nil
28
29
  @done = false
29
30
  @first_render = true
@@ -139,7 +140,7 @@ module TTY
139
140
  def keyright(*)
140
141
  if (@page_active + page_size) <= @choices.size
141
142
  @page_active += page_size
142
- else
143
+ elsif @cycle
143
144
  @page_active = 1
144
145
  end
145
146
  end
@@ -148,7 +149,7 @@ module TTY
148
149
  def keyleft(*)
149
150
  if (@page_active - page_size) >= 0
150
151
  @page_active -= page_size
151
- else
152
+ elsif @cycle
152
153
  @page_active = @choices.size - 1
153
154
  end
154
155
  end
@@ -174,8 +175,8 @@ module TTY
174
175
  # @api private
175
176
  def validate_defaults
176
177
  return if @default >= 1 && @default <= @choices.size
177
- raise PromptConfigurationError,
178
- "default index `#{d}` out of range (1 - #{@choices.size})"
178
+ raise ConfigurationError,
179
+ "default index `#{@default}` out of range (1 - #{@choices.size})"
179
180
  end
180
181
 
181
182
  # Setup default option and active selection
@@ -13,6 +13,8 @@ module TTY
13
13
  default_size = (list.size <= DEFAULT_PAGE_SIZE ? list.size : DEFAULT_PAGE_SIZE)
14
14
  @per_page = @per_page || per_page || default_size
15
15
 
16
+ check_page_size!
17
+
16
18
  # Don't paginate short lists
17
19
  if list.size <= @per_page
18
20
  @lower_index = 0
@@ -25,7 +25,9 @@ module TTY
25
25
  @interval_handler = proc { |time|
26
26
  unless @done
27
27
  question = render_question
28
- @prompt.print(refresh(question.lines.count))
28
+ line_size = question.size
29
+ total_lines = @prompt.count_screen_lines(line_size)
30
+ @prompt.print(refresh(question.lines.count, total_lines))
29
31
  countdown(time)
30
32
  @prompt.print(render_question)
31
33
  end
@@ -70,6 +72,7 @@ module TTY
70
72
 
71
73
  def process_input(question)
72
74
  time do
75
+ @prompt.print(render_question)
73
76
  until @done
74
77
  @input = @prompt.read_keypress(nonblock: true)
75
78
  end
@@ -77,7 +80,7 @@ module TTY
77
80
  @evaluator.(@input)
78
81
  end
79
82
 
80
- def refresh(lines)
83
+ def refresh(lines, lines_to_clear)
81
84
  @prompt.clear_lines(lines)
82
85
  end
83
86
 
@@ -41,6 +41,7 @@ module TTY
41
41
  @active_color = options.fetch(:active_color) { @prompt.active_color }
42
42
  @help_color = options.fetch(:help_color) { @prompt.help_color }
43
43
  @marker = options.fetch(:marker) { symbols[:pointer] }
44
+ @cycle = options.fetch(:cycle) { false }
44
45
  @help = options[:help]
45
46
  @first_render = true
46
47
  @done = false
@@ -169,20 +170,26 @@ module TTY
169
170
  @active = value
170
171
  end
171
172
 
172
- def keyspace(*)
173
- @done = true
174
- end
175
-
176
- def keyreturn(*)
173
+ def keyenter(*)
177
174
  @done = true
178
175
  end
176
+ alias keyreturn keyenter
177
+ alias keyspace keyenter
179
178
 
180
179
  def keyup(*)
181
- @active = (@active == 1) ? @choices.length : @active - 1
180
+ if @active == 1
181
+ @active = @choices.length if @cycle
182
+ else
183
+ @active -= 1
184
+ end
182
185
  end
183
186
 
184
187
  def keydown(*)
185
- @active = (@active == @choices.length) ? 1 : @active + 1
188
+ if @active == @choices.length
189
+ @active = 1 if @cycle
190
+ else
191
+ @active += 1
192
+ end
186
193
  end
187
194
  alias keytab keydown
188
195
 
@@ -78,9 +78,12 @@ module TTY
78
78
  @done_masked = false
79
79
  @failure = false
80
80
  @input = ''
81
+ @prompt.print(question)
81
82
  until @done_masked
82
83
  @prompt.read_keypress
83
- @prompt.print(@prompt.clear_line)
84
+ question = render_question
85
+ total_lines = @prompt.count_screen_lines(question)
86
+ @prompt.print(@prompt.clear_lines(total_lines))
84
87
  @prompt.print(render_question)
85
88
  end
86
89
  @prompt.puts
@@ -54,6 +54,7 @@ module TTY
54
54
  end
55
55
 
56
56
  def process_input(question)
57
+ @prompt.print(question)
57
58
  @lines = read_input
58
59
  @input = "#{@lines.first.strip} ..." unless @lines.first.to_s.empty?
59
60
  if Utils.blank?(@input)
@@ -62,8 +63,8 @@ module TTY
62
63
  @evaluator.(@lines)
63
64
  end
64
65
 
65
- def refresh(lines)
66
- size = @lines_count + lines + 1
66
+ def refresh(lines, lines_to_clear)
67
+ size = @lines_count + lines_to_clear + 1
67
68
  @prompt.clear_lines(size)
68
69
  end
69
70
  end # Multiline
@@ -24,6 +24,15 @@ module TTY
24
24
  @lower_index + @per_page - 1
25
25
  end
26
26
 
27
+ # Check if page size is valid
28
+ #
29
+ # @raise [InvalidArgument]
30
+ #
31
+ # @api private
32
+ def check_page_size!
33
+ raise InvalidArgument, 'per_page must be > 0' if @per_page < 1
34
+ end
35
+
27
36
  # Paginate collection given an active index
28
37
  #
29
38
  # @param [Array[Choice]] list
@@ -43,6 +52,8 @@ module TTY
43
52
  @lower_index ||= current_index
44
53
  @upper_index ||= max_index
45
54
 
55
+ check_page_size!
56
+
46
57
  # Don't paginate short lists
47
58
  if list.size <= @per_page
48
59
  @lower_index = 0
@@ -107,16 +107,17 @@ module TTY
107
107
  def render
108
108
  @errors = []
109
109
  until @done
110
- question = render_question
111
- @prompt.print(question)
112
- result = process_input(question)
110
+ result = process_input(render_question)
113
111
  if result.failure?
114
112
  @errors = result.errors
115
113
  @prompt.print(render_error(result.errors))
116
114
  else
117
115
  @done = true
118
116
  end
119
- @prompt.print(refresh(question.lines.count))
117
+ question = render_question
118
+ input_line = question + result.value.to_s
119
+ total_lines = @prompt.count_screen_lines(input_line)
120
+ @prompt.print(refresh(question.lines.count, total_lines))
120
121
  end
121
122
  @prompt.print(render_question)
122
123
  convert_result(result.value)
@@ -164,11 +165,10 @@ module TTY
164
165
  #
165
166
  # @api private
166
167
  def render_error(errors)
167
- errors.reduce('') do |acc, err|
168
- newline = (@echo ? '' : "\n")
169
- acc << newline + @prompt.decorate('>>', :red) + ' ' + err
168
+ errors.reduce([]) do |acc, err|
169
+ acc << @prompt.decorate('>>', :red) + ' ' + err
170
170
  acc
171
- end
171
+ end.join("\n")
172
172
  end
173
173
 
174
174
  # Determine area of the screen to clear
@@ -179,18 +179,19 @@ module TTY
179
179
  # @return [String]
180
180
  #
181
181
  # @api private
182
- def refresh(lines)
182
+ def refresh(lines, lines_to_clear)
183
183
  output = ''
184
184
  if @done
185
- if @errors.count.zero? && @echo
185
+ if @errors.count.zero?
186
186
  output << @prompt.cursor.up(lines)
187
187
  else
188
188
  lines += @errors.count
189
+ lines_to_clear += @errors.count
189
190
  end
190
191
  else
191
192
  output << @prompt.cursor.up(lines)
192
193
  end
193
- output + @prompt.clear_lines(lines)
194
+ output + @prompt.clear_lines(lines_to_clear)
194
195
  end
195
196
 
196
197
  # Convert value to expected type
@@ -13,8 +13,19 @@ module TTY
13
13
 
14
14
  HELP = '(Use arrow keys, press Enter to select)'.freeze
15
15
 
16
+ FORMAT = ':slider %d'.freeze
17
+
16
18
  # Initailize a Slider
17
19
  #
20
+ # @param [Prompt] prompt
21
+ # the prompt
22
+ # @param [Hash] options
23
+ # the options to configure this slider
24
+ # @option options [Integer] :min The minimum value
25
+ # @option options [Integer] :max The maximum value
26
+ # @option options [Integer] :step The step value
27
+ # @option options [String] :format The display format
28
+ #
18
29
  # @api public
19
30
  def initialize(prompt, options = {})
20
31
  @prompt = prompt
@@ -25,6 +36,7 @@ module TTY
25
36
  @default = options[:default]
26
37
  @active_color = options.fetch(:active_color) { @prompt.active_color }
27
38
  @help_color = options.fetch(:help_color) { @prompt.help_color }
39
+ @format = options.fetch(:format) { FORMAT }
28
40
  @first_render = true
29
41
  @done = false
30
42
 
@@ -73,6 +85,10 @@ module TTY
73
85
  @step = value
74
86
  end
75
87
 
88
+ def format(value)
89
+ @format = value
90
+ end
91
+
76
92
  # Call the slider by passing question
77
93
  #
78
94
  # @param [String] question
@@ -89,17 +105,18 @@ module TTY
89
105
  def keyleft(*)
90
106
  @active -= 1 if @active > 0
91
107
  end
92
- alias_method :keydown, :keyleft
108
+ alias keydown keyleft
93
109
 
94
110
  def keyright(*)
95
- @active += 1 if (@active + @step) < range.size
111
+ @active += 1 if (@active + 1) < range.size
96
112
  end
97
- alias_method :keyup, :keyright
113
+ alias keyup keyright
98
114
 
99
115
  def keyreturn(*)
100
116
  @done = true
101
117
  end
102
- alias_method :keyspace, :keyreturn
118
+ alias keyspace keyreturn
119
+ alias keyenter keyreturn
103
120
 
104
121
  private
105
122
 
@@ -143,23 +160,18 @@ module TTY
143
160
  #
144
161
  # @api private
145
162
  def render_question
146
- header = "#{@prefix}#{@question} #{render_header}\n"
147
- @first_render = false
148
- header << render_slider unless @done
149
- header
150
- end
151
-
152
- # Render actual answer or help
153
- #
154
- # @return [String]
155
- #
156
- # @api private
157
- def render_header
163
+ header = "#{@prefix}#{@question} "
158
164
  if @done
159
- @prompt.decorate(answer.to_s, @active_color)
160
- elsif @first_render
161
- @prompt.decorate(HELP, @help_color)
165
+ header << @prompt.decorate(answer.to_s, @active_color)
166
+ header << "\n"
167
+ else
168
+ header << render_slider
169
+ end
170
+ if @first_render
171
+ header << "\n" + @prompt.decorate(HELP, @help_color)
172
+ @first_render = false
162
173
  end
174
+ header
163
175
  end
164
176
 
165
177
  # Render slider representation
@@ -168,14 +180,11 @@ module TTY
168
180
  #
169
181
  # @api private
170
182
  def render_slider
171
- output = ''
172
- output << symbols[:pipe]
173
- output << symbols[:line] * @active
174
- output << @prompt.decorate(symbols[:handle], @active_color)
175
- output << symbols[:line] * (range.size - @active - 1)
176
- output << symbols[:pipe]
177
- output << " #{range[@active]}"
178
- output
183
+ slider = (symbols[:line] * @active) +
184
+ @prompt.decorate(symbols[:handle], @active_color) +
185
+ (symbols[:line] * (range.size - @active - 1))
186
+ value = " #{range[@active]}"
187
+ @format.gsub(':slider', slider) % [value]
179
188
  end
180
189
  end # Slider
181
190
  end # Prompt
@@ -10,6 +10,8 @@ module TTY
10
10
  tick: '✓',
11
11
  cross: '✘',
12
12
  star: '★',
13
+ square: '◼',
14
+ square_empty: '◻',
13
15
  dot: '•',
14
16
  pointer: '‣',
15
17
  line: '─',
@@ -28,6 +30,8 @@ module TTY
28
30
  tick: '√',
29
31
  cross: '×',
30
32
  star: '*',
33
+ square: '[█]',
34
+ square_empty: '[ ]',
31
35
  dot: '.',
32
36
  pointer: '>',
33
37
  line: '-',
@@ -2,6 +2,6 @@
2
2
 
3
3
  module TTY
4
4
  class Prompt
5
- VERSION = "0.13.2"
5
+ VERSION = '0.14.0'.freeze
6
6
  end # Prompt
7
7
  end # TTY
data/tty-prompt.gemspec CHANGED
@@ -20,13 +20,15 @@ Gem::Specification.new do |spec|
20
20
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
21
  spec.require_paths = ["lib"]
22
22
 
23
+ spec.required_ruby_version = '>= 2.0.0'
24
+
23
25
  spec.add_dependency 'necromancer', '~> 0.4.0'
24
26
  spec.add_dependency 'pastel', '~> 0.7.0'
25
27
  spec.add_dependency 'timers', '~> 4.1.2'
26
28
  spec.add_dependency 'tty-cursor', '~> 0.5.0'
27
- spec.add_dependency 'tty-reader', '~> 0.1.0'
29
+ spec.add_dependency 'tty-reader', '~> 0.2.0'
28
30
 
29
31
  spec.add_development_dependency 'bundler', '>= 1.5.0', '< 2.0'
30
32
  spec.add_development_dependency 'rake'
31
- spec.add_development_dependency 'rspec', '~> 3.5.0'
33
+ spec.add_development_dependency 'rspec', '~> 3.0'
32
34
  end
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.13.2
4
+ version: 0.14.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: 2017-08-30 00:00:00.000000000 Z
11
+ date: 2018-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: necromancer
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 0.1.0
75
+ version: 0.2.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 0.1.0
82
+ version: 0.2.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: bundler
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -120,14 +120,14 @@ dependencies:
120
120
  requirements:
121
121
  - - "~>"
122
122
  - !ruby/object:Gem::Version
123
- version: 3.5.0
123
+ version: '3.0'
124
124
  type: :development
125
125
  prerelease: false
126
126
  version_requirements: !ruby/object:Gem::Requirement
127
127
  requirements:
128
128
  - - "~>"
129
129
  - !ruby/object:Gem::Version
130
- version: 3.5.0
130
+ version: '3.0'
131
131
  description: A beautiful and powerful interactive command line prompt with a robust
132
132
  API for getting and validating complex inputs.
133
133
  email:
@@ -148,6 +148,7 @@ files:
148
148
  - appveyor.yml
149
149
  - benchmarks/speed.rb
150
150
  - examples/ask.rb
151
+ - examples/ask_valid.rb
151
152
  - examples/collect.rb
152
153
  - examples/echo.rb
153
154
  - examples/enum.rb
@@ -217,7 +218,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
217
218
  requirements:
218
219
  - - ">="
219
220
  - !ruby/object:Gem::Version
220
- version: '0'
221
+ version: 2.0.0
221
222
  required_rubygems_version: !ruby/object:Gem::Requirement
222
223
  requirements:
223
224
  - - ">="
@@ -230,4 +231,3 @@ signing_key:
230
231
  specification_version: 4
231
232
  summary: A beautiful and powerful interactive command line prompt.
232
233
  test_files: []
233
- has_rdoc: