lib/app/menu.rb (86 lines of code) (raw):
#
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
# or more contributor license agreements. Licensed under the Elastic License;
# you may not use this file except in compliance with the Elastic License.
#
# frozen_string_literal: true
#
require 'remedy'
module App
class Menu
attr_reader :items
attr_reader :title
attr_reader :index
def initialize(title, items)
super()
@index = 0
@title = title
@items = items.map.with_index do |item, i|
item.is_a?(String) ? MenuItem.new(item, nil, i == 0) : MenuItem.new(item[:command], item[:hint], i == 0)
end
end
def select_item(index)
@index = index
@items.each_with_index { |item, i| item.selected = (i == index) }
display
end
def select_command
display
interaction = Remedy::Interaction.new
interaction.loop do |key|
if key.nil?
break
end
case key.to_s.to_sym
when :down
index = @index + 1
index = 0 if index >= @items.size
select_item(index)
when :up
index = @index - 1
index = 0 if index < 0
select_item(index)
when :control_m
return @items[@index].command
end
end
end
private
def display
clear_screen
puts(title)
@items.each do |item|
print(item.selected ? '--> ' : ' ')
puts item.hint.present? ? "#{item.hint} (#{item.command})" : item.command
end
end
def clear_screen
system('clear') || system('cls')
end
def read_char
STDIN.echo = false
STDIN.raw!
input = STDIN.getc
if input == "\e"
begin
input << STDIN.read_nonblock(3)
rescue StandardError
nil
end
begin
input << STDIN.read_nonblock(2)
rescue StandardError
nil
end
end
input
ensure
STDIN.echo = true
STDIN.cooked!
end
end
class MenuItem
attr_reader :command
attr_reader :hint
attr_accessor :selected
def initialize(command, hint = nil, selected = false)
super()
@command = command
@hint = hint
@selected = selected
end
end
end