module PandaPal module ConsoleHelpers extend self COLORS = { "black" => 0, "red" => 1, "green" => 2, "yellow" => 3, "blue" => 4, "purple" => 5, "magenta" => 5, "cyan" => 6, "white" => 7 }.freeze COLORS.each_pair do |color, value| define_method color do |text| "\033[0;#{30 + value}m#{text}\033[0m" end define_method "bright_#{color}" do |text| "\033[1;#{30 + value}m#{text}\033[0m" end end def pandapalrc # TODO Consider searching app and parent dirs before ~/ @pandapalrc ||= YAML.load(File.read(File.expand_path("~/pandapalrc.yml"))) rescue {} end def prompt(prompt = "", default: nil) prompt = prompt + " (#{default})" if default.present? puts prompt print "> " v = STDIN.gets.chomp.downcase return default if v == "" v end def prompt_options(options, prompt = "", default: nil) options = options.map(&:to_s) prompt = prompt + " (" + options.map { |o| o == default ? o.capitalize : o }.join("/") + ")" i = 0 loop do puts prompt print "> " i += 1 v = STDIN.gets.chomp.downcase return v if options.include?(v) return default if v == "" return nil if i > 3 puts "Invalid Input." end end def prompt_yes_no(prompt = "", default: true) result = prompt_options(["y", "n"], prompt, default: default ? "y" : "n") return true if result == "y" return false if result == "n" result end def prompt_pry_retry(prompt = "Retry?", default: false) default = default ? "y" : "n" unless default.is_a?(String) result = prompt_options(["y", "n", "pry"], prompt, default: default ? "y" : "n") if result == "pry" binding.pry return true end return true if result == "y" return false if result == "n" result end def open_editor(file_path) raise "EDITOR environment variable not set" unless ENV["EDITOR"].present? args = Shellwords.shellwords(ENV['EDITOR']) args << file_path Kernel::system(*args) end def open_string_editor(string, file: nil, name: nil, require_save: true) file_obj = file.present? ? File.new(file) : Tempfile.new([File.basename(name, File.extname(name)), File.extname(name)]) File.open(file_obj.path, 'w') { |f| f.write(string) } mtime = File.stat(file_obj.path).mtime path = file_obj.path file_obj.close rescue nil open_editor(path) return :aborted unless !require_save || mtime < File.stat(file_obj.path).mtime File.read(path) end class CodeBuilder def initialize(indent: 0) @code = "" @line_prefix = [" "] * indent end def <<(line) if line.is_a?(Array) line.each do |l| self << l end else bits = line.split("\n", -1) push_bit(bits.shift) bits.each do |bit| @code << "\n" push_bit(bit) end end end def ensure_line return if @code.end_with?("\n") @code << "\n" end def block(char = nil) indent!(char) yield ensure dedent! end def indent!(char = nil) @line_prefix << (char || " ") end def dedent! @line_prefix.pop end def to_s @code end protected def push_bit(bit) return unless bit.present? @code << @line_prefix.join if @code.end_with?("\n") @code << bit end end end end