2012-02-23 03:28:00 +00:00
|
|
|
require 'tempfile'
|
2012-06-23 19:56:54 +00:00
|
|
|
require 'pry/default_commands/gist'
|
2012-02-23 03:28:00 +00:00
|
|
|
|
2011-05-01 10:25:37 +00:00
|
|
|
class Pry
|
|
|
|
module DefaultCommands
|
|
|
|
|
2012-02-23 03:28:00 +00:00
|
|
|
InputAndOutput = Pry::CommandSet.new do
|
2012-06-23 19:56:54 +00:00
|
|
|
import Gist
|
2012-02-27 01:36:02 +00:00
|
|
|
command(/\.(.*)/, "All text following a '.' is forwarded to the shell.", :listing => ".<shell command>", :use_prefix => false, :takes_block => true) do |cmd|
|
2011-05-28 15:41:15 +00:00
|
|
|
if cmd =~ /^cd\s+(.+)/i
|
2011-06-01 16:24:15 +00:00
|
|
|
dest = $1
|
2011-05-28 15:41:15 +00:00
|
|
|
begin
|
2011-06-01 16:24:15 +00:00
|
|
|
Dir.chdir File.expand_path(dest)
|
2011-05-28 15:41:15 +00:00
|
|
|
rescue Errno::ENOENT
|
2011-10-01 23:57:39 +00:00
|
|
|
raise CommandError, "No such directory: #{dest}"
|
2011-05-28 15:41:15 +00:00
|
|
|
end
|
|
|
|
else
|
2012-02-27 01:36:02 +00:00
|
|
|
pass_block(cmd)
|
|
|
|
|
|
|
|
if command_block
|
|
|
|
command_block.call `#{cmd}`
|
|
|
|
else
|
|
|
|
Pry.config.system.call(output, cmd, _pry_)
|
|
|
|
end
|
2011-05-28 15:41:15 +00:00
|
|
|
end
|
2011-05-01 10:25:37 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
command "shell-mode", "Toggle shell mode. Bring in pwd prompt and file completion." do
|
2011-08-16 01:02:32 +00:00
|
|
|
case _pry_.prompt
|
2011-05-01 10:25:37 +00:00
|
|
|
when Pry::SHELL_PROMPT
|
2011-08-16 01:02:32 +00:00
|
|
|
_pry_.pop_prompt
|
|
|
|
_pry_.custom_completions = Pry::DEFAULT_CUSTOM_COMPLETIONS
|
2011-05-01 10:25:37 +00:00
|
|
|
else
|
2011-08-16 01:02:32 +00:00
|
|
|
_pry_.push_prompt Pry::SHELL_PROMPT
|
|
|
|
_pry_.custom_completions = Pry::FILE_COMPLETIONS
|
2012-08-04 01:20:20 +00:00
|
|
|
Readline.completion_proc = Pry::InputCompleter.build_completion_proc target, _pry_,
|
2011-08-16 01:02:32 +00:00
|
|
|
_pry_.instance_eval(&Pry::FILE_COMPLETIONS)
|
2011-05-01 10:25:37 +00:00
|
|
|
end
|
|
|
|
end
|
2011-09-18 06:36:39 +00:00
|
|
|
alias_command "file-mode", "shell-mode"
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2012-01-21 23:17:43 +00:00
|
|
|
create_command "save-file", "Export to a file using content from the REPL." do
|
2012-01-21 14:54:45 +00:00
|
|
|
banner <<-USAGE
|
2012-01-23 03:40:40 +00:00
|
|
|
Usage: save-file [OPTIONS] [FILE]
|
2012-01-21 14:54:45 +00:00
|
|
|
Save REPL content to a file.
|
|
|
|
e.g: save-file -m my_method -m my_method2 ./hello.rb
|
2012-01-22 11:28:22 +00:00
|
|
|
e.g: save-file -i 1..10 ./hello.rb --append
|
2012-06-02 13:50:30 +00:00
|
|
|
e.g: save-file -k show-method ./my_command.rb
|
2012-01-21 14:54:45 +00:00
|
|
|
e.g: save-file -f sample_file --lines 2..10 ./output_file.rb
|
|
|
|
USAGE
|
|
|
|
|
2012-01-21 13:59:42 +00:00
|
|
|
attr_accessor :content
|
|
|
|
attr_accessor :file_name
|
|
|
|
|
|
|
|
def setup
|
|
|
|
self.content = ""
|
|
|
|
end
|
|
|
|
|
2012-05-25 18:45:33 +00:00
|
|
|
def convert_to_range(n)
|
|
|
|
if !n.is_a?(Range)
|
|
|
|
(n..n)
|
|
|
|
else
|
|
|
|
n
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-01-21 13:59:42 +00:00
|
|
|
def options(opt)
|
2012-05-27 08:36:41 +00:00
|
|
|
opt.on :m, :method, "Save a method's source.", :argument => true do |meth_name|
|
2012-01-21 13:59:42 +00:00
|
|
|
meth = get_method_or_raise(meth_name, target, {})
|
|
|
|
self.content << meth.source
|
|
|
|
end
|
2012-06-02 13:50:30 +00:00
|
|
|
opt.on :c, :class, "Save a class's source.", :argument => true do |class_name|
|
2012-05-25 18:45:33 +00:00
|
|
|
mod = Pry::WrappedModule.from_str(class_name, target)
|
|
|
|
self.content << mod.source
|
|
|
|
end
|
2012-06-02 13:50:30 +00:00
|
|
|
opt.on :k, :command, "Save a command's source.", :argument => true do |command_name|
|
2012-01-21 13:59:42 +00:00
|
|
|
command = find_command(command_name)
|
2012-05-28 23:37:02 +00:00
|
|
|
block = Pry::Method.new(command.block)
|
2012-01-23 05:06:33 +00:00
|
|
|
self.content << block.source
|
2012-01-21 13:59:42 +00:00
|
|
|
end
|
2012-05-27 08:36:41 +00:00
|
|
|
opt.on :f, :file, "Save a file.", :argument => true do |file|
|
2012-01-21 13:59:42 +00:00
|
|
|
self.content << File.read(File.expand_path(file))
|
|
|
|
end
|
2012-05-27 08:36:41 +00:00
|
|
|
opt.on :l, :lines, "Only save a subset of lines.", :optional_argument => true, :as => Range, :default => 1..-1
|
|
|
|
opt.on :o, :out, "Save entries from Pry's output result history. Takes an index or range.", :optional_argument => true,
|
2012-05-25 18:45:33 +00:00
|
|
|
:as => Range, :default => -5..-1 do |range|
|
|
|
|
range = convert_to_range(range)
|
|
|
|
|
|
|
|
range.each do |v|
|
|
|
|
self.content << Pry.config.gist.inspecter.call(_pry_.output_array[v])
|
|
|
|
end
|
|
|
|
|
|
|
|
self.content << "\n"
|
|
|
|
end
|
2012-05-27 08:36:41 +00:00
|
|
|
opt.on :i, :in, "Save entries from Pry's input expression history. Takes an index or range.", :optional_argument => true,
|
2012-01-21 13:59:42 +00:00
|
|
|
:as => Range, :default => -5..-1 do |range|
|
|
|
|
input_expressions = _pry_.input_array[range] || []
|
|
|
|
Array(input_expressions).each { |v| self.content << v }
|
|
|
|
end
|
2012-01-22 11:28:22 +00:00
|
|
|
opt.on :a, :append, "Append to the given file instead of overwriting it."
|
2012-01-21 13:59:42 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def process
|
|
|
|
if args.empty?
|
|
|
|
raise CommandError, "Must specify a file name."
|
|
|
|
end
|
|
|
|
|
|
|
|
self.file_name = File.expand_path(args.first)
|
|
|
|
|
|
|
|
save_file
|
|
|
|
end
|
|
|
|
|
|
|
|
def save_file
|
|
|
|
if self.content.empty?
|
|
|
|
raise CommandError, "Found no code to save."
|
|
|
|
end
|
|
|
|
|
2012-01-22 11:28:22 +00:00
|
|
|
File.open(file_name, mode) do |f|
|
2012-01-21 13:59:42 +00:00
|
|
|
if opts.present?(:lines)
|
|
|
|
f.puts restrict_to_lines(content, opts[:l])
|
|
|
|
else
|
|
|
|
f.puts content
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-01-22 11:28:22 +00:00
|
|
|
def mode
|
|
|
|
if opts.present?(:append)
|
|
|
|
"a"
|
|
|
|
else
|
|
|
|
"w"
|
|
|
|
end
|
|
|
|
end
|
2012-01-21 13:59:42 +00:00
|
|
|
end
|
|
|
|
|
2012-01-20 22:49:38 +00:00
|
|
|
create_command "cat", "Show code from a file, Pry's input buffer, or the last exception." do
|
2012-01-08 06:01:15 +00:00
|
|
|
banner <<-USAGE
|
|
|
|
Usage: cat FILE
|
|
|
|
cat --ex [STACK_INDEX]
|
|
|
|
cat --in [INPUT_INDEX_OR_RANGE]
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2012-01-08 06:01:15 +00:00
|
|
|
cat is capable of showing part or all of a source file, the context of the
|
|
|
|
last exception, or an expression from Pry's input history.
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2012-01-08 06:01:15 +00:00
|
|
|
cat --ex defaults to showing the lines surrounding the location of the last
|
|
|
|
exception. Invoking it more than once travels up the exception's backtrace,
|
|
|
|
and providing a number shows the context of the given index of the backtrace.
|
|
|
|
USAGE
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2012-01-08 06:01:15 +00:00
|
|
|
def options(opt)
|
2012-05-27 08:36:41 +00:00
|
|
|
opt.on :ex, "Show the context of the last exception.", :optional_argument => true, :as => Integer
|
|
|
|
opt.on :i, :in, "Show one or more entries from Pry's expression history.", :optional_argument => true, :as => Range, :default => -5..-1
|
2012-01-08 06:01:15 +00:00
|
|
|
|
2012-05-27 08:36:41 +00:00
|
|
|
opt.on :s, :start, "Starting line (defaults to the first line).", :optional_argument => true, :as => Integer
|
|
|
|
opt.on :e, :end, "Ending line (defaults to the last line).", :optional_argument => true, :as => Integer
|
2012-01-08 06:01:15 +00:00
|
|
|
opt.on :l, :'line-numbers', "Show line numbers."
|
2012-05-27 08:36:41 +00:00
|
|
|
opt.on :t, :type, "The file type for syntax highlighting (e.g., 'ruby' or 'python').", :argument => true, :as => Symbol
|
2012-01-08 06:01:15 +00:00
|
|
|
|
|
|
|
opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
|
|
|
|
end
|
|
|
|
|
|
|
|
def process
|
|
|
|
handler = case
|
2012-02-23 03:28:00 +00:00
|
|
|
when opts.present?(:ex)
|
|
|
|
method :process_ex
|
|
|
|
when opts.present?(:in)
|
|
|
|
method :process_in
|
|
|
|
else
|
|
|
|
method :process_file
|
|
|
|
end
|
2011-07-26 15:15:36 +00:00
|
|
|
|
2012-01-15 08:23:07 +00:00
|
|
|
output = handler.call do |code|
|
2012-01-08 06:01:15 +00:00
|
|
|
code.code_type = opts[:type] || :ruby
|
2011-11-06 07:59:49 +00:00
|
|
|
|
2012-01-15 08:23:07 +00:00
|
|
|
code.between(opts[:start] || 1, opts[:end] || -1).
|
2012-01-08 06:01:15 +00:00
|
|
|
with_line_numbers(opts.present?(:'line-numbers') || opts.present?(:ex))
|
2011-05-01 10:25:37 +00:00
|
|
|
end
|
2012-01-15 08:23:07 +00:00
|
|
|
|
|
|
|
render_output(output, opts)
|
2011-05-01 10:25:37 +00:00
|
|
|
end
|
|
|
|
|
2012-01-08 06:01:15 +00:00
|
|
|
def process_ex
|
2012-01-15 06:30:32 +00:00
|
|
|
window_size = Pry.config.default_window_size || 5
|
2012-01-08 06:01:15 +00:00
|
|
|
ex = _pry_.last_exception
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2012-01-08 06:01:15 +00:00
|
|
|
raise CommandError, "No exception found." unless ex
|
|
|
|
|
|
|
|
if opts[:ex].nil?
|
|
|
|
bt_index = ex.bt_index
|
|
|
|
ex.inc_bt_index
|
|
|
|
else
|
|
|
|
bt_index = opts[:ex]
|
2012-07-02 12:53:38 +00:00
|
|
|
ex.bt_index = bt_index
|
|
|
|
ex.inc_bt_index
|
2011-10-01 23:57:39 +00:00
|
|
|
end
|
2012-01-08 06:01:15 +00:00
|
|
|
|
|
|
|
ex_file, ex_line = ex.bt_source_location_for(bt_index)
|
|
|
|
|
|
|
|
raise CommandError, "The given backtrace level is out of bounds." unless ex_file
|
|
|
|
|
|
|
|
if RbxPath.is_core_path?(ex_file)
|
|
|
|
ex_file = RbxPath.convert_path_to_full(ex_file)
|
|
|
|
end
|
|
|
|
|
2012-01-22 00:34:43 +00:00
|
|
|
set_file_and_dir_locals(ex_file)
|
|
|
|
|
2012-01-08 06:01:15 +00:00
|
|
|
start_line = ex_line - window_size
|
|
|
|
start_line = 1 if start_line < 1
|
|
|
|
end_line = ex_line + window_size
|
|
|
|
|
|
|
|
header = unindent <<-HEADER
|
|
|
|
#{text.bold 'Exception:'} #{ex.class}: #{ex.message}
|
|
|
|
--
|
|
|
|
#{text.bold('From:')} #{ex_file} @ line #{ex_line} @ #{text.bold("level: #{bt_index}")} of backtrace (of #{ex.backtrace.size - 1}).
|
|
|
|
|
|
|
|
HEADER
|
|
|
|
|
|
|
|
code = yield(Pry::Code.from_file(ex_file).
|
2012-02-23 03:28:00 +00:00
|
|
|
between(start_line, end_line).
|
|
|
|
with_marker(ex_line))
|
2012-01-08 06:01:15 +00:00
|
|
|
|
2012-01-15 08:23:07 +00:00
|
|
|
"#{header}#{code}"
|
2011-07-26 15:15:36 +00:00
|
|
|
end
|
|
|
|
|
2012-01-08 06:01:15 +00:00
|
|
|
def process_in
|
2011-11-06 07:59:49 +00:00
|
|
|
normalized_range = absolute_index_range(opts[:i], _pry_.input_array.length)
|
|
|
|
input_items = _pry_.input_array[normalized_range] || []
|
|
|
|
|
|
|
|
zipped_items = normalized_range.zip(input_items).reject { |_, s| s.nil? || s == "" }
|
|
|
|
|
|
|
|
unless zipped_items.length > 0
|
|
|
|
raise CommandError, "No expressions found."
|
|
|
|
end
|
|
|
|
|
2012-01-08 06:01:15 +00:00
|
|
|
if zipped_items.length > 1
|
2011-11-06 07:59:49 +00:00
|
|
|
contents = ""
|
|
|
|
zipped_items.each do |i, s|
|
|
|
|
contents << "#{text.bold(i.to_s)}:\n"
|
2012-01-08 06:01:15 +00:00
|
|
|
contents << yield(Pry::Code(s).with_indentation(2)).to_s
|
2011-11-06 07:59:49 +00:00
|
|
|
end
|
|
|
|
else
|
2012-01-08 06:01:15 +00:00
|
|
|
contents = yield(Pry::Code(zipped_items.first.last))
|
2011-11-06 07:59:49 +00:00
|
|
|
end
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2012-01-15 08:23:07 +00:00
|
|
|
contents
|
2011-08-05 21:51:11 +00:00
|
|
|
end
|
|
|
|
|
2012-01-08 06:01:15 +00:00
|
|
|
def process_file
|
|
|
|
file_name = args.shift
|
2011-08-14 09:12:14 +00:00
|
|
|
|
2012-01-08 06:01:15 +00:00
|
|
|
unless file_name
|
|
|
|
raise CommandError, "Must provide a filename, --in, or --ex."
|
|
|
|
end
|
2011-07-26 15:15:36 +00:00
|
|
|
|
2012-01-15 06:30:32 +00:00
|
|
|
file_name, line_num = file_name.split(':')
|
2012-01-24 12:07:07 +00:00
|
|
|
file_name = File.expand_path(file_name)
|
2012-01-15 08:23:07 +00:00
|
|
|
set_file_and_dir_locals(file_name)
|
2012-01-15 06:30:32 +00:00
|
|
|
|
2012-01-08 06:01:15 +00:00
|
|
|
code = yield(Pry::Code.from_file(file_name))
|
2011-08-05 21:51:11 +00:00
|
|
|
|
2012-07-02 12:53:38 +00:00
|
|
|
code.code_type = opts[:type] || detect_code_type_from_file(file_name)
|
2012-01-15 06:30:32 +00:00
|
|
|
if line_num
|
|
|
|
code = code.around(line_num.to_i,
|
|
|
|
Pry.config.default_window_size || 7)
|
|
|
|
end
|
|
|
|
|
2012-01-15 08:23:07 +00:00
|
|
|
code
|
2011-08-05 21:51:11 +00:00
|
|
|
end
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2012-06-23 14:05:03 +00:00
|
|
|
def detect_code_type_from_file(file_name)
|
|
|
|
name, ext = File.basename(file_name).split('.', 2)
|
|
|
|
|
|
|
|
if ext
|
|
|
|
case ext
|
|
|
|
when "py"
|
|
|
|
:python
|
|
|
|
when "rb", "gemspec", "rakefile", "ru"
|
|
|
|
:ruby
|
|
|
|
when "js"
|
|
|
|
return :javascript
|
2012-07-02 12:53:38 +00:00
|
|
|
when "yml", "prytheme"
|
|
|
|
:yaml
|
|
|
|
when "groovy"
|
|
|
|
:groovy
|
|
|
|
when "c"
|
|
|
|
:c
|
|
|
|
when "cpp"
|
|
|
|
:cpp
|
|
|
|
when "java"
|
|
|
|
:java
|
2012-06-23 14:05:03 +00:00
|
|
|
else
|
2012-07-02 12:53:38 +00:00
|
|
|
:text
|
2012-06-23 14:05:03 +00:00
|
|
|
end
|
|
|
|
else
|
|
|
|
case name
|
|
|
|
when "Rakefile", "Gemfile"
|
|
|
|
:ruby
|
|
|
|
else
|
2012-07-02 12:53:38 +00:00
|
|
|
:text
|
2012-06-23 14:05:03 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2012-02-23 03:28:00 +00:00
|
|
|
end
|
2011-05-01 10:25:37 +00:00
|
|
|
end
|
|
|
|
end
|