class TTY::Prompt::MultiList

A class responsible for rendering multi select list menu. Used by {Prompt} to display interactive choice menu.

@api private

Public Class Methods

new(prompt, **options) click to toggle source

Create instance of TTY::Prompt::MultiList menu.

@param [Prompt] :prompt @param [Hash] options

@api public

Calls superclass method TTY::Prompt::List.new
# File lib/tty/prompt/multi_list.rb, line 18
def initialize(prompt, **options)
  super
  @selected = SelectedChoices.new
  @help = options[:help]
  @echo = options.fetch(:echo, true)
  @min  = options[:min]
  @max  = options[:max]
end

Public Instance Methods

keyctrl_a(*) click to toggle source

Selects all choices when Ctrl+A is pressed

@api private

# File lib/tty/prompt/multi_list.rb, line 70
def keyctrl_a(*)
  return if @max && @max < choices.size

  @selected = SelectedChoices.new(choices.enabled, choices.enabled_indexes)
end
keyctrl_r(*) click to toggle source

Revert currently selected choices when Ctrl+I is pressed

@api private

# File lib/tty/prompt/multi_list.rb, line 79
def keyctrl_r(*)
  return if @max && @max < choices.size

  indexes = choices.each_with_index.reduce([]) do |acc, (choice, idx)|
              acc << idx if !choice.disabled? && !@selected.include?(choice)
              acc
            end
  @selected = SelectedChoices.new(choices.enabled - @selected.to_a, indexes)
end
keyenter(*) click to toggle source

Callback fired when enter/return key is pressed

@api private

Calls superclass method TTY::Prompt::List#keyenter
# File lib/tty/prompt/multi_list.rb, line 44
def keyenter(*)
  valid = true
  valid = @min <= @selected.size if @min
  valid = @selected.size <= @max if @max

  super if valid
end
Also aliased as: keyreturn
keyreturn(*)
Alias for: keyenter
keyspace(*) click to toggle source

Callback fired when space key is pressed

@api private

# File lib/tty/prompt/multi_list.rb, line 56
def keyspace(*)
  active_choice = choices[@active - 1]
  if @selected.include?(active_choice)
    @selected.delete_at(@active - 1)
  else
    return if @max && @selected.size >= @max

    @selected.insert(@active - 1, active_choice)
  end
end
max(value) click to toggle source

Set a maximum number of choices

@api public

# File lib/tty/prompt/multi_list.rb, line 37
def max(value)
  @max = value
end
min(value) click to toggle source

Set a minimum number of choices

@api public

# File lib/tty/prompt/multi_list.rb, line 30
def min(value)
  @min = value
end

Private Instance Methods

answer() click to toggle source

All values for the choices selected

@return [Array]

@api private

# File lib/tty/prompt/multi_list.rb, line 188
def answer
  @selected.map(&:value)
end
default_help() click to toggle source

Build a default help text

@return [String]

@api private

# File lib/tty/prompt/multi_list.rb, line 143
def default_help
  str = []
  str << "(Press "
  str << "#{arrows_help} arrow"
  str << " or 1-#{choices.size} number" if enumerate?
  str << " to move, Space"
  str << "/Ctrl+A|R" if @max.nil?
  str << " to select"
  str << " (all|rev)" if @max.nil?
  str << (filterable? ? "," : " and")
  str << " Enter to finish"
  str << " and letters to filter" if filterable?
  str << ")"
  str.join
end
minmax_help() click to toggle source

Header part showing the minimum/maximum number of choices

@return [String]

@api private

# File lib/tty/prompt/multi_list.rb, line 131
def minmax_help
  help = []
  help << "min. #{@min}" if @min
  help << "max. #{@max}" if @max
  "(%s) " % [help.join(", ")]
end
render_header() click to toggle source

Render initial help text and then currently selected choices

@api private

# File lib/tty/prompt/multi_list.rb, line 162
def render_header
  instructions = @prompt.decorate(help, @help_color)
  minmax_suffix = @min || @max ? minmax_help : ""
  print_selected = @selected.size.nonzero? && @echo

  if @done && @echo
    @prompt.decorate(selected_names, @active_color)
  elsif (@first_render && (help_start? || help_always?)) ||
        (help_always? && !@filter.any? && !@done)
    minmax_suffix +
      (print_selected ? "#{selected_names} " : "") +
      instructions
  elsif filterable? && @filter.any?
    minmax_suffix +
      (print_selected ? "#{selected_names} " : "") +
      @prompt.decorate(filter_help, @help_color)
  else
    minmax_suffix + (print_selected ? selected_names : "")
  end
end
render_menu() click to toggle source

Render menu with choices to select from

@return [String]

@api private

# File lib/tty/prompt/multi_list.rb, line 197
def render_menu
  output = []

  sync_paginators if @paging_changed
  paginator.paginate(choices, @active, @per_page) do |choice, index|
    num = enumerate? ? (index + 1).to_s + @enum + " " : ""
    indicator = (index + 1 == @active) ?  @symbols[:marker] : " "
    indicator += " "
    message = if @selected.include?(choice) && !choice.disabled?
                selected = @prompt.decorate(@symbols[:radio_on], @active_color)
                "#{selected} #{num}#{choice.name}"
              elsif choice.disabled?
                @prompt.decorate(@symbols[:cross], :red) +
                  " #{num}#{choice.name} #{choice.disabled}"
              else
                "#{@symbols[:radio_off]} #{num}#{choice.name}"
              end
    end_index = paginated? ? paginator.end_index : choices.size - 1
    newline = (index == end_index) ? "" : "\n"
    output << indicator + message + newline
  end

  output.join
end
selected_names() click to toggle source

Generate selected items names

@return [String]

@api private

# File lib/tty/prompt/multi_list.rb, line 122
def selected_names
  @selected.map(&:name).join(", ")
end
setup_defaults() click to toggle source

Setup default options and active selection

@api private

# File lib/tty/prompt/multi_list.rb, line 94
def setup_defaults
  validate_defaults
  # At this stage, @choices matches all the visible choices.
  default_indexes = @default.map do |d|
    if d.to_s =~ INTEGER_MATCHER
      d - 1
    else
      choices.index(choices.find_by(:name, d.to_s))
    end
  end
  @selected = SelectedChoices.new(@choices.values_at(*default_indexes),
                                  default_indexes)

  if @default.empty?
    # no default, pick the first non-disabled choice
    @active = choices.index { |choice| !choice.disabled? } + 1
  elsif @default.last.to_s =~ INTEGER_MATCHER
    @active = @default.last
  elsif default_choice = choices.find_by(:name, @default.last.to_s)
    @active = choices.index(default_choice) + 1
  end
end