2011-04-12 20:48:50 -04:00
|
|
|
class Pry
|
|
|
|
class CommandBase
|
|
|
|
module CommandBaseHelpers
|
|
|
|
|
2011-04-22 01:12:32 -04:00
|
|
|
private
|
2011-04-18 17:31:39 -04:00
|
|
|
|
2011-04-19 06:37:10 -04:00
|
|
|
def gem_installed?(gem_name)
|
2011-04-12 20:48:50 -04:00
|
|
|
require 'rubygems'
|
|
|
|
!!Gem.source_index.find_name(gem_name).first
|
|
|
|
end
|
|
|
|
|
|
|
|
def command_dependencies_met?(options)
|
|
|
|
return true if !options[:requires_gem]
|
|
|
|
Array(options[:requires_gem]).all? do |g|
|
|
|
|
gem_installed?(g)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def stub_proc(name, options)
|
|
|
|
gems_needed = Array(options[:requires_gem])
|
|
|
|
gems_not_installed = gems_needed.select { |g| !gem_installed?(g) }
|
|
|
|
proc do
|
|
|
|
output.puts "\n`#{name}` requires the following gems to be installed: `#{gems_needed.join(", ")}`"
|
|
|
|
output.puts "Command not available due to dependency on gems: `#{gems_not_installed.join(", ")}` not being met."
|
|
|
|
output.puts "Type `install #{name}` to install the required gems and activate this command."
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def create_command_stub(names, description, options, block)
|
|
|
|
Array(names).each do |name|
|
|
|
|
commands[name] = {
|
|
|
|
:description => "Not available. Execute `#{name}` command for more information.",
|
|
|
|
:action => stub_proc(name, options),
|
|
|
|
:stub_info => options
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-04-18 15:11:46 -04:00
|
|
|
#
|
|
|
|
# Color helpers:
|
|
|
|
# gray, red, green, yellow, blue, purple, cyan, white,
|
|
|
|
# and bright_red, bright_green, etc...
|
|
|
|
#
|
|
|
|
# ANSI color codes:
|
|
|
|
# \033 => escape
|
|
|
|
# 30 => color base
|
|
|
|
# 1 => bright
|
|
|
|
# 0 => normal
|
|
|
|
#
|
2011-04-18 17:31:39 -04:00
|
|
|
|
2011-04-22 02:47:06 -04:00
|
|
|
COLORS = {
|
|
|
|
"black" => 0,
|
|
|
|
"red" => 1,
|
|
|
|
"green" => 2,
|
|
|
|
"yellow" => 3,
|
|
|
|
"blue" => 4,
|
|
|
|
"purple" => 5,
|
|
|
|
"magenta" => 5,
|
|
|
|
"cyan" => 6,
|
|
|
|
"white" => 7
|
|
|
|
}
|
|
|
|
|
|
|
|
COLORS.each do |color, i|
|
2011-04-18 15:11:46 -04:00
|
|
|
define_method color do |str|
|
|
|
|
Pry.color ? "\033[0;#{30+i}m#{str}\033[0m" : str
|
|
|
|
end
|
2011-04-22 02:47:06 -04:00
|
|
|
|
|
|
|
define_method "bright_#{color}" do |str|
|
|
|
|
Pry.color ? "\033[1;#{30+i}m#{str}\033[0m" : str
|
|
|
|
end
|
2011-04-18 15:11:46 -04:00
|
|
|
end
|
2011-04-22 02:47:06 -04:00
|
|
|
|
2011-04-22 01:12:32 -04:00
|
|
|
alias_method :grey, :bright_black
|
|
|
|
alias_method :gray, :bright_black
|
2011-04-18 17:31:39 -04:00
|
|
|
|
2011-04-22 02:47:06 -04:00
|
|
|
require 'set'
|
|
|
|
VALID_COLORS = Set.new(
|
|
|
|
COLORS.keys +
|
|
|
|
COLORS.keys.map{|k| "bright_#{k}" } +
|
|
|
|
["grey", "gray"]
|
|
|
|
)
|
|
|
|
|
2011-04-13 01:16:12 -04:00
|
|
|
def bold(text)
|
|
|
|
Pry.color ? "\e[1m#{text}\e[0m" : text
|
|
|
|
end
|
|
|
|
|
2011-04-22 01:12:32 -04:00
|
|
|
#
|
|
|
|
# Colorize a string that has "color tags".
|
|
|
|
#
|
|
|
|
# Examples:
|
|
|
|
# puts colorize("<light_green><magenta>*</magenta> Hey mom! I am <light_blue>SO</light_blue> colored right now.</light_green>")
|
|
|
|
#
|
|
|
|
def colorize(string)
|
|
|
|
stack = []
|
|
|
|
|
|
|
|
# split the string into tags and literal strings
|
|
|
|
tokens = string.split(/(<\/?[\w\d_]+>)/)
|
|
|
|
tokens.delete_if { |token| token.size == 0 }
|
|
|
|
|
|
|
|
result = ""
|
|
|
|
|
|
|
|
tokens.each do |token|
|
|
|
|
|
|
|
|
# token is an opening tag!
|
|
|
|
|
2011-04-22 02:47:06 -04:00
|
|
|
if /<([\w\d_]+)>/ =~ token and VALID_COLORS.include?($1) #valid_tag?($1)
|
2011-04-22 01:12:32 -04:00
|
|
|
stack.push $1
|
|
|
|
|
|
|
|
# token is a closing tag!
|
|
|
|
|
2011-04-22 02:47:06 -04:00
|
|
|
elsif /<\/([\w\d_]+)>/ =~ token and VALID_COLORS.include?($1) # valid_tag?($1)
|
2011-04-22 01:12:32 -04:00
|
|
|
|
|
|
|
# if this color is on the stack somwehere...
|
|
|
|
if pos = stack.rindex($1)
|
|
|
|
# close the tag by removing it from the stack
|
|
|
|
stack.delete_at pos
|
|
|
|
else
|
|
|
|
raise "Error: tried to close an unopened color tag -- #{token}"
|
|
|
|
end
|
|
|
|
|
|
|
|
# token is a literal string!
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
color = (stack.last || "white")
|
|
|
|
#color = BBS_COLOR_TABLE[color.to_i] if color =~ /^\d+$/
|
|
|
|
result << send(color, token) # colorize the result
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
def highlight(string, regexp, highlight_color=:bright_yellow)
|
|
|
|
highlighted = string.gsub(regexp) { |match| "<#{highlight_color}>#{match}</#{highlight_color}>" }
|
|
|
|
end
|
|
|
|
|
2011-04-13 01:16:12 -04:00
|
|
|
# formatting
|
|
|
|
def heading(text)
|
|
|
|
text = "#{text}\n--"
|
|
|
|
Pry.color ? "\e[1m#{text}\e[0m": text
|
|
|
|
end
|
|
|
|
|
|
|
|
def page_size
|
|
|
|
27
|
|
|
|
end
|
2011-04-18 17:31:39 -04:00
|
|
|
|
2011-04-13 01:16:12 -04:00
|
|
|
# a simple pager for systems without `less`. A la windows.
|
|
|
|
def simple_pager(text)
|
|
|
|
text_array = text.lines.to_a
|
|
|
|
text_array.each_slice(page_size) do |chunk|
|
|
|
|
output.puts chunk.join
|
|
|
|
break if chunk.size < page_size
|
|
|
|
if text_array.size > page_size
|
2011-04-18 17:31:39 -04:00
|
|
|
output.puts "\n<page break> --- Press enter to continue ( q<enter> to break ) --- <page break>"
|
2011-04-13 01:16:12 -04:00
|
|
|
break if $stdin.gets.chomp == "q"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2011-04-18 17:31:39 -04:00
|
|
|
|
2011-04-18 10:11:00 -04:00
|
|
|
# Try to use `less` for paging, if it fails then use
|
|
|
|
# simple_pager. Also do not page if Pry.pager is falsey
|
2011-04-23 11:45:36 -04:00
|
|
|
# FIXME! Another JRuby hack
|
2011-04-13 01:16:12 -04:00
|
|
|
def stagger_output(text)
|
2011-04-18 10:11:00 -04:00
|
|
|
if text.lines.count < page_size || !Pry.pager
|
2011-04-13 01:16:12 -04:00
|
|
|
output.puts text
|
|
|
|
return
|
|
|
|
end
|
2011-04-23 11:45:36 -04:00
|
|
|
|
|
|
|
# FIXME! Another JRuby hack
|
2011-04-23 20:26:08 -04:00
|
|
|
if Object.const_defined?(:RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
|
2011-04-23 11:45:36 -04:00
|
|
|
simple_pager(text)
|
|
|
|
else
|
|
|
|
lesspipe { |less| less.puts text }
|
|
|
|
end
|
2011-04-19 06:37:10 -04:00
|
|
|
rescue Errno::ENOENT
|
2011-04-13 01:16:12 -04:00
|
|
|
simple_pager(text)
|
2011-04-19 06:37:10 -04:00
|
|
|
rescue Errno::EPIPE
|
2011-04-13 01:16:12 -04:00
|
|
|
end
|
2011-04-22 01:12:32 -04:00
|
|
|
|
2011-04-18 18:33:42 -04:00
|
|
|
#
|
|
|
|
# Create scrollable output via less!
|
|
|
|
#
|
|
|
|
# This command runs `less` in a subprocess, and gives you the IO to its STDIN pipe
|
|
|
|
# so that you can communicate with it.
|
|
|
|
#
|
|
|
|
# Example:
|
|
|
|
#
|
|
|
|
# lesspipe do |less|
|
|
|
|
# 50.times { less.puts "Hi mom!" }
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# The default less parameters are:
|
|
|
|
# * Allow colour
|
|
|
|
# * Don't wrap lines longer than the screen
|
|
|
|
# * Quit immediately (without paging) if there's less than one screen of text.
|
2011-04-22 01:12:32 -04:00
|
|
|
#
|
2011-04-18 18:33:42 -04:00
|
|
|
# You can change these options by passing a hash to `lesspipe`, like so:
|
|
|
|
#
|
|
|
|
# lesspipe(:wrap=>false) { |less| less.puts essay.to_s }
|
|
|
|
#
|
|
|
|
# It accepts the following boolean options:
|
|
|
|
# :color => Allow ANSI colour codes?
|
|
|
|
# :wrap => Wrap long lines?
|
|
|
|
# :always => Always page, even if there's less than one page of text?
|
|
|
|
#
|
2011-04-13 01:16:12 -04:00
|
|
|
def lesspipe(*args)
|
|
|
|
if args.any? and args.last.is_a?(Hash)
|
|
|
|
options = args.pop
|
|
|
|
else
|
|
|
|
options = {}
|
|
|
|
end
|
2011-04-18 17:31:39 -04:00
|
|
|
|
2011-04-13 01:16:12 -04:00
|
|
|
output = args.first if args.any?
|
2011-04-18 17:31:39 -04:00
|
|
|
|
2011-04-13 01:16:12 -04:00
|
|
|
params = []
|
|
|
|
params << "-R" unless options[:color] == false
|
|
|
|
params << "-S" unless options[:wrap] == true
|
|
|
|
params << "-F" unless options[:always] == true
|
|
|
|
if options[:tail] == true
|
|
|
|
params << "+\\>"
|
|
|
|
$stderr.puts "Seeking to end of stream..."
|
|
|
|
end
|
|
|
|
params << "-X"
|
2011-04-18 17:31:39 -04:00
|
|
|
|
2011-04-13 01:16:12 -04:00
|
|
|
IO.popen("less #{params * ' '}", "w") do |less|
|
|
|
|
if output
|
|
|
|
less.puts output
|
|
|
|
else
|
|
|
|
yield less
|
|
|
|
end
|
|
|
|
end
|
2011-04-18 17:31:39 -04:00
|
|
|
end
|
2011-04-13 01:16:12 -04:00
|
|
|
|
2011-04-12 20:48:50 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-04-18 17:31:39 -04:00
|
|
|
|