class TTY::Prompt::Expander

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

@api private

Constants

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 21
def initialize(prompt, options = {})
  @prompt       = prompt
  @prefix       = options.fetch(:prefix) { @prompt.prefix }
  @default      = options.fetch(:default) { 1 }
  @active_color = options.fetch(:active_color) { @prompt.active_color }
  @help_color   = options.fetch(:help_color) { @prompt.help_color }
  @choices      = Choices.new
  @selected     = nil
  @done         = false
  @status       = :collapsed
  @hint         = nil
  @default_key  = false

  @prompt.subscribe(self)
end

Public Instance Methods

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

Execute this prompt

@api public

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

Add a single choice

@api public

# File lib/tty/prompt/expander.rb, line 108
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 122
def choices(values)
  values.each { |val| choice(val) }
end
collapsed?() click to toggle source
# File lib/tty/prompt/expander.rb, line 41
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 100
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 45
def expand
  @status = :expanded
end
expanded?() click to toggle source
# File lib/tty/prompt/expander.rb, line 37
def expanded?
  @status == :expanded
end
keyenter(_) click to toggle source

Respond to submit event

@api public

# File lib/tty/prompt/expander.rb, line 52
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
  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 76
def keypress(event)
  if [:backspace, :delete].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
select_choice(key) click to toggle source

Select choice by given key

@return [Choice]

@api private

# File lib/tty/prompt/expander.rb, line 93
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 171
def answer
  @selected.value
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 145
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 227
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 238
def refresh(lines)
  if @hint && (!@selected || @done)
    @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 158
def render
  @input = ''
  until @done
    question = render_question
    @prompt.print(question)
    read_input
    @prompt.print(refresh(question.lines.count))
  end
  @prompt.print(render_question)
  answer
end
render_header() click to toggle source

Render message with options

@return [String]

@api private

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

Show hint for selected option key

return [String]

@api private

# File lib/tty/prompt/expander.rb, line 198
def render_hint
  hint = "\n"
  hint << @prompt.decorate('>> ', @active_color)
  hint << @hint
  hint << @prompt.cursor.prev_line
  hint << @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 253
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
end
render_question() click to toggle source

Render question with menu

@return [String]

@api private

# File lib/tty/prompt/expander.rb, line 211
def render_question
  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 265
def setup_defaults
  validate_choices
end
validate_choices() click to toggle source
# File lib/tty/prompt/expander.rb, line 269
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| fail ConfigurationError, err }
end