class Djinni
Attributes
fallback[RW]
Public Class Methods
new(interactive = false)
click to toggle source
# File lib/djinni.rb, line 201 def initialize(interactive = false) @fallback = nil @hist_index = nil @history = Array.new @interactive = interactive @loaded_from = Array.new @width = %x(tput cols).to_i @wishes = Hash.new Signal.trap( "WINCH", proc do @width = %x(tput cols).to_i end ) load_wishes("#{File.dirname(__FILE__)}/djinni/wish") end
Public Instance Methods
grant_wish(input, djinni_env = {})
click to toggle source
# File lib/djinni.rb, line 7 def grant_wish(input, djinni_env = {}) return "" if (input.nil? || input.empty?) djinni_env["djinni"] = self djinni_env["djinni_history"] = @history djinni_env["djinni_wishes"] = @wishes space = 4 case input[-1] when "\x03" # ^C puts if (@interactive) return "" when "\x04" # ^D return "\x04" when "\x7F", "\b" # Backspace or ^H return input[0..-3] when "\f" # ^L system("clear") if (@interactive) return input[0..-2] when "\t" # Tab input = input[0..-2] if (input.include?(" ")) name, args = input.split(" ", 2) return input if (!@wishes.has_key?(name)) begin wish = @wishes[name] djinni_env["djinni_input"] = name completions, replace, append = wish.tab_complete( args, djinni_env ) rescue SystemExit => e raise e rescue Exception => e puts puts e.message ensure append ||= " " completions ||= Hash.new replace ||= "" end return input if (completions.empty?) if (completions.length == 1) return input.gsub( /#{replace}$/, "#{completions.first.first}#{append}" ) end max = completions.keys.max_by(&:length).length nlfill = "" nlfill = " " * (max + space) if ((max + space) > 0) width = @width - (max + space) - 2 puts completions.each do |item, desc| desc ||= "" fill = "" if ((max + space - item.length) > 0) fill = " " * (max + space - item.length) end lines = desc.scan( /\S.{0,#{width}}\S(?=\s|$)|\S+/ ) if (lines.empty?) puts item else start = lines.delete_at(0) puts "#{item}#{fill}#{start}" lines.each do |line| puts "#{nlfill}#{line}" end end end longest = longest_common_substring(completions.keys) return input if (longest.empty?) return input.gsub(/#{replace}$/, longest) else wishes = @wishes.select do |aliaz, w| aliaz.start_with?(input) end return input if (wishes.empty?) if (wishes.length == 1) return "#{wishes.first.first} " end max = wishes.keys.max_by(&:length).length nlfill = "" nlfill = " " * (max + space) if ((max + space) > 0) width = @width - (max + space) - 2 puts wishes.sort do |a, b| a.first.downcase <=> b.first.downcase end.each do |aliaz, w| fill = "" if ((max + space - aliaz.length) > 0) fill = " " * (max + space - aliaz.length) end lines = w.description.scan( /\S.{0,#{width}}\S(?=\s|$)|\S+/ ) if (lines.empty?) puts aliaz else start = lines.delete_at(0) puts "#{aliaz}#{fill}#{start}" lines.each do |line| puts "#{nlfill}#{line}" end end end return longest_common_substring(wishes.keys) end when /\r|\n/ # Enter input.strip! puts if (@interactive) return "" if (input.empty?) # "".split(" ", 2) => [] aka [nil, nil] # " ".split(" ", 2) => [""] aka ["", nil] # The above 2 would return before getting here # "string".split(" ", 2) => ["string"] aka ["string", nil] # "string ".split(" ", 2) => ["string", ""] name, args = input.split(" ", 2) args ||= "" @wishes.select do |aliaz, w| aliaz == name end.each do |aliaz, w| begin djinni_env["djinni_input"] = name w.execute(args, djinni_env) rescue SystemExit => e raise e rescue Exception => e puts e.message end if (w.class.to_s != "Djinni::Wish::History") store_history(input) end return "" end store_history(input) return nil when "\e" # Arrow keys code = "\e" t = Thread.new do code += STDIN.getch + STDIN.getch end t.join(0.001) if (t) t.kill if (t) case code when /\e[\[O]A/ # Up arrow return "" if (@history.empty?) @hist_index = @history.size if (@hist_index.nil?) @hist_index = 1 if (@hist_index == 0) @hist_index -= 1 return @history[@hist_index] when /\e[\[O]B/ # Down arrow @hist_index = @history.size if (@hist_index.nil?) @hist_index += 1 if (@hist_index < @history.size) return @history[@hist_index] else @hist_index = @history.size return "" end when /\e[\[O]C/ # Right arrow # TODO maybe implement right arrow return input[0..-2] when /\e[\[O]D/ # Left arrow # TODO maybe implement left arrow return input[0..-2] else return input[0..-2] end else return input end end
load_wishes(dir)
click to toggle source
# File lib/djinni.rb, line 220 def load_wishes(dir) return if @loaded_from.include?(dir) classes = Fagin.find_children("Djinni::Wish", dir) classes.each do |clas, wish| w = wish.new w.aliases.each do |aliaz| @wishes[aliaz] = w end end @loaded_from.push(dir) end
prompt(djinni_env = {}, djinni_prompt = "$ ")
click to toggle source
# File lib/djinni.rb, line 249 def prompt(djinni_env = {}, djinni_prompt = "$ ") @interactive = true djinni_env["djinni_prompt"] = djinni_prompt prev_len = 0 buff = "" loop do djinni_prompt = djinni_env["djinni_prompt"] blank_line = "" blank_line = " " * @width if (@width > 0) # Handle long lines that get wrapped buff_len = remove_colors(djinni_prompt).length + prev_len lines = buff_len / @width lines -= 1 if ((buff_len % @width) == 0) lines.times do print "\r#{blank_line}" print "\e[F" end # Redisplay prompt print "\r#{blank_line}" print "\r#{djinni_prompt}#{buff}" # Process input input = nil system("stty raw -echo") while (input.nil?) begin input = STDIN.getch rescue puts if (@interactive) end end system("stty -raw echo") prev_len = remove_colors(buff).length save = buff buff = grant_wish(buff + input, djinni_env) if (buff.nil? && !@fallback.nil? && !@fallback.empty?) puts "\e[2A" buff = grant_wish( @fallback + " " + save + input, djinni_env ) end if (buff.nil?) puts "Command not found!" buff = "" end # Exit on ^D if (buff == "\x04") return end end end
Private Instance Methods
longest_common_substring(array)
click to toggle source
# File lib/djinni.rb, line 234 def longest_common_substring(array) compare = array.min_by(&:length) compare ||= "" loop do break if (compare.empty?) all = array.all? do |item| item.downcase.start_with?(compare.downcase) end compare = compare[0..-2] if (!all) break if (all) end return compare end
remove_colors(str)
click to toggle source
# File lib/djinni.rb, line 307 def remove_colors(str) str.unpack("C*").pack("U*").gsub(/\e\[([0-9;]*m|K)/, "") end
store_history(input)
click to toggle source
# File lib/djinni.rb, line 312 def store_history(input) # Only keep newest wish if repeat # @history.delete(input) @history.push(input) @hist_index = nil end