debug 1.3.3 → 1.5.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 +4 -4
- data/CONTRIBUTING.md +163 -6
- data/Gemfile +1 -0
- data/README.md +42 -15
- data/Rakefile +5 -5
- data/debug.gemspec +6 -4
- data/ext/debug/debug.c +88 -1
- data/ext/debug/extconf.rb +11 -0
- data/lib/debug/breakpoint.rb +75 -36
- data/lib/debug/client.rb +65 -18
- data/lib/debug/color.rb +29 -19
- data/lib/debug/config.rb +6 -3
- data/lib/debug/console.rb +50 -15
- data/lib/debug/frame_info.rb +14 -20
- data/lib/debug/local.rb +1 -1
- data/lib/debug/prelude.rb +2 -2
- data/lib/debug/server.rb +100 -94
- data/lib/debug/server_cdp.rb +878 -160
- data/lib/debug/server_dap.rb +277 -81
- data/lib/debug/session.rb +327 -154
- data/lib/debug/source_repository.rb +90 -52
- data/lib/debug/thread_client.rb +149 -78
- data/lib/debug/tracer.rb +4 -10
- data/lib/debug/version.rb +1 -1
- data/misc/README.md.erb +16 -8
- metadata +4 -12
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -24
- data/.github/ISSUE_TEMPLATE/custom.md +0 -10
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -14
- data/.github/workflows/ruby.yml +0 -34
- data/.gitignore +0 -12
- data/bin/console +0 -14
- data/bin/gentest +0 -22
- data/bin/setup +0 -8
data/lib/debug/breakpoint.rb
CHANGED
@@ -4,11 +4,17 @@ require_relative 'color'
|
|
4
4
|
|
5
5
|
module DEBUGGER__
|
6
6
|
class Breakpoint
|
7
|
+
include SkipPathHelper
|
8
|
+
|
7
9
|
attr_reader :key
|
8
10
|
|
9
|
-
def initialize do_enable
|
11
|
+
def initialize cond, command, path, do_enable: true
|
10
12
|
@deleted = false
|
11
13
|
|
14
|
+
@cond = cond
|
15
|
+
@command = command
|
16
|
+
@path = path
|
17
|
+
|
12
18
|
setup
|
13
19
|
enable if do_enable
|
14
20
|
end
|
@@ -23,6 +29,10 @@ module DEBUGGER__
|
|
23
29
|
nil
|
24
30
|
end
|
25
31
|
|
32
|
+
def oneshot?
|
33
|
+
defined?(@oneshot) && @oneshot
|
34
|
+
end
|
35
|
+
|
26
36
|
def setup
|
27
37
|
raise "not implemented..."
|
28
38
|
end
|
@@ -75,6 +85,17 @@ module DEBUGGER__
|
|
75
85
|
false
|
76
86
|
end
|
77
87
|
|
88
|
+
def skip_path?(path)
|
89
|
+
case @path
|
90
|
+
when Regexp
|
91
|
+
!path.match?(@path)
|
92
|
+
when String
|
93
|
+
!path.include?(@path)
|
94
|
+
else
|
95
|
+
super
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
78
99
|
include Color
|
79
100
|
|
80
101
|
def generate_label(name)
|
@@ -87,24 +108,43 @@ module DEBUGGER__
|
|
87
108
|
TracePoint.new(:line){}.enable{}
|
88
109
|
end
|
89
110
|
|
111
|
+
class ISeqBreakpoint < Breakpoint
|
112
|
+
def initialize iseq, events, oneshot: false
|
113
|
+
@events = events
|
114
|
+
@iseq = iseq
|
115
|
+
@oneshot = oneshot
|
116
|
+
@key = [:iseq, @iseq.path, @iseq.first_lineno].freeze
|
117
|
+
|
118
|
+
super(nil, nil, nil)
|
119
|
+
end
|
120
|
+
|
121
|
+
def setup
|
122
|
+
@tp = TracePoint.new(*@events) do |tp|
|
123
|
+
delete if @oneshot
|
124
|
+
suspend
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def enable
|
129
|
+
@tp.enable(target: @iseq)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
90
133
|
class LineBreakpoint < Breakpoint
|
91
134
|
attr_reader :path, :line, :iseq
|
92
135
|
|
93
136
|
def initialize path, line, cond: nil, oneshot: false, hook_call: true, command: nil
|
94
|
-
@path = path
|
95
137
|
@line = line
|
96
|
-
@cond = cond
|
97
138
|
@oneshot = oneshot
|
98
139
|
@hook_call = hook_call
|
99
|
-
@command = command
|
100
140
|
@pending = false
|
101
141
|
|
102
142
|
@iseq = nil
|
103
143
|
@type = nil
|
104
144
|
|
105
|
-
@key = [
|
145
|
+
@key = [path, @line].freeze
|
106
146
|
|
107
|
-
super()
|
147
|
+
super(cond, command, path)
|
108
148
|
|
109
149
|
try_activate
|
110
150
|
@pending = !@iseq
|
@@ -180,7 +220,7 @@ module DEBUGGER__
|
|
180
220
|
nearest = nil # NearestISeq
|
181
221
|
|
182
222
|
ObjectSpace.each_iseq{|iseq|
|
183
|
-
if (iseq.absolute_path || iseq.path)
|
223
|
+
if DEBUGGER__.compare_path((iseq.absolute_path || iseq.path), self.path) &&
|
184
224
|
iseq.first_lineno <= self.line &&
|
185
225
|
iseq.type != :ensure # ensure iseq is copied (duplicated)
|
186
226
|
|
@@ -235,24 +275,21 @@ module DEBUGGER__
|
|
235
275
|
|
236
276
|
class CatchBreakpoint < Breakpoint
|
237
277
|
attr_reader :last_exc
|
238
|
-
include SkipPathHelper
|
239
278
|
|
240
|
-
def initialize pat, cond: nil, command: nil
|
279
|
+
def initialize pat, cond: nil, command: nil, path: nil
|
241
280
|
@pat = pat.freeze
|
242
281
|
@key = [:catch, @pat].freeze
|
243
282
|
@last_exc = nil
|
244
283
|
|
245
|
-
|
246
|
-
@command = command
|
247
|
-
|
248
|
-
super()
|
284
|
+
super(cond, command, path)
|
249
285
|
end
|
250
286
|
|
251
287
|
def setup
|
252
288
|
@tp = TracePoint.new(:raise){|tp|
|
253
|
-
next if skip_path?(tp.path)
|
254
289
|
exc = tp.raised_exception
|
255
290
|
next if SystemExit === exc
|
291
|
+
next if skip_path?(tp.path)
|
292
|
+
|
256
293
|
next if !safe_eval(tp.binding, @cond) if @cond
|
257
294
|
should_suspend = false
|
258
295
|
|
@@ -277,47 +314,52 @@ module DEBUGGER__
|
|
277
314
|
end
|
278
315
|
|
279
316
|
class CheckBreakpoint < Breakpoint
|
280
|
-
def initialize
|
281
|
-
@
|
282
|
-
@key = [:check, @expr].freeze
|
317
|
+
def initialize cond:, command: nil, path: nil
|
318
|
+
@key = [:check, cond].freeze
|
283
319
|
|
284
|
-
super()
|
320
|
+
super(cond, command, path)
|
285
321
|
end
|
286
322
|
|
287
323
|
def setup
|
288
324
|
@tp = TracePoint.new(:line){|tp|
|
289
|
-
next if
|
290
|
-
next if tp.path.start_with? '<internal:'
|
325
|
+
next if SESSION.in_subsession? # TODO: Ractor support
|
291
326
|
next if ThreadClient.current.management?
|
327
|
+
next if skip_path?(tp.path)
|
292
328
|
|
293
|
-
if safe_eval tp.binding, @
|
329
|
+
if safe_eval tp.binding, @cond
|
294
330
|
suspend
|
295
331
|
end
|
296
332
|
}
|
297
333
|
end
|
298
334
|
|
299
335
|
def to_s
|
300
|
-
"#{generate_label("Check")}
|
336
|
+
s = "#{generate_label("Check")}"
|
337
|
+
s += super
|
338
|
+
s
|
301
339
|
end
|
302
340
|
end
|
303
341
|
|
304
342
|
class WatchIVarBreakpoint < Breakpoint
|
305
|
-
def initialize ivar, object, current
|
343
|
+
def initialize ivar, object, current, cond: nil, command: nil, path: nil
|
306
344
|
@ivar = ivar.to_sym
|
307
345
|
@object = object
|
308
|
-
@key = [:watch, @ivar].freeze
|
346
|
+
@key = [:watch, object.object_id, @ivar].freeze
|
309
347
|
|
310
348
|
@current = current
|
311
|
-
|
349
|
+
|
350
|
+
super(cond, command, path)
|
312
351
|
end
|
313
352
|
|
314
|
-
def watch_eval
|
353
|
+
def watch_eval(tp)
|
315
354
|
result = @object.instance_variable_get(@ivar)
|
316
355
|
if result != @current
|
317
356
|
begin
|
318
357
|
@prev = @current
|
319
358
|
@current = result
|
320
|
-
|
359
|
+
|
360
|
+
if (@cond.nil? || @object.instance_eval(@cond)) && !skip_path?(tp.path)
|
361
|
+
suspend
|
362
|
+
end
|
321
363
|
ensure
|
322
364
|
remove_instance_variable(:@prev)
|
323
365
|
end
|
@@ -328,10 +370,7 @@ module DEBUGGER__
|
|
328
370
|
|
329
371
|
def setup
|
330
372
|
@tp = TracePoint.new(:line, :return, :b_return){|tp|
|
331
|
-
|
332
|
-
next if tp.path.start_with? '<internal:'
|
333
|
-
|
334
|
-
watch_eval
|
373
|
+
watch_eval(tp)
|
335
374
|
}
|
336
375
|
end
|
337
376
|
|
@@ -349,7 +388,7 @@ module DEBUGGER__
|
|
349
388
|
class MethodBreakpoint < Breakpoint
|
350
389
|
attr_reader :sig_method_name, :method
|
351
390
|
|
352
|
-
def initialize b, klass_name, op, method_name, cond: nil, command: nil
|
391
|
+
def initialize b, klass_name, op, method_name, cond: nil, command: nil, path: nil
|
353
392
|
@sig_klass_name = klass_name
|
354
393
|
@sig_op = op
|
355
394
|
@sig_method_name = method_name
|
@@ -358,19 +397,19 @@ module DEBUGGER__
|
|
358
397
|
|
359
398
|
@klass = nil
|
360
399
|
@method = nil
|
361
|
-
@cond = cond
|
362
400
|
@cond_class = nil
|
363
|
-
@command = command
|
364
401
|
@key = "#{klass_name}#{op}#{method_name}".freeze
|
365
402
|
|
366
|
-
super(false)
|
403
|
+
super(cond, command, path, do_enable: false)
|
367
404
|
end
|
368
405
|
|
369
406
|
def setup
|
370
407
|
@tp = TracePoint.new(:call){|tp|
|
371
408
|
next if !safe_eval(tp.binding, @cond) if @cond
|
372
409
|
next if @cond_class && !tp.self.kind_of?(@cond_class)
|
373
|
-
|
410
|
+
|
411
|
+
caller_location = caller_locations(2, 1).first.to_s
|
412
|
+
next if skip_path?(caller_location)
|
374
413
|
|
375
414
|
suspend
|
376
415
|
}
|
data/lib/debug/client.rb
CHANGED
@@ -18,29 +18,69 @@ module DEBUGGER__
|
|
18
18
|
case name
|
19
19
|
when 'gen-sockpath'
|
20
20
|
puts DEBUGGER__.create_unix_domain_socket_name
|
21
|
+
when 'gen-portpath'
|
22
|
+
port_path = File.join(DEBUGGER__.unix_domain_socket_dir, 'tcp_port')
|
23
|
+
File.unlink port_path if File.exist?(port_path)
|
24
|
+
puts port_path
|
21
25
|
when 'list-socks'
|
22
26
|
cleanup_unix_domain_sockets
|
23
27
|
puts list_connections
|
24
|
-
when '
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
28
|
+
when 'setup-autoload'
|
29
|
+
setup_autoload
|
30
|
+
else
|
31
|
+
abort "Unknown utility: #{name}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def working_shell_type
|
36
|
+
shell = `ps -p #{Process.ppid} -o 'args='`
|
37
|
+
case shell
|
38
|
+
when /bash/
|
39
|
+
:bash
|
40
|
+
when /fish/
|
41
|
+
:fish
|
42
|
+
when /csh/
|
43
|
+
:csh
|
44
|
+
when /zsh/
|
45
|
+
:szh
|
46
|
+
when /dash/
|
47
|
+
:dash
|
48
|
+
else
|
49
|
+
:unknown
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def setup_autoload
|
54
|
+
prelude_path = File.join(__dir__, 'prelude.rb')
|
55
|
+
|
56
|
+
case shell = working_shell_type
|
57
|
+
when :bash, :zsh
|
58
|
+
puts <<~EOS
|
59
|
+
# add the following lines in your ~/.#{shell}_profile
|
60
|
+
|
61
|
+
if test -s #{prelude_path} ; then
|
62
|
+
export RUBYOPT='-r #{prelude_path}'
|
63
|
+
fi
|
64
|
+
|
65
|
+
# Add `Kernel#bb` method which is alias of `Kernel#debugger`
|
66
|
+
# export RUBY_DEBUG_BB=1
|
67
|
+
EOS
|
68
|
+
|
69
|
+
when :fish
|
70
|
+
puts <<~EOS
|
71
|
+
# add the following lines in your ~/.config/fish/config.fish
|
72
|
+
set -x RUBYOPT "-r #{__dir__}/prelude" $RUBYOPT
|
73
|
+
EOS
|
74
|
+
|
36
75
|
else
|
37
|
-
|
76
|
+
puts "# Sorry that your shell is not supported yet.",
|
77
|
+
"# Please use the content in #{prelude_path} as a reference and modify your login script accordingly."
|
38
78
|
end
|
39
79
|
end
|
40
80
|
|
41
81
|
def cleanup_unix_domain_sockets
|
42
82
|
Dir.glob(DEBUGGER__.create_unix_domain_socket_name_prefix + '*') do |file|
|
43
|
-
if
|
83
|
+
if File.socket?(file) && (/-(\d+)-\d+$/ =~ file || /-(\d+)$/ =~ file)
|
44
84
|
begin
|
45
85
|
Process.kill(0, $1.to_i)
|
46
86
|
rescue Errno::EPERM
|
@@ -52,7 +92,9 @@ module DEBUGGER__
|
|
52
92
|
end
|
53
93
|
|
54
94
|
def list_connections
|
55
|
-
Dir.glob(DEBUGGER__.create_unix_domain_socket_name_prefix + '*')
|
95
|
+
Dir.glob(DEBUGGER__.create_unix_domain_socket_name_prefix + '*').find_all do |path|
|
96
|
+
File.socket?(path)
|
97
|
+
end
|
56
98
|
end
|
57
99
|
end
|
58
100
|
|
@@ -134,9 +176,14 @@ module DEBUGGER__
|
|
134
176
|
trap(:SIGINT){
|
135
177
|
send "pause"
|
136
178
|
}
|
137
|
-
|
138
|
-
|
139
|
-
|
179
|
+
|
180
|
+
begin
|
181
|
+
trap(:SIGWINCH){
|
182
|
+
@width = IO.console_size[1]
|
183
|
+
}
|
184
|
+
rescue ArgumentError
|
185
|
+
@width = 80
|
186
|
+
end
|
140
187
|
|
141
188
|
while line = @s.gets
|
142
189
|
p recv: line if $VERBOSE
|
data/lib/debug/color.rb
CHANGED
@@ -48,33 +48,29 @@ module DEBUGGER__
|
|
48
48
|
|
49
49
|
if defined? IRB::ColorPrinter.pp
|
50
50
|
def color_pp obj, width
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
with_inspection_error_guard do
|
52
|
+
if !CONFIG[:no_color]
|
53
|
+
IRB::ColorPrinter.pp(obj, "".dup, width)
|
54
|
+
else
|
55
|
+
obj.pretty_inspect
|
56
|
+
end
|
55
57
|
end
|
56
58
|
end
|
57
59
|
else
|
58
60
|
def color_pp obj, width
|
59
|
-
|
61
|
+
with_inspection_error_guard do
|
62
|
+
obj.pretty_inspect
|
63
|
+
end
|
60
64
|
end
|
61
65
|
end
|
62
66
|
|
63
67
|
def colored_inspect obj, width: SESSION.width, no_color: false
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
err_msg = "#{ex.inspect} rescued during inspection"
|
71
|
-
string_result = obj.to_s rescue nil
|
72
|
-
|
73
|
-
# don't colorize the string here because it's not from user's application
|
74
|
-
if string_result
|
75
|
-
%Q{"#{string_result}" from #to_s because #{err_msg}}
|
76
|
-
else
|
77
|
-
err_msg
|
68
|
+
with_inspection_error_guard do
|
69
|
+
if !no_color
|
70
|
+
color_pp obj, width
|
71
|
+
else
|
72
|
+
obj.pretty_inspect
|
73
|
+
end
|
78
74
|
end
|
79
75
|
end
|
80
76
|
|
@@ -109,5 +105,19 @@ module DEBUGGER__
|
|
109
105
|
def colorize_dim(str)
|
110
106
|
colorize(str, [:DIM])
|
111
107
|
end
|
108
|
+
|
109
|
+
def with_inspection_error_guard
|
110
|
+
yield
|
111
|
+
rescue Exception => ex
|
112
|
+
err_msg = "#{ex.inspect} rescued during inspection"
|
113
|
+
string_result = obj.to_s rescue nil
|
114
|
+
|
115
|
+
# don't colorize the string here because it's not from user's application
|
116
|
+
if string_result
|
117
|
+
%Q{"#{string_result}" from #to_s because #{err_msg}}
|
118
|
+
else
|
119
|
+
err_msg
|
120
|
+
end
|
121
|
+
end
|
112
122
|
end
|
113
123
|
end
|
data/lib/debug/config.rb
CHANGED
@@ -43,20 +43,23 @@ module DEBUGGER__
|
|
43
43
|
sock_dir: ['RUBY_DEBUG_SOCK_DIR', "REMOTE: UNIX Domain Socket remote debugging: socket directory"],
|
44
44
|
cookie: ['RUBY_DEBUG_COOKIE', "REMOTE: Cookie for negotiation"],
|
45
45
|
open_frontend: ['RUBY_DEBUG_OPEN_FRONTEND',"REMOTE: frontend used by open command (vscode, chrome, default: rdbg)."],
|
46
|
+
chrome_path: ['RUBY_DEBUG_CHROME_PATH', "REMOTE: Platform dependent path of Chrome (For more information, See [here](https://github.com/ruby/debug/pull/334/files#diff-5fc3d0a901379a95bc111b86cf0090b03f857edfd0b99a0c1537e26735698453R55-R64))"],
|
46
47
|
|
47
48
|
# obsolete
|
48
49
|
parent_on_fork: ['RUBY_DEBUG_PARENT_ON_FORK', "OBSOLETE: Keep debugging parent process on fork (default: false)", :bool],
|
49
50
|
}.freeze
|
50
51
|
|
51
|
-
CONFIG_MAP = CONFIG_SET.map{|k, (ev,
|
52
|
+
CONFIG_MAP = CONFIG_SET.map{|k, (ev, _)| [k, ev]}.to_h.freeze
|
52
53
|
|
53
54
|
class Config
|
55
|
+
@config = nil
|
56
|
+
|
54
57
|
def self.config
|
55
58
|
@config
|
56
59
|
end
|
57
60
|
|
58
61
|
def initialize argv
|
59
|
-
if self.class.
|
62
|
+
if self.class.config
|
60
63
|
raise 'Can not make multiple configurations in one process'
|
61
64
|
end
|
62
65
|
|
@@ -480,7 +483,7 @@ module DEBUGGER__
|
|
480
483
|
self.helps.each{|cat, cmds|
|
481
484
|
r << "### #{cat}"
|
482
485
|
r << ''
|
483
|
-
cmds.each{|
|
486
|
+
cmds.each{|_, desc|
|
484
487
|
r << desc
|
485
488
|
}
|
486
489
|
r << ''
|
data/lib/debug/console.rb
CHANGED
@@ -30,10 +30,38 @@ module DEBUGGER__
|
|
30
30
|
prepend m
|
31
31
|
end if SIGWINCH_SUPPORTED
|
32
32
|
|
33
|
+
def parse_input buff, commands
|
34
|
+
c, rest = get_command buff
|
35
|
+
case
|
36
|
+
when commands.keys.include?(c)
|
37
|
+
:command
|
38
|
+
when !rest && /\A\s*[a-z]*\z/ =~ c
|
39
|
+
nil
|
40
|
+
else
|
41
|
+
:ruby
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
33
45
|
def readline_setup prompt
|
34
46
|
load_history_if_not_loaded
|
35
47
|
commands = DEBUGGER__.commands
|
36
48
|
|
49
|
+
prev_completion_proc = Reline.completion_proc
|
50
|
+
prev_output_modifier_proc = Reline.output_modifier_proc
|
51
|
+
prev_prompt_proc = Reline.prompt_proc
|
52
|
+
|
53
|
+
# prompt state
|
54
|
+
state = nil # :command, :ruby, nil (unknown)
|
55
|
+
|
56
|
+
Reline.prompt_proc = -> args, *kw do
|
57
|
+
case state = parse_input(args.first, commands)
|
58
|
+
when nil, :command
|
59
|
+
[prompt, prompt]
|
60
|
+
when :ruby
|
61
|
+
[prompt.sub('rdbg'){colorize('ruby', [:RED])}] * 2
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
37
65
|
Reline.completion_proc = -> given do
|
38
66
|
buff = Reline.line_buffer
|
39
67
|
Reline.completion_append_character= ' '
|
@@ -46,17 +74,16 @@ module DEBUGGER__
|
|
46
74
|
end
|
47
75
|
files
|
48
76
|
else
|
49
|
-
commands.keys.grep(/\A#{given}/)
|
77
|
+
commands.keys.grep(/\A#{Regexp.escape(given)}/)
|
50
78
|
end
|
51
79
|
end
|
52
80
|
|
53
81
|
Reline.output_modifier_proc = -> buff, **kw do
|
54
82
|
c, rest = get_command buff
|
55
83
|
|
56
|
-
case
|
57
|
-
when
|
58
|
-
|
59
|
-
cmd = colorize(c.strip, [:CYAN, :UNDERLINE])
|
84
|
+
case state
|
85
|
+
when :command
|
86
|
+
cmd = colorize(c, [:CYAN, :UNDERLINE])
|
60
87
|
|
61
88
|
if commands[c] == c
|
62
89
|
rprompt = colorize(" # command", [:DIM])
|
@@ -64,28 +91,36 @@ module DEBUGGER__
|
|
64
91
|
rprompt = colorize(" # #{commands[c]} command", [:DIM])
|
65
92
|
end
|
66
93
|
|
67
|
-
rest =
|
68
|
-
cmd + rest
|
69
|
-
when
|
94
|
+
rest = rest ? colorize_code(rest) : ''
|
95
|
+
cmd + rest + rprompt
|
96
|
+
when nil
|
70
97
|
buff
|
71
|
-
|
72
|
-
colorize_code(buff.chomp)
|
98
|
+
when :ruby
|
99
|
+
colorize_code(buff.chomp)
|
73
100
|
end
|
74
101
|
end
|
102
|
+
|
103
|
+
yield
|
104
|
+
|
105
|
+
ensure
|
106
|
+
Reline.completion_proc = prev_completion_proc
|
107
|
+
Reline.output_modifier_proc = prev_output_modifier_proc
|
108
|
+
Reline.prompt_proc = prev_prompt_proc
|
75
109
|
end
|
76
110
|
|
77
111
|
private def get_command line
|
78
112
|
case line.chomp
|
79
113
|
when /\A(\s*[a-z]+)(\s.*)?\z$/
|
80
|
-
return $1, $2
|
114
|
+
return $1.strip, $2
|
81
115
|
else
|
82
|
-
line.
|
116
|
+
line.strip
|
83
117
|
end
|
84
118
|
end
|
85
119
|
|
86
120
|
def readline prompt
|
87
|
-
readline_setup prompt
|
88
|
-
|
121
|
+
readline_setup prompt do
|
122
|
+
Reline.readmultiline(prompt, true){ true }
|
123
|
+
end
|
89
124
|
end
|
90
125
|
|
91
126
|
def history
|
@@ -145,7 +180,7 @@ module DEBUGGER__
|
|
145
180
|
FH = "# Today's OMIKUJI: "
|
146
181
|
|
147
182
|
def read_history_file
|
148
|
-
if history && File.
|
183
|
+
if history && File.exist?(path = history_file)
|
149
184
|
f = (['', 'DAI-', 'CHU-', 'SHO-'].map{|e| e+'KICHI'}+['KYO']).sample
|
150
185
|
["#{FH}#{f}".dup] + File.readlines(path)
|
151
186
|
else
|
data/lib/debug/frame_info.rb
CHANGED
@@ -2,10 +2,11 @@
|
|
2
2
|
|
3
3
|
module DEBUGGER__
|
4
4
|
FrameInfo = Struct.new(:location, :self, :binding, :iseq, :class, :frame_depth,
|
5
|
-
:has_return_value,
|
5
|
+
:has_return_value, :return_value,
|
6
6
|
:has_raised_exception, :raised_exception,
|
7
7
|
:show_line,
|
8
|
-
:_local_variables, :_callee # for recorder
|
8
|
+
:_local_variables, :_callee, # for recorder
|
9
|
+
:dupped_binding,
|
9
10
|
)
|
10
11
|
|
11
12
|
# extend FrameInfo with debug.so
|
@@ -31,7 +32,7 @@ module DEBUGGER__
|
|
31
32
|
use_short_path = CONFIG[:use_short_path]
|
32
33
|
|
33
34
|
case
|
34
|
-
when use_short_path && path.start_with?(dir = CONFIG["rubylibdir"] + '/')
|
35
|
+
when use_short_path && path.start_with?(dir = RbConfig::CONFIG["rubylibdir"] + '/')
|
35
36
|
path.sub(dir, '$(rubylibdir)/')
|
36
37
|
when use_short_path && Gem.path.any? do |gp|
|
37
38
|
path.start_with?(dir = gp + '/gems/')
|
@@ -82,14 +83,14 @@ module DEBUGGER__
|
|
82
83
|
|
83
84
|
def block_identifier
|
84
85
|
return unless frame_type == :block
|
85
|
-
args = parameters_info
|
86
|
+
args = parameters_info
|
86
87
|
_, level, block_loc = location.label.match(BLOCK_LABL_REGEXP).to_a
|
87
88
|
[level || "", block_loc, args]
|
88
89
|
end
|
89
90
|
|
90
91
|
def method_identifier
|
91
92
|
return unless frame_type == :method
|
92
|
-
args = parameters_info
|
93
|
+
args = parameters_info
|
93
94
|
ci = "#{klass_sig}#{callee}"
|
94
95
|
[ci, args]
|
95
96
|
end
|
@@ -110,7 +111,7 @@ module DEBUGGER__
|
|
110
111
|
|
111
112
|
def return_str
|
112
113
|
if self.binding && iseq && has_return_value
|
113
|
-
DEBUGGER__.
|
114
|
+
DEBUGGER__.safe_inspect(return_value, short: true)
|
114
115
|
end
|
115
116
|
end
|
116
117
|
|
@@ -118,19 +119,12 @@ module DEBUGGER__
|
|
118
119
|
"#{pretty_path}:#{location.lineno}"
|
119
120
|
end
|
120
121
|
|
121
|
-
private def make_binding
|
122
|
-
__newb__ = self.self.instance_eval('binding')
|
123
|
-
self.local_variables.each{|var, val|
|
124
|
-
__newb__.local_variable_set(var, val)
|
125
|
-
}
|
126
|
-
__newb__
|
127
|
-
end
|
128
|
-
|
129
122
|
def eval_binding
|
130
|
-
if b = self.
|
123
|
+
if b = self.dupped_binding
|
131
124
|
b
|
132
|
-
|
133
|
-
|
125
|
+
else
|
126
|
+
b = self.binding || TOPLEVEL_BINDING
|
127
|
+
self.dupped_binding = b.dup
|
134
128
|
end
|
135
129
|
end
|
136
130
|
|
@@ -156,11 +150,11 @@ module DEBUGGER__
|
|
156
150
|
local_variables[var]
|
157
151
|
end
|
158
152
|
|
159
|
-
def parameters_info
|
160
|
-
vars = iseq.
|
153
|
+
def parameters_info
|
154
|
+
vars = iseq.parameters_symbols
|
161
155
|
vars.map{|var|
|
162
156
|
begin
|
163
|
-
{ name: var, value: DEBUGGER__.
|
157
|
+
{ name: var, value: DEBUGGER__.safe_inspect(local_variable_get(var), short: true) }
|
164
158
|
rescue NameError, TypeError
|
165
159
|
nil
|
166
160
|
end
|
data/lib/debug/local.rb
CHANGED
data/lib/debug/prelude.rb
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
return if defined?(::DEBUGGER__)
|
4
4
|
|
5
|
+
# Put the following line in your login script (e.g. ~/.bash_profile) with modified path:
|
5
6
|
#
|
6
|
-
#
|
7
|
-
# export RUBYOPT="-r .../debug/prelude $(RUBYOPT)"
|
7
|
+
# export RUBYOPT="-r /path/to/debug/prelude $(RUBYOPT)"
|
8
8
|
#
|
9
9
|
module Kernel
|
10
10
|
def debugger(*a, up_level: 0, **kw)
|