class TTY::Prompt::Expander
@api private
Used by {Prompt} to display key options question.
A class responsible for rendering expanding options
def call(message, possibilities, &block)
- Api: - public
def call(message, possibilities, &block) choices(possibilities) @message = message block.call(self) if block setup_defaults choice(HELP_CHOICE) render end
def choice(value, &block)
- Api: - public
def choice(value, &block) if block @choices << value.update(value: block) else @choices << value end end
def choices(values)
- Api: - public
Parameters:
-
values(Array[Object]) --
def choices(values) values.each { |val| choice(val) } end
def collapsed?
def collapsed? @status == :collapsed end
def count_lines
- Api: - private
def count_lines lines = render_header.scan("\n").length + 1 if @hint lines += @hint.scan("\n").length + 1 elsif expanded? lines += @choices.length lines += render_footer.scan("\n").length + 1 end lines end
def default(value = (not_set = true))
- Api: - public
def default(value = (not_set = true)) return @default if not_set @default = value end
def expand
def expand @status = :expanded end
def expanded?
def expanded? @status == :expanded end
def initialize(prompt, options = {})
- Api: - public
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
def keyenter(_)
- Api: - public
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
def keypress(event)
- Api: - public
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
def possible_keys
- Api: - private
Returns:
-
(String)-
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
def read_input
def read_input @prompt.read_keypress end
def refresh
- Api: - private
def refresh lines = count_lines if @hint && (!@selected || @done) @hint = nil @prompt.print(@prompt.clear_lines(lines, :down)) @prompt.print(@prompt.cursor.prev_line) elsif expanded? @prompt.print(@prompt.clear_lines(lines)) else @prompt.print(@prompt.clear_line) end end
def render
- Api: - private
def render @input = '' until @done render_question read_input refresh end render_question render_answer end
def render_answer
- Api: - private
def render_answer @selected.value end
def render_footer
def render_footer " Choice [#{@choices[@default - 1].key}]: #{@input}" end
def render_header
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
def render_hint
- Api: - private
def render_hint hint = "\n" hint << @prompt.decorate('>> ', @active_color) hint << @hint @prompt.print(hint) @prompt.print(@prompt.cursor.prev_line) @prompt.print(@prompt.cursor.forward(@prompt.strip(render_header).size)) end
def render_menu
- Api: - private
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
def render_question
- Api: - private
def render_question header = render_header @prompt.print(header) render_hint if @hint @prompt.print("\n") if @done if !@done && expanded? @prompt.print(render_menu) @prompt.print(render_footer) end end
def select_choice(key)
- Api: - private
Returns:
-
(Choice)-
def select_choice(key) @choices.find_by(:key, key) end
def setup_defaults
def setup_defaults validate_choices end
def validate_choices
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