Skip to content

Commit

Permalink
Make multi-select select keys an array and allow custom labels
Browse files Browse the repository at this point in the history
  • Loading branch information
Geekfish committed May 16, 2021
1 parent 135e62a commit 395e6b1
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 19 deletions.
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Or install it yourself as:
* [2.6.3.8 :min](#2638-min)
* [2.6.3.9 :max](#2639-max)
* [2.6.3.10 :submit_keys](#26310-submit_keys)
* [2.6.3.11 :select_key](#262311-select_key)
* [2.6.3.11 :select_keys](#262311-select_keys)
* [2.6.4 enum_select](#264-enum_select)
* [2.6.4.1 :per_page](#2641-per_page)
* [2.6.4.1 :disabled](#2641-disabled)
Expand Down Expand Up @@ -1239,14 +1239,14 @@ The user can then press the `Ctrl+S` key to confirm their selection:

Please note that alphanumeric keys are *not* supported.

#### 2.6.3.11 `:select_key`
#### 2.6.3.11 `:select_keys`

You can configure which key selects an option (`:space` default).
This is particularly useful in conjunction with the `filter` option, as you may have choices that include spaces.

```ruby
choices = ["gin", "gin tonic", "gin fizz", "beer"]
prompt.multi_select("Select drinks?", choices, filter: true, select_key: :ctrl_s)
prompt.multi_select("Select drinks?", choices, filter: true, select_keys: [:ctrl_s])
# =>
# Select drinks? (Press ↑/↓ arrow keys to move, Ctrl+S/Ctrl+A|R to select (all|rev), Enter to finish and letters to filter)
# ‣ ⬡ gin
Expand Down Expand Up @@ -1282,6 +1282,19 @@ The user can then press the `Ctrl+S` key combo to select the options:
# ⬡ gin fizz
```

Similar to the `:submit_keys` option, you may also pass your own key labels to be displayed in the hint:

```ruby
choices = ["gin", "gin tonic", "gin fizz", "beer"]
prompt.multi_select("Select drinks?", choices, filter: true, select_keys: [{ctr_s: "Ctrl-S"}, {space: "Spacebar"}])
# =>
# Select drinks? (Press ↑/↓ arrow keys to move, Ctrl-S or Spacebar/Ctrl+A|R to select (all|rev), Enter to finish and letters to filter)
# ‣ ⬡ gin
# ⬡ gin tonic
# ⬡ gin fizz
# ⬡ beer
```

Please note that alphanumeric keys are *not* supported.

### 2.6.4 enum_select
Expand Down
10 changes: 10 additions & 0 deletions examples/multi_select_custom_keys.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

require_relative "../lib/tty-prompt"

prompt = TTY::Prompt.new

drinks = %w[vodka beer wine whisky bourbon]
prompt.multi_select("Choose your favourite drink?", drinks,
submit_keys: [:return, {escape: "Esc"}],
select_keys: [{space: "Spacebar"}, :ctrl_s])
6 changes: 3 additions & 3 deletions lib/tty/prompt/list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,8 @@ def key_help_label(key_name)
# @return [String]
#
# @api private
def submit_keys_help
labels = @submit_keys.values.uniq
def keys_help(keys)
labels = keys.values.uniq
if labels.length == 1
labels[0]
else
Expand All @@ -226,7 +226,7 @@ def default_help
str << " or 1-#{choices.size} number" if enumerate?
str << " to move"
str << (filterable? ? "," : " and")
str << " #{submit_keys_help} to select"
str << " #{keys_help(@submit_keys)} to select"
str << " and letters to filter" if filterable?
str << ")"
str.join
Expand Down
12 changes: 6 additions & 6 deletions lib/tty/prompt/multi_list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class MultiList < List
def initialize(prompt, **options)
super
@selected = SelectedChoices.new
@select_key = options.fetch(:select_key) { :space }
@select_keys = keys_with_labels(options.fetch(:select_keys, [:space]))
@help = options[:help]
@echo = options.fetch(:echo, true)
@min = options[:min]
Expand Down Expand Up @@ -78,7 +78,7 @@ def select_choice
#
# @api private
def keypress(event)
if event.key.name == @select_key
if @select_keys.include?(event.key.name)
select_choice
else
super(event)
Expand Down Expand Up @@ -113,11 +113,11 @@ def keyctrl_r(*)
#
# @api private
def check_clashing_keys
return unless @submit_keys.include?(@select_key)
return if (@submit_keys.keys & @select_keys.keys).empty?

raise ConfigurationError,
":submit_keys #{@submit_keys.keys} are clashing with " \
":select_key (:#{@select_key})"
":select_keys #{@select_keys.keys}"
end

# Setup default options and active selection
Expand Down Expand Up @@ -177,12 +177,12 @@ def default_help
str << "(Press "
str << "#{arrows_help} arrow"
str << " or 1-#{choices.size} number" if enumerate?
str << " to move, #{key_help_label(@select_key)}"
str << " to move, #{keys_help(@select_keys)}"
str << "/Ctrl+A|R" if @max.nil?
str << " to select"
str << " (all|rev)" if @max.nil?
str << (filterable? ? "," : " and")
str << " #{submit_keys_help} to finish"
str << " #{keys_help(@submit_keys)} to finish"
str << " and letters to filter" if filterable?
str << ")"
str.join
Expand Down
29 changes: 22 additions & 7 deletions spec/unit/multi_select_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,30 @@ def exit_message(prompt, choices)
expect(prompt.output.string).to eq(expected_output)
end

it "selects item when custom key pressed" do
it "selects item when custom key pressed and shows custom key labels" do
choices = %w[vodka beer wine whisky bourbon]
prompt.input << "\C-s\r"
prompt.input.rewind
expect(prompt.multi_select("Select drinks?", choices, select_key: :ctrl_s)).to eq(["vodka"])
expect(prompt.multi_select("Select drinks?", choices, select_keys: [:ctrl_s, {escape: "Esc"}])).to eq(["vodka"])

expected_output =
output_helper("Select drinks?", choices, "vodka", [], init: true,
hint: "Press #{up_down} arrow to move, Ctrl+S/Ctrl+A|R to select (all|rev) and Enter to finish") +
hint: "Press #{up_down} arrow to move, Ctrl+S or Esc/Ctrl+A|R to select (all|rev) and Enter to finish") +
output_helper("Select drinks?", choices, "vodka", ["vodka"]) +
exit_message("Select drinks?", %w[vodka])

expect(prompt.output.string).to eq(expected_output)
end

it "selects item and submits selection with custom keys" do
choices = %w[vodka beer wine whisky bourbon]
prompt.input << "\C-s\e"
prompt.input.rewind
expect(prompt.multi_select("Select drinks?", choices, select_keys: [:ctrl_s], submit_keys: [{escape: "Esc"}])).to eq(["vodka"])

expected_output =
output_helper("Select drinks?", choices, "vodka", [], init: true,
hint: "Press #{up_down} arrow to move, Ctrl+S/Ctrl+A|R to select (all|rev) and Esc to finish") +
output_helper("Select drinks?", choices, "vodka", ["vodka"]) +
exit_message("Select drinks?", %w[vodka])

Expand Down Expand Up @@ -272,16 +287,16 @@ def exit_message(prompt, choices)
expect {
prompt.multi_select("Select drinks?", %w[vodka beer wine], submit_keys: [:space])
}.to raise_error(TTY::Prompt::ConfigurationError,
":submit_keys [:space] are clashing with :select_key (:space)")
":submit_keys [:space] are clashing with :select_keys [:space]")
end

it "raises error when submit and select keys clash (configured)" do
prompt.input << "\r"
prompt.input.rewind
expect {
prompt.multi_select("Select drinks?", %w[vodka beer wine], submit_keys: %i[space ctrl_s], select_key: :space)
prompt.multi_select("Select drinks?", %w[vodka beer wine], submit_keys: %i[space ctrl_s], select_keys: [:space])
}.to raise_error(TTY::Prompt::ConfigurationError,
":submit_keys [:space, :ctrl_s] are clashing with :select_key (:space)")
":submit_keys [:space, :ctrl_s] are clashing with :select_keys [:space]")
end


Expand Down Expand Up @@ -756,7 +771,7 @@ def exit_message(prompt, choices)
prompt.input << "\r"
prompt.input.rewind

expect(prompt.multi_select("Select drinks?", choices, filter: true, select_key: :ctrl_s)).to eq(["gin fizz", "gin tonic"])
expect(prompt.multi_select("Select drinks?", choices, filter: true, select_keys: [:ctrl_s])).to eq(["gin fizz", "gin tonic"])

expected_output =
output_helper("Select drinks?", choices, "gin", [], init: true,
Expand Down

0 comments on commit 395e6b1

Please sign in to comment.