class TTY::Prompt::Expander

A class responsible for rendering expanding options Used by {Prompt} to display key options question.

@api private

Constants

DELETE_KEYS

Names for delete keys

HELP_CHOICE

Public Class Methods

new(prompt, options = {}) click to toggle source

Create instance of Expander

@api public

# File lib/tty/prompt/expander.rb, line 24
def initialize(prompt, options = {})
  @prompt       = prompt
  @prefix       = options.fetch(:prefix) { @prompt.prefix }
  @default      = options.fetch(:default, 1)
  @auto_hint    = options.fetch(:auto_hint, false)
  @active_color = options.fetch(:active_color) { @prompt.active_color }
  @help_color   = options.fetch(:help_color) { @prompt.help_color }
  @quiet        = options.fetch(:quiet) { @prompt.quiet }
  @choices      = Choices.new
  @selected     = nil
  @done         = false
  @status       = :collapsed
  @hint         = nil
  @default_key  = false
end

Public Instance Methods

call(message, possibilities, &block) click to toggle source

Execute this prompt

@api public

# File lib/tty/prompt/expander.rb, line 142
def call(message, possibilities, &block)
  choices(possibilities)
  @message = message
  block.call(self) if block
  setup_defaults
  choice(HELP_CHOICE)
  @prompt.subscribe(self) do
    render
  end
end
choice(value, &block) click to toggle source

Add a single choice

@api public

# File lib/tty/prompt/expander.rb, line 121
def choice(value, &block)
  if block
    @choices << value.update(value: block)
  else
    @choices << value
  end
end
choices(values) click to toggle source

Add multiple choices

@param [Array] values

the values to add as choices

@api public

# File lib/tty/prompt/expander.rb, line 135
def choices(values)
  values.each { |val| choice(val) }
end
collapsed?() click to toggle source
# File lib/tty/prompt/expander.rb, line 44
def collapsed?
  @status == :collapsed
end
default(value = (not_set = true)) click to toggle source

Set default value.

@api public

# File lib/tty/prompt/expander.rb, line 105
def default(value = (not_set = true))
  return @default if not_set

  @default = value
end
expand() click to toggle source
# File lib/tty/prompt/expander.rb, line 48
def expand
  @status = :expanded
end
expanded?() click to toggle source
# File lib/tty/prompt/expander.rb, line 40
def expanded?
  @status == :expanded
end
keyenter(_) click to toggle source

Respond to submit event

@api public

# File lib/tty/prompt/expander.rb, line 55
def keyenter(_)
  if @input.nil? || @input.empty?
    @input = @choices[@default - 1].key
    @default_key = true
  end

  selected = select_choice(@input)

  if selected && selected.key.to_s == "h"
    expand
    @selected = nil
    @input = ""
  elsif selected
    @done = true
    @selected = selected
    @hint = nil
  else
    @input = ""
  end
end
Also aliased as: keyreturn
keypress(event) click to toggle source

Respond to key press event

@api public

# File lib/tty/prompt/expander.rb, line 80
def keypress(event)
  if DELETE_KEYS.include?(event.key.name)
    @input.chop! unless @input.empty?
  elsif event.value =~ /^[^\e\n\r]/
    @input += event.value
  end

  @selected = select_choice(@input)
  if @selected && !@default_key && collapsed?
    @hint = @selected.name
  end
end
keyreturn(_)
Alias for: keyenter
quiet(value) click to toggle source

Set quiet mode.

@api public

# File lib/tty/prompt/expander.rb, line 114
def quiet(value)
  @quiet = value
end
select_choice(key) click to toggle source

Select choice by given key

@return [Choice]

@api private

# File lib/tty/prompt/expander.rb, line 98
def select_choice(key)
  @choices.find_by(:key, key)
end

Private Instance Methods

answer() click to toggle source

@api private

# File lib/tty/prompt/expander.rb, line 186
def answer
  @selected.value
