2012-12-20 04:28:04 -05:00
|
|
|
require 'forwardable'
|
2012-12-21 03:02:13 -05:00
|
|
|
|
2012-12-20 04:28:04 -05:00
|
|
|
class Pry
|
2012-12-21 03:02:13 -05:00
|
|
|
class REPL
|
2012-12-20 04:28:04 -05:00
|
|
|
extend Forwardable
|
|
|
|
attr_accessor :pry
|
|
|
|
|
2012-12-28 16:35:14 -05:00
|
|
|
def_delegators :pry, :input, :output
|
2012-12-20 04:28:04 -05:00
|
|
|
|
2012-12-28 19:24:07 -05:00
|
|
|
# Start a new Pry::REPL wrapping a pry created with the given options.
|
|
|
|
#
|
|
|
|
# @option options (see Pry#initialize)
|
2012-12-20 04:28:04 -05:00
|
|
|
def self.start(options)
|
2012-12-23 03:08:40 -05:00
|
|
|
new(Pry.new(options)).start
|
2012-12-20 04:28:04 -05:00
|
|
|
end
|
|
|
|
|
2012-12-28 19:24:07 -05:00
|
|
|
# Create a new REPL.
|
|
|
|
#
|
|
|
|
# @param [Pry] pry The instance of pry in which to eval code.
|
|
|
|
# @option options [Object] :target The target to REPL on.
|
2012-12-23 03:08:40 -05:00
|
|
|
def initialize(pry, options = {})
|
|
|
|
@pry = pry
|
|
|
|
@indent = Pry::Indent.new
|
|
|
|
|
|
|
|
if options[:target]
|
2012-12-22 01:06:41 -05:00
|
|
|
@pry.push_binding options[:target]
|
|
|
|
end
|
2012-12-20 04:28:04 -05:00
|
|
|
end
|
|
|
|
|
2012-12-28 19:24:07 -05:00
|
|
|
# Start the read-eval-print-loop.
|
|
|
|
#
|
|
|
|
# @return [Object] anything returned by the user from within Pry
|
|
|
|
# @raise [Exception] anything raise-up'd by the user from within Pry
|
2012-12-21 03:02:13 -05:00
|
|
|
def start
|
2012-12-28 01:10:44 -05:00
|
|
|
prologue
|
2012-12-28 17:19:42 -05:00
|
|
|
repl
|
2012-12-20 04:28:04 -05:00
|
|
|
ensure
|
2012-12-28 01:10:44 -05:00
|
|
|
epilogue
|
2012-12-20 04:28:04 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2012-12-28 19:24:07 -05:00
|
|
|
# Set up the repl session
|
2012-12-28 01:10:44 -05:00
|
|
|
def prologue
|
2012-12-21 04:38:32 -05:00
|
|
|
pry.exec_hook :before_session, pry.output, pry.current_binding, pry
|
2012-12-20 04:28:04 -05:00
|
|
|
# Clear the line before starting Pry. This fixes the issue discussed here:
|
|
|
|
# https://github.com/pry/pry/issues/566
|
2012-12-28 18:59:41 -05:00
|
|
|
if Pry.config.correct_indent
|
2012-12-20 04:28:04 -05:00
|
|
|
Kernel.print Pry::Helpers::BaseHelpers.windows_ansi? ? "\e[0F" : "\e[0G"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-12-28 19:24:07 -05:00
|
|
|
# The actual read-eval-print-loop.
|
|
|
|
#
|
|
|
|
# This object is responsible for reading and looping, and it delegates
|
|
|
|
# to Pry for the evaling and printing.
|
|
|
|
#
|
|
|
|
# @return [Object] anything returned by the user from Pry
|
|
|
|
# @raise [Exception] anything raise-up'd by the user from Pry
|
2012-12-28 17:19:42 -05:00
|
|
|
def repl
|
|
|
|
loop do
|
2012-12-28 01:11:30 -05:00
|
|
|
case val = read
|
2012-12-20 04:28:04 -05:00
|
|
|
when :control_c
|
|
|
|
output.puts ""
|
2012-12-27 22:56:43 -05:00
|
|
|
pry.reset_eval_string
|
2012-12-21 03:40:21 -05:00
|
|
|
when :no_more_input
|
|
|
|
output.puts "" if output.tty?
|
2012-12-21 04:38:32 -05:00
|
|
|
break
|
2012-12-20 04:28:04 -05:00
|
|
|
else
|
2012-12-21 04:38:32 -05:00
|
|
|
output.puts "" if val.nil? && output.tty?
|
2012-12-28 01:06:50 -05:00
|
|
|
return pry.exit_value unless pry.eval(val)
|
2012-12-20 04:28:04 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Clean-up after the repl session.
|
2012-12-28 01:10:44 -05:00
|
|
|
def epilogue
|
2012-12-21 04:38:32 -05:00
|
|
|
pry.exec_hook :after_session, pry.output, pry.current_binding, pry
|
2012-12-20 04:28:04 -05:00
|
|
|
end
|
|
|
|
|
2012-12-28 19:24:07 -05:00
|
|
|
# Read a line of input from the user, special handling for:
|
2012-12-20 04:28:04 -05:00
|
|
|
#
|
2012-12-28 19:24:07 -05:00
|
|
|
# @return [nil] on <ctrl+d>
|
|
|
|
# @return [:control_c] on <ctrl+c>
|
|
|
|
# @return [:no_more_input] on EOF from Pry.input
|
|
|
|
# @return [String] The line from the user
|
2012-12-28 01:11:30 -05:00
|
|
|
def read
|
2012-12-20 04:28:04 -05:00
|
|
|
@indent.reset if pry.eval_string.empty?
|
|
|
|
|
|
|
|
current_prompt = pry.select_prompt
|
|
|
|
|
|
|
|
indentation = Pry.config.auto_indent ? @indent.current_prefix : ''
|
|
|
|
|
|
|
|
begin
|
2012-12-28 18:19:21 -05:00
|
|
|
val = read_line("#{current_prompt}#{indentation}")
|
2012-12-20 04:28:04 -05:00
|
|
|
|
2012-12-28 22:05:06 -05:00
|
|
|
# Handle <Ctrl+C> like Bash: empty the current input buffer, but don't
|
|
|
|
# quit. This is only for MRI 1.9; other versions of Ruby don't let you
|
|
|
|
# send Interrupt from within Readline.
|
2012-12-20 04:28:04 -05:00
|
|
|
rescue Interrupt
|
2012-12-28 18:59:41 -05:00
|
|
|
val = :control_c
|
2012-12-20 04:28:04 -05:00
|
|
|
end
|
|
|
|
|
2012-12-28 22:05:06 -05:00
|
|
|
# Return nil for EOF, :no_more_input for error, or :control_c for <Ctrl-C>
|
2012-12-28 18:59:41 -05:00
|
|
|
return val unless String === val
|
2012-12-20 04:28:04 -05:00
|
|
|
|
2012-12-28 18:59:41 -05:00
|
|
|
if Pry.config.auto_indent
|
2012-12-20 04:28:04 -05:00
|
|
|
original_val = "#{indentation}#{val}"
|
|
|
|
indented_val = @indent.indent(val)
|
|
|
|
|
2012-12-28 22:05:06 -05:00
|
|
|
if output.tty? && @indent.should_correct_indentation?
|
|
|
|
output.print @indent.correct_indentation(
|
|
|
|
current_prompt, indented_val,
|
|
|
|
original_val.length - indented_val.length
|
|
|
|
)
|
2012-12-20 04:28:04 -05:00
|
|
|
output.flush
|
|
|
|
end
|
|
|
|
else
|
|
|
|
indented_val = val
|
|
|
|
end
|
|
|
|
|
|
|
|
indented_val
|
|
|
|
end
|
|
|
|
|
|
|
|
# Manage switching of input objects on encountering EOFErrors
|
2012-12-28 19:24:07 -05:00
|
|
|
#
|
|
|
|
# @return [:no_more_input] if no more input can be read.
|
|
|
|
# @return [String?]
|
2012-12-20 04:28:04 -05:00
|
|
|
def handle_read_errors
|
|
|
|
should_retry = true
|
|
|
|
exception_count = 0
|
|
|
|
begin
|
|
|
|
yield
|
|
|
|
rescue EOFError
|
2012-12-28 16:35:14 -05:00
|
|
|
pry.input = Pry.config.input
|
|
|
|
if !should_retry
|
|
|
|
output.puts "Error: Pry ran out of things to read from! Attempting to break out of REPL."
|
|
|
|
return :no_more_input
|
2012-12-20 04:28:04 -05:00
|
|
|
end
|
2012-12-28 16:35:14 -05:00
|
|
|
should_retry = false
|
2012-12-20 04:28:04 -05:00
|
|
|
retry
|
|
|
|
|
|
|
|
rescue Interrupt
|
|
|
|
raise
|
|
|
|
|
|
|
|
# If we get a random error when trying to read a line we don't want to automatically
|
|
|
|
# retry, as the user will see a lot of error messages scroll past and be unable to do
|
|
|
|
# anything about it.
|
|
|
|
rescue RescuableException => e
|
|
|
|
puts "Error: #{e.message}"
|
|
|
|
output.puts e.backtrace
|
|
|
|
exception_count += 1
|
|
|
|
if exception_count < 5
|
|
|
|
retry
|
|
|
|
end
|
|
|
|
puts "FATAL: Pry failed to get user input using `#{input}`."
|
|
|
|
puts "To fix this you may be able to pass input and output file descriptors to pry directly. e.g."
|
|
|
|
puts " Pry.config.input = STDIN"
|
|
|
|
puts " Pry.config.output = STDOUT"
|
|
|
|
puts " binding.pry"
|
2012-12-21 03:40:21 -05:00
|
|
|
return :no_more_input
|
2012-12-20 04:28:04 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Returns the next line of input to be used by the pry instance.
|
|
|
|
# @param [String] current_prompt The prompt to use for input.
|
2012-12-28 19:24:07 -05:00
|
|
|
# @return [String?] The next line of input, nil on <ctrl+d>
|
2012-12-28 18:19:21 -05:00
|
|
|
def read_line(current_prompt)
|
2012-12-20 04:28:04 -05:00
|
|
|
handle_read_errors do
|
|
|
|
if defined? Coolline and input.is_a? Coolline
|
|
|
|
input.completion_proc = proc do |cool|
|
2012-12-28 18:19:21 -05:00
|
|
|
completions = @pry.complete cool.completed_word
|
2012-12-20 04:28:04 -05:00
|
|
|
completions.compact
|
|
|
|
end
|
|
|
|
elsif input.respond_to? :completion_proc=
|
2012-12-28 18:19:21 -05:00
|
|
|
input.completion_proc = proc do |input|
|
|
|
|
@pry.complete input
|
|
|
|
end
|
2012-12-20 04:28:04 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
if input == Readline
|
|
|
|
input.readline(current_prompt, false) # false since we'll add it manually
|
|
|
|
elsif defined? Coolline and input.is_a? Coolline
|
|
|
|
input.readline(current_prompt)
|
|
|
|
else
|
|
|
|
if input.method(:readline).arity == 1
|
|
|
|
input.readline(current_prompt)
|
|
|
|
else
|
|
|
|
input.readline
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|