diff --git a/lib/tty/prompt/list.rb b/lib/tty/prompt/list.rb index f2c82dc..c946232 100644 --- a/lib/tty/prompt/list.rb +++ b/lib/tty/prompt/list.rb @@ -47,7 +47,7 @@ def initialize(prompt, **options) @filterable = options.fetch(:filter) { false } @symbols = @prompt.symbols.merge(options.fetch(:symbols, {})) @quiet = options.fetch(:quiet) { @prompt.quiet } - @submit_keys = keys_with_labels(options.fetch(:submit_keys) { default_submit_keys }) + @submit_keys = init_action_keys(options.fetch(:submit_keys) { default_submit_keys }) @filter = [] @filter_cache = {} @help = options[:help] @@ -87,6 +87,39 @@ def default_submit_keys %i[space return enter].freeze end + # Ensure that if any EOL char is passed as an action key + # then all EOL chars are included (for cross-system compat) + # Maintain any custom labels. + # + # @return [Array[Hash]] + # + # @api private + def ensure_eol_compat(keys) + eol_symbols = %i[enter return].sort + key_symbols = keys.keys.sort + key_intersection = key_symbols & eol_symbols + + case key_intersection + when [], eol_symbols + keys + else + eol_label = keys[key_intersection[0]] + all_eol_keys = eol_symbols.to_h { |key| [key, eol_label] } + all_eol_keys.merge(keys) + end + end + + # Initialize any default or custom action keys + # setting up their labels and dealing with compat + # + # @return [Array[Hash]] + # + # @api private + def init_action_keys(keys) + keys = keys_with_labels(keys) + ensure_eol_compat(keys) + end + # Select paginator based on the current navigation key # # @return [Paginator] diff --git a/lib/tty/prompt/multi_list.rb b/lib/tty/prompt/multi_list.rb index 8ffd805..4e65335 100644 --- a/lib/tty/prompt/multi_list.rb +++ b/lib/tty/prompt/multi_list.rb @@ -19,7 +19,7 @@ class MultiList < List def initialize(prompt, **options) super @selected = SelectedChoices.new - @select_keys = keys_with_labels(options.fetch(:select_keys, [:space])) + @select_keys = init_action_keys(options.fetch(:select_keys, [:space])) @help = options[:help] @echo = options.fetch(:echo, true) @min = options[:min] diff --git a/spec/unit/select_spec.rb b/spec/unit/select_spec.rb index 7382435..7446399 100644 --- a/spec/unit/select_spec.rb +++ b/spec/unit/select_spec.rb @@ -903,6 +903,40 @@ def exit_message(prompt, choice) expect(actual_prompt_output).to eql(expected_prompt_output) end + it "filters and chooses entry with enter even if only return is passed in submit_keys" do + prompt.input << "g" << "\n" + prompt.input.rewind + + answer = prompt.select("What size?", %i[Small Medium Large Huge], filter: true, submit_keys: [:return]) + expect(answer).to eql(:Large) + + actual_prompt_output = prompt.output.string + expected_prompt_output = + output_helper("What size?", %w[Small Medium Large Huge], "Small", init: true, + hint: "Press #{up_down} arrow to move, Enter to select and letters to filter") + + output_helper("What size?", %w[Large Huge], "Large", hint: "Filter: \"g\"") + + exit_message("What size?", "Large") + + expect(actual_prompt_output).to eql(expected_prompt_output) + end + + it "filters and chooses entry with enter preserving the return key label" do + prompt.input << "g" << "\n" + prompt.input.rewind + + answer = prompt.select("What size?", %i[Small Medium Large Huge], filter: true, submit_keys: [{return: ">ENTER<"}]) + expect(answer).to eql(:Large) + + actual_prompt_output = prompt.output.string + expected_prompt_output = + output_helper("What size?", %w[Small Medium Large Huge], "Small", init: true, + hint: "Press #{up_down} arrow to move, >ENTER< to select and letters to filter") + + output_helper("What size?", %w[Large Huge], "Large", hint: "Filter: \"g\"") + + exit_message("What size?", "Large") + + expect(actual_prompt_output).to eql(expected_prompt_output) + end + it "filters and chooses entry with return and enter, with default key config" do prompt.input << "g" << "\r\n" prompt.input.rewind