end
load_auto_hint() click to toggle source
# File lib/tty/prompt/expander.rb, line 238
def load_auto_hint
  if @hint.nil? && collapsed?
    if @selected
      @hint = @selected.name
    else
      if @input.empty?
        @hint = @choices[@default - 1].name
      else
        @hint = "invalid option"
      end
    end
  end
end
possible_keys() click to toggle source

Create possible keys with current choice highlighted

@return [String]

@api private

# File lib/tty/prompt/expander.rb, line 160
def possible_keys
  keys = @choices.pluck(:key)
  default_key = keys[@default - 1]
  if @selected
    index = keys.index(@selected.key)
    keys[index] = @prompt.decorate(keys[index], @active_color)
  elsif @input.to_s.empty? && default_key
    keys[@default - 1] = @prompt.decorate(default_key, @active_color)
  end
  keys.join(",")
end
read_input() click to toggle source
# File lib/tty/prompt/expander.rb, line 256
def read_input
  @prompt.read_keypress
end
refresh(lines) click to toggle source

Refresh the current input

@param [Integer] lines

@return [String]

@api private

# File lib/tty/prompt/expander.rb, line 267
def refresh(lines)
  if (@hint && (!@selected || @done)) || (@auto_hint && collapsed?)
    @hint = nil
    @prompt.clear_lines(lines, :down) +
      @prompt.cursor.prev_line
  elsif expanded?
    @prompt.clear_lines(lines)
  else
    @prompt.clear_line
  end
end
render() click to toggle source

@api private

# File lib/tty/prompt/expander.rb, line 173
def render
  @input = ""
  until @done
    question = render_question
    @prompt.print(question)
    read_input
    @prompt.print(refresh(question.lines.count))
  end
  @prompt.print(render_question) unless @quiet
  answer
end
render_header() click to toggle source

Render message with options

@return [String]

@api private

# File lib/tty/prompt/expander.rb, line 195
def render_header
  header = ["#{@prefix}#{@message} "]
  if @done
    selected_item = @selected.name.to_s
    header << @prompt.decorate(selected_item, @active_color)
  elsif collapsed?
    header << %[(enter "h" for help) ]
    header << "[#{possible_keys}] "
    header << @input
  end
  header.join
end
render_hint() click to toggle source

Show hint for selected option key

return [String]

@api private

# File lib/tty/prompt/expander.rb, line 213
def render_hint
  "\n" + @prompt.decorate(">> ", @active_color) +
    @hint +
    @prompt.cursor.prev_line +
    @prompt.cursor.forward(@prompt.strip(render_header).size)
end
render_menu() click to toggle source

Render help menu

@api private

# File lib/tty/prompt/expander.rb, line 282
def render_menu
  output = ["\n"]
  @choices.each do |choice|
    chosen = %(#{choice.key} - #{choice.name})
    if @selected && @selected.key == choice.key
      chosen = @prompt.decorate(chosen, @active_color)
    end
    output << "  " + chosen + "\n"
  end
  output.join
end
render_question() click to toggle source

Render question with menu

@return [String]

@api private

# File lib/tty/prompt/expander.rb, line 225
def render_question
  load_auto_hint if @auto_hint
  header = render_header
  header << render_hint if @hint
  header << "\n" if @done

  if !@done && expanded?
    header << render_menu
    header << render_footer
  end
  header
end
setup_defaults() click to toggle source
# File lib/tty/prompt/expander.rb, line 294
def setup_defaults
  validate_choices
end
validate_choices() click to toggle source
# File lib/tty/prompt/expander.rb, line 298
def validate_choices
  errors = []
  keys = []
  @choices.each do |choice|
    if choice.key.nil?
      errors << "Choice #{choice.name} is missing a :key attribute"
      next
    end
    if choice.key.length != 1
      errors << "Choice key `#{choice.key}` is more than one character long."
    end
    if choice.key.to_s == "h"
      errors << "Choice key `#{choice.key}` is reserved for help menu."
    end
    if keys.include?(choice.key)
      errors << "Choice key `#{choice.key}` is a duplicate."
    end
    keys << choice.key if choice.key
  end
  errors.each { |err| raise ConfigurationError, err }
end