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