-
-
Notifications
You must be signed in to change notification settings - Fork 137
/
Copy pathpry_processor.rb
158 lines (121 loc) · 3.32 KB
/
pry_processor.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
# frozen_string_literal: true
require "byebug/core"
module Byebug
#
# Extends raw byebug's processor.
#
class PryProcessor < CommandProcessor
attr_accessor :pry
extend Forwardable
def_delegators :@pry, :output
def_delegators Pry::Helpers::Text, :bold
def self.start
Byebug.start
Setting[:autolist] = false
Context.processor = self
Byebug.current_context.step_out(5, true)
end
#
# Wrap a Pry REPL to catch navigational commands and act on them.
#
def run(&_block)
return_value = nil
command = catch(:breakout_nav) do # Throws from PryByebug::Commands
return_value = allowing_other_threads { yield }
{} # Nothing thrown == no navigational command
end
# Pry instance to resume after stepping
@pry = command[:pry]
perform(command[:action], command[:options])
return_value
end
#
# Set up a number of navigational commands to be performed by Byebug.
#
def perform(action, options = {})
return unless %i[
backtrace
down
finish
frame
next
step
up
].include?(action)
send("perform_#{action}", options)
end
# --- Callbacks from byebug C extension ---
#
# Called when the debugger wants to stop at a regular line
#
def at_line
resume_pry
end
#
# Called when the debugger wants to stop right before a method return
#
def at_return(_return_value)
resume_pry
end
#
# Called when a breakpoint is hit. Note that `at_line`` is called
# inmediately after with the context's `stop_reason == :breakpoint`, so we
# must not resume the pry instance here
#
def at_breakpoint(breakpoint)
@pry ||= Pry.new
output.puts bold("\n Breakpoint #{breakpoint.id}. ") + n_hits(breakpoint)
expr = breakpoint.expr
return unless expr
output.puts bold("Condition: ") + expr
end
private
def n_hits(breakpoint)
n_hits = breakpoint.hit_count
n_hits == 1 ? "First hit" : "Hit #{n_hits} times."
end
#
# Resume an existing Pry REPL at the paused point.
#
def resume_pry
new_binding = frame._binding
run do
if defined?(@pry) && @pry
@pry.repl(new_binding)
else
@pry = Pry::REPL.start_without_pry_byebug(target: new_binding)
end
end
end
def perform_backtrace(_options)
Byebug::WhereCommand.new(self, "backtrace").execute
resume_pry
end
def perform_next(options)
lines = (options[:lines] || 1).to_i
context.step_over(lines, frame.pos)
end
def perform_step(options)
times = (options[:times] || 1).to_i
context.step_into(times, frame.pos)
end
def perform_finish(*)
context.step_out(1)
end
def perform_up(options)
times = (options[:times] || 1).to_i
Byebug::UpCommand.new(self, "up #{times}").execute
resume_pry
end
def perform_down(options)
times = (options[:times] || 1).to_i
Byebug::DownCommand.new(self, "down #{times}").execute
resume_pry
end
def perform_frame(options)
index = options[:index] ? options[:index].to_i : ""
Byebug::FrameCommand.new(self, "frame #{index}").execute
resume_pry
end
end
end