/
context.rb
180 lines (149 loc) · 5.83 KB
/
context.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
require "pry/default_commands/ls"
class Pry
module DefaultCommands
Context = Pry::CommandSet.new do
import Ls
command "cd", "Move into a new context (use `cd ..` to go back and `cd /` to return to Pry top-level). Complex syntax (e.g cd ../@x/y) also supported." do |obj|
path = arg_string.split(/\//)
stack = _pry_.binding_stack.dup
# special case when we only get a single "/", return to root
stack = [stack.first] if path.empty?
resolve_failure = false
path.each do |context|
begin
case context.chomp
when ""
stack = [stack.first]
when "::"
stack.push(TOPLEVEL_BINDING)
when "."
next
when ".."
if stack.one?
_pry_.binding_stack.clear
throw(:breakout)
else
stack.pop
end
else
stack.push(Pry.binding_for(stack.last.eval(context)))
end
rescue RescuableException
output.puts "Bad object path: #{arg_string}. Failed trying to resolve: #{context}"
resolve_failure = true
end
end
next if resolve_failure
_pry_.binding_stack = stack
end
command "switch-to", "Start a new sub-session on a binding in the current stack (numbered by nesting)." do |selection|
selection = selection.to_i
if selection < 0 || selection > _pry_.binding_stack.size - 1
output.puts "Invalid binding index #{selection} - use `nesting` command to view valid indices."
else
Pry.start(_pry_.binding_stack[selection])
end
end
command "nesting", "Show nesting information." do
output.puts "Nesting status:"
output.puts "--"
_pry_.binding_stack.each_with_index do |obj, level|
if level == 0
output.puts "#{level}. #{Pry.view_clip(obj.eval('self'))} (Pry top level)"
else
output.puts "#{level}. #{Pry.view_clip(obj.eval('self'))}"
end
end
end
command "jump-to", "Jump to a binding further up the stack, popping all bindings below." do |break_level|
break_level = break_level.to_i
nesting_level = _pry_.binding_stack.size - 1
case break_level
when nesting_level
output.puts "Already at nesting level #{nesting_level}"
when (0...nesting_level)
_pry_.binding_stack.slice!(break_level + 1, _pry_.binding_stack.size)
else
max_nest_level = nesting_level - 1
output.puts "Invalid nest level. Must be between 0 and #{max_nest_level}. Got #{break_level}."
end
end
command "exit-all", "End the current Pry session (popping all bindings) and returning to caller. Accepts optional return value. Aliases: !!@" do
# clear the binding stack
_pry_.binding_stack.clear
# break out of the repl loop
throw(:breakout, target.eval(arg_string))
end
alias_command "!!@", "exit-all", ""
command "exit", "Pop the current binding and return to the one immediately prior. Note this does NOT exit the program. Aliases: quit", :keep_retval => true do
if _pry_.binding_stack.one?
# when breaking out of top-level then behave like `exit-all`
_pry_.binding_stack.clear
throw(:breakout, target.eval(arg_string))
else
# otherwise just pop a binding
popped_object = _pry_.binding_stack.pop.eval('self')
# return a user-specified value if given
if !arg_string.empty?
target.eval(arg_string)
else
popped_object
end
end
end
alias_command "quit", "exit", ""
command "exit-program", "End the current program. Aliases: quit-program, !!!" do
Pry.save_history if Pry.config.history.should_save
Kernel.exit target.eval(arg_string).to_i
end
alias_command "quit-program", "exit-program", ""
alias_command "!!!", "exit-program", ""
command "!pry", "Start a Pry session on current self; this even works mid multi-line expression." do
target.pry
end
command "whereami", "Show the code context for the session. (whereami <n> shows <n> extra lines of code around the invocation line. Default: 5)" do |num|
file = target.eval('__FILE__')
line_num = target.eval('__LINE__')
klass = target.eval('self.class')
if num
i_num = num.to_i
else
i_num = 5
end
meth_name = meth_name_from_binding(target)
meth_name = "N/A" if !meth_name
if file =~ /(\(.*\))|<.*>/ || file == "" || file == "-e"
output.puts "Cannot find local context. Did you use `binding.pry` ?"
next
end
set_file_and_dir_locals(file)
output.puts "\n#{text.bold('From:')} #{file} @ line #{line_num} in #{klass}##{meth_name}:\n\n"
unless File.readable?(file)
output.puts "Cannot open #{file.inspect} for reading."
next
end
# This method inspired by http://rubygems.org/gems/ir_b
File.open(file).each_with_index do |line, index|
line_n = index + 1
next unless line_n > (line_num - i_num - 1)
break if line_n > (line_num + i_num)
if line_n == line_num
code =" =>#{line_n.to_s.rjust(3)}: #{line.chomp}"
if Pry.color
code = CodeRay.scan(code, :ruby).term
end
output.puts code
code
else
code = "#{line_n.to_s.rjust(6)}: #{line.chomp}"
if Pry.color
code = CodeRay.scan(code, :ruby).term
end
output.puts code
code
end
end
end
end
end
end