gitlab-pry-byebug 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +214 -0
- data/LICENSE +20 -0
- data/README.md +192 -0
- data/lib/byebug/processors/pry_processor.rb +166 -0
- data/lib/byebug/processors/pry_remote_processor.rb +42 -0
- data/lib/pry-byebug.rb +4 -0
- data/lib/pry-byebug/base.rb +31 -0
- data/lib/pry-byebug/cli.rb +6 -0
- data/lib/pry-byebug/commands.rb +12 -0
- data/lib/pry-byebug/commands/backtrace.rb +31 -0
- data/lib/pry-byebug/commands/breakpoint.rb +137 -0
- data/lib/pry-byebug/commands/continue.rb +43 -0
- data/lib/pry-byebug/commands/down.rb +35 -0
- data/lib/pry-byebug/commands/exit_all.rb +19 -0
- data/lib/pry-byebug/commands/finish.rb +29 -0
- data/lib/pry-byebug/commands/frame.rb +35 -0
- data/lib/pry-byebug/commands/next.rb +39 -0
- data/lib/pry-byebug/commands/step.rb +34 -0
- data/lib/pry-byebug/commands/up.rb +35 -0
- data/lib/pry-byebug/control_d_handler.rb +9 -0
- data/lib/pry-byebug/helpers/breakpoints.rb +82 -0
- data/lib/pry-byebug/helpers/location.rb +24 -0
- data/lib/pry-byebug/helpers/multiline.rb +23 -0
- data/lib/pry-byebug/helpers/navigation.rb +19 -0
- data/lib/pry-byebug/pry_ext.rb +23 -0
- data/lib/pry-byebug/pry_remote_ext.rb +44 -0
- data/lib/pry-byebug/version.rb +8 -0
- data/lib/pry/byebug/breakpoints.rb +167 -0
- metadata +103 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pry-byebug/helpers/navigation"
|
4
|
+
|
5
|
+
module PryByebug
|
6
|
+
#
|
7
|
+
# Run a number of Ruby statements and then stop again
|
8
|
+
#
|
9
|
+
class StepCommand < Pry::ClassCommand
|
10
|
+
include Helpers::Navigation
|
11
|
+
|
12
|
+
match "step"
|
13
|
+
group "Byebug"
|
14
|
+
description "Step execution into the next line or method."
|
15
|
+
|
16
|
+
banner <<-BANNER
|
17
|
+
Usage: step [TIMES]
|
18
|
+
|
19
|
+
Step execution forward. By default, moves a single step.
|
20
|
+
|
21
|
+
Examples:
|
22
|
+
step #=> Move a single step forward.
|
23
|
+
step 5 #=> Execute the next 5 steps.
|
24
|
+
BANNER
|
25
|
+
|
26
|
+
def process
|
27
|
+
PryByebug.check_file_context(target)
|
28
|
+
|
29
|
+
breakout_navigation :step, times: args.first
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Pry::Commands.add_command(PryByebug::StepCommand)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pry-byebug/helpers/navigation"
|
4
|
+
|
5
|
+
module PryByebug
|
6
|
+
#
|
7
|
+
# Travel up the frame stack
|
8
|
+
#
|
9
|
+
class UpCommand < Pry::ClassCommand
|
10
|
+
include Helpers::Navigation
|
11
|
+
|
12
|
+
match "up"
|
13
|
+
group "Byebug"
|
14
|
+
|
15
|
+
description "Move current frame up."
|
16
|
+
|
17
|
+
banner <<-BANNER
|
18
|
+
Usage: up [TIMES]
|
19
|
+
|
20
|
+
Move current frame up. By default, moves by 1 frame.
|
21
|
+
|
22
|
+
Examples:
|
23
|
+
up #=> Move up 1 frame.
|
24
|
+
up 5 #=> Move up 5 frames.
|
25
|
+
BANNER
|
26
|
+
|
27
|
+
def process
|
28
|
+
PryByebug.check_file_context(target)
|
29
|
+
|
30
|
+
breakout_navigation :up, times: args.first
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Pry::Commands.add_command(PryByebug::UpCommand)
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "byebug"
|
4
|
+
|
5
|
+
module PryByebug
|
6
|
+
module Helpers
|
7
|
+
#
|
8
|
+
# Common helpers for breakpoint related commands
|
9
|
+
#
|
10
|
+
module Breakpoints
|
11
|
+
#
|
12
|
+
# Byebug's array of breakpoints.
|
13
|
+
#
|
14
|
+
def breakpoints
|
15
|
+
Pry::Byebug::Breakpoints
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Prints a message with bold font.
|
20
|
+
#
|
21
|
+
def bold_puts(msg)
|
22
|
+
output.puts(bold(msg))
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Print out full information about a breakpoint.
|
27
|
+
#
|
28
|
+
# Includes surrounding code at that point.
|
29
|
+
#
|
30
|
+
def print_full_breakpoint(breakpoint)
|
31
|
+
header = "Breakpoint #{breakpoint.id}:"
|
32
|
+
status = breakpoint.enabled? ? "Enabled" : "Disabled"
|
33
|
+
code = breakpoint.source_code.with_line_numbers.to_s
|
34
|
+
condition = if breakpoint.expr
|
35
|
+
"#{bold('Condition:')} #{breakpoint.expr}\n"
|
36
|
+
else
|
37
|
+
""
|
38
|
+
end
|
39
|
+
|
40
|
+
output.puts <<-BREAKPOINT.gsub(/ {8}/, "")
|
41
|
+
|
42
|
+
#{bold(header)} #{breakpoint} (#{status}) #{condition}
|
43
|
+
|
44
|
+
#{code}
|
45
|
+
|
46
|
+
BREAKPOINT
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Print out concise information about a breakpoint.
|
51
|
+
#
|
52
|
+
def print_short_breakpoint(breakpoint)
|
53
|
+
id = format("%*d", max_width, breakpoint.id)
|
54
|
+
status = breakpoint.enabled? ? "Yes" : "No "
|
55
|
+
expr = breakpoint.expr ? " #{breakpoint.expr} " : ""
|
56
|
+
|
57
|
+
output.puts(" #{id} #{status} #{breakpoint}#{expr}")
|
58
|
+
end
|
59
|
+
|
60
|
+
#
|
61
|
+
# Prints a header for the breakpoint list.
|
62
|
+
#
|
63
|
+
def print_breakpoints_header
|
64
|
+
header = "#{' ' * (max_width - 1)}# Enabled At "
|
65
|
+
|
66
|
+
output.puts <<-BREAKPOINTS.gsub(/ {8}/, "")
|
67
|
+
|
68
|
+
#{bold(header)}
|
69
|
+
#{bold('-' * header.size)}
|
70
|
+
|
71
|
+
BREAKPOINTS
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# Max width of breakpoints id column
|
76
|
+
#
|
77
|
+
def max_width
|
78
|
+
breakpoints.last ? breakpoints.last.id.to_s.length : 1
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PryByebug
|
4
|
+
module Helpers
|
5
|
+
#
|
6
|
+
# Compatibility helper to handle source location
|
7
|
+
#
|
8
|
+
module Location
|
9
|
+
module_function
|
10
|
+
|
11
|
+
#
|
12
|
+
# Current file in the target binding. Used as the default breakpoint
|
13
|
+
# location.
|
14
|
+
#
|
15
|
+
def current_file(source = target)
|
16
|
+
# Guard clause for Ruby >= 2.6 providing now Binding#source_location ...
|
17
|
+
return source.source_location[0] if source.respond_to?(:source_location)
|
18
|
+
|
19
|
+
# ... to avoid warning: 'eval may not return location in binding'
|
20
|
+
source.eval("__FILE__")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PryByebug
|
4
|
+
module Helpers
|
5
|
+
#
|
6
|
+
# Helpers to help handling multiline inputs
|
7
|
+
#
|
8
|
+
module Multiline
|
9
|
+
#
|
10
|
+
# Returns true if we are in a multiline context and, as a side effect,
|
11
|
+
# updates the partial evaluation string with the current input.
|
12
|
+
#
|
13
|
+
# Returns false otherwise
|
14
|
+
#
|
15
|
+
def check_multiline_context
|
16
|
+
return false if eval_string.empty?
|
17
|
+
|
18
|
+
eval_string.replace("#{eval_string}#{match} #{arg_string}\n")
|
19
|
+
true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PryByebug
|
4
|
+
module Helpers
|
5
|
+
#
|
6
|
+
# Helpers to aid breaking out of the REPL loop
|
7
|
+
#
|
8
|
+
module Navigation
|
9
|
+
#
|
10
|
+
# Breaks out of the REPL loop and signals tracer
|
11
|
+
#
|
12
|
+
def breakout_navigation(action, options = {})
|
13
|
+
pry_instance.binding_stack.clear
|
14
|
+
|
15
|
+
throw :breakout_nav, action: action, options: options, pry: pry_instance
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "byebug/processors/pry_processor"
|
4
|
+
require "byebug/processors/pry_remote_processor"
|
5
|
+
|
6
|
+
class << Pry
|
7
|
+
alias start_without_pry_byebug start
|
8
|
+
|
9
|
+
def start_with_pry_byebug(target = TOPLEVEL_BINDING, options = {})
|
10
|
+
if target.is_a?(Binding) && PryByebug.file_context?(target) && !ENV["DISABLE_PRY"]
|
11
|
+
run_remote? ? Byebug::PryRemoteProcessor.start : Byebug::PryProcessor.start
|
12
|
+
else
|
13
|
+
# No need for the tracer unless we have a file context to step through
|
14
|
+
start_without_pry_byebug(target, options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def run_remote?
|
19
|
+
PryByebug.current_remote_server
|
20
|
+
end
|
21
|
+
|
22
|
+
alias start start_with_pry_byebug
|
23
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pry-remote"
|
4
|
+
|
5
|
+
module PryRemote
|
6
|
+
#
|
7
|
+
# Overrides PryRemote::Server
|
8
|
+
#
|
9
|
+
class Server
|
10
|
+
#
|
11
|
+
# Override the call to Pry.start to save off current Server, and not
|
12
|
+
# teardown the server right after Pry.start finishes.
|
13
|
+
#
|
14
|
+
def run
|
15
|
+
raise("Already running a pry-remote session!") if
|
16
|
+
PryByebug.current_remote_server
|
17
|
+
|
18
|
+
PryByebug.current_remote_server = self
|
19
|
+
|
20
|
+
setup
|
21
|
+
Pry.start @object, input: client.input_proxy, output: client.output
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Override to reset our saved global current server session.
|
26
|
+
#
|
27
|
+
alias teardown_without_pry_byebug teardown
|
28
|
+
def teardown_with_pry_byebug
|
29
|
+
return if @torn
|
30
|
+
|
31
|
+
teardown_without_pry_byebug
|
32
|
+
PryByebug.current_remote_server = nil
|
33
|
+
@torn = true
|
34
|
+
end
|
35
|
+
alias teardown teardown_with_pry_byebug
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Ensure cleanup when a program finishes without another break. For example,
|
40
|
+
# 'next' on the last line of a program won't hit Byebug::PryProcessor#run,
|
41
|
+
# which normally handles cleanup.
|
42
|
+
at_exit do
|
43
|
+
PryByebug.current_remote_server&.teardown
|
44
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Pry
|
4
|
+
module Byebug
|
5
|
+
#
|
6
|
+
# Wrapper for Byebug.breakpoints that respects our Processor and has better
|
7
|
+
# failure behavior. Acts as an Enumerable.
|
8
|
+
#
|
9
|
+
module Breakpoints
|
10
|
+
extend Enumerable
|
11
|
+
extend self
|
12
|
+
|
13
|
+
#
|
14
|
+
# Breakpoint in a file:line location
|
15
|
+
#
|
16
|
+
class FileBreakpoint < SimpleDelegator
|
17
|
+
def source_code
|
18
|
+
Pry::Code.from_file(source).around(pos, 3).with_marker(pos)
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
"#{source} @ #{pos}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Breakpoint in a Class#method location
|
28
|
+
#
|
29
|
+
class MethodBreakpoint < SimpleDelegator
|
30
|
+
def initialize(byebug_bp, method)
|
31
|
+
__setobj__ byebug_bp
|
32
|
+
@method = method
|
33
|
+
end
|
34
|
+
|
35
|
+
def source_code
|
36
|
+
Pry::Code.from_method(Pry::Method.from_str(@method))
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
@method
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def breakpoints
|
45
|
+
@breakpoints ||= []
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Adds a method breakpoint.
|
50
|
+
#
|
51
|
+
def add_method(method, expression = nil)
|
52
|
+
validate_expression expression
|
53
|
+
owner, name = method.split(/[\.#]/)
|
54
|
+
byebug_bp = ::Byebug::Breakpoint.add(owner, name.to_sym, expression)
|
55
|
+
bp = MethodBreakpoint.new byebug_bp, method
|
56
|
+
breakpoints << bp
|
57
|
+
bp
|
58
|
+
end
|
59
|
+
|
60
|
+
#
|
61
|
+
# Adds a file breakpoint.
|
62
|
+
#
|
63
|
+
def add_file(file, line, expression = nil)
|
64
|
+
real_file = (file != Pry.eval_path)
|
65
|
+
raise(ArgumentError, "Invalid file!") if real_file && !File.exist?(file)
|
66
|
+
|
67
|
+
validate_expression expression
|
68
|
+
|
69
|
+
path = (real_file ? File.expand_path(file) : file)
|
70
|
+
bp = FileBreakpoint.new ::Byebug::Breakpoint.add(path, line, expression)
|
71
|
+
breakpoints << bp
|
72
|
+
bp
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Changes the conditional expression for a breakpoint.
|
77
|
+
#
|
78
|
+
def change(id, expression = nil)
|
79
|
+
validate_expression expression
|
80
|
+
|
81
|
+
breakpoint = find_by_id(id)
|
82
|
+
breakpoint.expr = expression
|
83
|
+
breakpoint
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# Deletes an existing breakpoint with the given ID.
|
88
|
+
#
|
89
|
+
def delete(id)
|
90
|
+
deleted =
|
91
|
+
::Byebug::Breakpoint.remove(id) &&
|
92
|
+
breakpoints.delete(find_by_id(id))
|
93
|
+
|
94
|
+
raise(ArgumentError, "No breakpoint ##{id}") unless deleted
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# Deletes all breakpoints.
|
99
|
+
#
|
100
|
+
def delete_all
|
101
|
+
@breakpoints = []
|
102
|
+
::Byebug.breakpoints.clear
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# Enables a disabled breakpoint with the given ID.
|
107
|
+
#
|
108
|
+
def enable(id)
|
109
|
+
change_status id, true
|
110
|
+
end
|
111
|
+
|
112
|
+
#
|
113
|
+
# Disables a breakpoint with the given ID.
|
114
|
+
#
|
115
|
+
def disable(id)
|
116
|
+
change_status id, false
|
117
|
+
end
|
118
|
+
|
119
|
+
#
|
120
|
+
# Disables all breakpoints.
|
121
|
+
#
|
122
|
+
def disable_all
|
123
|
+
each do |breakpoint|
|
124
|
+
breakpoint.enabled = false
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def to_a
|
129
|
+
breakpoints
|
130
|
+
end
|
131
|
+
|
132
|
+
def size
|
133
|
+
to_a.size
|
134
|
+
end
|
135
|
+
|
136
|
+
def each(&block)
|
137
|
+
to_a.each(&block)
|
138
|
+
end
|
139
|
+
|
140
|
+
def last
|
141
|
+
to_a.last
|
142
|
+
end
|
143
|
+
|
144
|
+
def find_by_id(id)
|
145
|
+
breakpoint = find { |b| b.id == id }
|
146
|
+
raise(ArgumentError, "No breakpoint ##{id}!") unless breakpoint
|
147
|
+
|
148
|
+
breakpoint
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def change_status(id, enabled = true)
|
154
|
+
breakpoint = find_by_id(id)
|
155
|
+
breakpoint.enabled = enabled
|
156
|
+
breakpoint
|
157
|
+
end
|
158
|
+
|
159
|
+
def validate_expression(exp)
|
160
|
+
valid = exp && (exp.empty? || !Pry::Code.complete_expression?(exp))
|
161
|
+
return unless valid
|
162
|
+
|
163
|
+
raise("Invalid breakpoint conditional: #{expression}")
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|