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/server_dap.rb
CHANGED
@@ -1,10 +1,68 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'json'
|
4
|
+
require 'irb/completion'
|
5
|
+
require 'tmpdir'
|
6
|
+
require 'fileutils'
|
4
7
|
|
5
8
|
module DEBUGGER__
|
6
9
|
module UI_DAP
|
7
|
-
SHOW_PROTOCOL = ENV['RUBY_DEBUG_DAP_SHOW_PROTOCOL'] == '1'
|
10
|
+
SHOW_PROTOCOL = ENV['DEBUG_DAP_SHOW_PROTOCOL'] == '1' || ENV['RUBY_DEBUG_DAP_SHOW_PROTOCOL'] == '1'
|
11
|
+
|
12
|
+
def self.setup debug_port
|
13
|
+
if File.directory? '.vscode'
|
14
|
+
dir = Dir.pwd
|
15
|
+
else
|
16
|
+
dir = Dir.mktmpdir("ruby-debug-vscode-")
|
17
|
+
tempdir = true
|
18
|
+
end
|
19
|
+
|
20
|
+
at_exit do
|
21
|
+
CONFIG[:skip_path] = [//] # skip all
|
22
|
+
FileUtils.rm_rf dir if tempdir
|
23
|
+
end
|
24
|
+
|
25
|
+
key = rand.to_s
|
26
|
+
|
27
|
+
Dir.chdir(dir) do
|
28
|
+
Dir.mkdir('.vscode') if tempdir
|
29
|
+
|
30
|
+
# vscode-rdbg 0.0.9 or later is needed
|
31
|
+
open('.vscode/rdbg_autoattach.json', 'w') do |f|
|
32
|
+
f.puts JSON.pretty_generate({
|
33
|
+
type: "rdbg",
|
34
|
+
name: "Attach with rdbg",
|
35
|
+
request: "attach",
|
36
|
+
rdbgPath: File.expand_path('../../exe/rdbg', __dir__),
|
37
|
+
debugPort: debug_port,
|
38
|
+
localfs: true,
|
39
|
+
autoAttach: key,
|
40
|
+
})
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
cmds = ['code', "#{dir}/"]
|
45
|
+
cmdline = cmds.join(' ')
|
46
|
+
ssh_cmdline = "code --remote ssh-remote+[SSH hostname] #{dir}/"
|
47
|
+
|
48
|
+
STDERR.puts "Launching: #{cmdline}"
|
49
|
+
env = ENV.delete_if{|k, h| /RUBY/ =~ k}.to_h
|
50
|
+
env['RUBY_DEBUG_AUTOATTACH'] = key
|
51
|
+
|
52
|
+
unless system(env, *cmds)
|
53
|
+
DEBUGGER__.warn <<~MESSAGE
|
54
|
+
Can not invoke the command.
|
55
|
+
Use the command-line on your terminal (with modification if you need).
|
56
|
+
|
57
|
+
#{cmdline}
|
58
|
+
|
59
|
+
If your application is running on a SSH remote host, please try:
|
60
|
+
|
61
|
+
#{ssh_cmdline}
|
62
|
+
|
63
|
+
MESSAGE
|
64
|
+
end
|
65
|
+
end
|
8
66
|
|
9
67
|
def show_protocol dir, msg
|
10
68
|
if SHOW_PROTOCOL
|
@@ -12,9 +70,20 @@ module DEBUGGER__
|
|
12
70
|
end
|
13
71
|
end
|
14
72
|
|
73
|
+
@local_fs = false
|
74
|
+
|
75
|
+
def self.local_fs
|
76
|
+
@local_fs
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.local_fs_set
|
80
|
+
@local_fs = true
|
81
|
+
end
|
82
|
+
|
15
83
|
def dap_setup bytes
|
16
84
|
CONFIG.set_config no_color: true
|
17
85
|
@seq = 0
|
86
|
+
UI_DAP.local_fs_set if self.kind_of?(UI_UnixDomainServer)
|
18
87
|
|
19
88
|
show_protocol :>, bytes
|
20
89
|
req = JSON.load(bytes)
|
@@ -44,11 +113,12 @@ module DEBUGGER__
|
|
44
113
|
],
|
45
114
|
supportsExceptionFilterOptions: true,
|
46
115
|
supportsStepBack: true,
|
116
|
+
supportsEvaluateForHovers: true,
|
117
|
+
supportsCompletionsRequest: true,
|
47
118
|
|
48
119
|
## Will be supported
|
49
120
|
# supportsExceptionOptions: true,
|
50
121
|
# supportsHitConditionalBreakpoints:
|
51
|
-
# supportsEvaluateForHovers:
|
52
122
|
# supportsSetVariable: true,
|
53
123
|
# supportSuspendDebuggee:
|
54
124
|
# supportsLogPoints:
|
@@ -58,7 +128,6 @@ module DEBUGGER__
|
|
58
128
|
|
59
129
|
## Possible?
|
60
130
|
# supportsRestartFrame:
|
61
|
-
# supportsCompletionsRequest:
|
62
131
|
# completionTriggerCharacters:
|
63
132
|
# supportsModulesRequest:
|
64
133
|
# additionalModuleColumns:
|
@@ -86,23 +155,23 @@ module DEBUGGER__
|
|
86
155
|
def send **kw
|
87
156
|
kw[:seq] = @seq += 1
|
88
157
|
str = JSON.dump(kw)
|
158
|
+
@sock.write "Content-Length: #{str.bytesize}\r\n\r\n#{str}"
|
89
159
|
show_protocol '<', str
|
90
|
-
@sock.write "Content-Length: #{str.size}\r\n\r\n#{str}"
|
91
160
|
end
|
92
161
|
|
93
|
-
def send_response req, success: true, **kw
|
162
|
+
def send_response req, success: true, message: nil, **kw
|
94
163
|
if kw.empty?
|
95
164
|
send type: 'response',
|
96
165
|
command: req['command'],
|
97
166
|
request_seq: req['seq'],
|
98
167
|
success: success,
|
99
|
-
message: success ? 'Success' : 'Failed'
|
168
|
+
message: message || (success ? 'Success' : 'Failed')
|
100
169
|
else
|
101
170
|
send type: 'response',
|
102
171
|
command: req['command'],
|
103
172
|
request_seq: req['seq'],
|
104
173
|
success: success,
|
105
|
-
message: success ? 'Success' : 'Failed',
|
174
|
+
message: message || (success ? 'Success' : 'Failed'),
|
106
175
|
body: kw
|
107
176
|
end
|
108
177
|
end
|
@@ -119,29 +188,27 @@ module DEBUGGER__
|
|
119
188
|
end
|
120
189
|
|
121
190
|
def recv_request
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
@
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
raise "unrecognized line: #{l} (#{l.size} bytes)"
|
140
|
-
end
|
191
|
+
r = IO.select([@sock])
|
192
|
+
|
193
|
+
@session.process_group.sync do
|
194
|
+
raise RetryBecauseCantRead unless IO.select([@sock], nil, nil, 0)
|
195
|
+
|
196
|
+
case header = @sock.gets
|
197
|
+
when /Content-Length: (\d+)/
|
198
|
+
b = @sock.read(2)
|
199
|
+
raise b.inspect unless b == "\r\n"
|
200
|
+
|
201
|
+
l = @sock.read(s = $1.to_i)
|
202
|
+
show_protocol :>, l
|
203
|
+
JSON.load(l)
|
204
|
+
when nil
|
205
|
+
nil
|
206
|
+
else
|
207
|
+
raise "unrecognized line: #{l} (#{l.size} bytes)"
|
141
208
|
end
|
142
|
-
rescue RetryBecauseCantRead
|
143
|
-
retry
|
144
209
|
end
|
210
|
+
rescue RetryBecauseCantRead
|
211
|
+
retry
|
145
212
|
end
|
146
213
|
|
147
214
|
def process
|
@@ -155,15 +222,18 @@ module DEBUGGER__
|
|
155
222
|
when 'launch'
|
156
223
|
send_response req
|
157
224
|
@is_attach = false
|
225
|
+
UI_DAP.local_fs_set if req.dig('arguments', 'localfs')
|
158
226
|
when 'attach'
|
159
227
|
send_response req
|
160
|
-
Process.kill(
|
228
|
+
Process.kill(UI_ServerBase::TRAP_SIGNAL, Process.pid)
|
161
229
|
@is_attach = true
|
230
|
+
UI_DAP.local_fs_set if req.dig('arguments', 'localfs')
|
162
231
|
when 'setBreakpoints'
|
163
232
|
path = args.dig('source', 'path')
|
164
|
-
|
233
|
+
SESSION.clear_line_breakpoints path
|
234
|
+
|
165
235
|
bps = []
|
166
|
-
|
236
|
+
args['breakpoints'].each{|bp|
|
167
237
|
line = bp['line']
|
168
238
|
if cond = bp['condition']
|
169
239
|
bps << SESSION.add_line_breakpoint(path, line, cond: cond)
|
@@ -222,20 +292,41 @@ module DEBUGGER__
|
|
222
292
|
@q_msg << 'c'
|
223
293
|
send_response req, allThreadsContinued: true
|
224
294
|
when 'next'
|
225
|
-
|
226
|
-
|
295
|
+
begin
|
296
|
+
@session.check_postmortem
|
297
|
+
@q_msg << 'n'
|
298
|
+
send_response req
|
299
|
+
rescue PostmortemError
|
300
|
+
send_response req,
|
301
|
+
success: false, message: 'postmortem mode',
|
302
|
+
result: "'Next' is not supported while postmortem mode"
|
303
|
+
end
|
227
304
|
when 'stepIn'
|
228
|
-
|
229
|
-
|
305
|
+
begin
|
306
|
+
@session.check_postmortem
|
307
|
+
@q_msg << 's'
|
308
|
+
send_response req
|
309
|
+
rescue PostmortemError
|
310
|
+
send_response req,
|
311
|
+
success: false, message: 'postmortem mode',
|
312
|
+
result: "'stepIn' is not supported while postmortem mode"
|
313
|
+
end
|
230
314
|
when 'stepOut'
|
231
|
-
|
232
|
-
|
315
|
+
begin
|
316
|
+
@session.check_postmortem
|
317
|
+
@q_msg << 'fin'
|
318
|
+
send_response req
|
319
|
+
rescue PostmortemError
|
320
|
+
send_response req,
|
321
|
+
success: false, message: 'postmortem mode',
|
322
|
+
result: "'stepOut' is not supported while postmortem mode"
|
323
|
+
end
|
233
324
|
when 'terminate'
|
234
325
|
send_response req
|
235
326
|
exit
|
236
327
|
when 'pause'
|
237
328
|
send_response req
|
238
|
-
Process.kill(
|
329
|
+
Process.kill(UI_ServerBase::TRAP_SIGNAL, Process.pid)
|
239
330
|
when 'reverseContinue'
|
240
331
|
send_response req,
|
241
332
|
success: false, message: 'cancelled',
|
@@ -255,13 +346,16 @@ module DEBUGGER__
|
|
255
346
|
'scopes',
|
256
347
|
'variables',
|
257
348
|
'evaluate',
|
258
|
-
'source'
|
349
|
+
'source',
|
350
|
+
'completions'
|
259
351
|
@q_msg << req
|
260
352
|
|
261
353
|
else
|
262
354
|
raise "Unknown request: #{req.inspect}"
|
263
355
|
end
|
264
356
|
end
|
357
|
+
ensure
|
358
|
+
send_event :terminated unless @sock.closed?
|
265
359
|
end
|
266
360
|
|
267
361
|
## called by the SESSION thread
|
@@ -361,7 +455,6 @@ module DEBUGGER__
|
|
361
455
|
case ref[0]
|
362
456
|
when :globals
|
363
457
|
vars = global_variables.map do |name|
|
364
|
-
File.write('/tmp/x', "#{name}\n")
|
365
458
|
gv = 'Not implemented yet...'
|
366
459
|
{
|
367
460
|
name: name,
|
@@ -402,11 +495,13 @@ module DEBUGGER__
|
|
402
495
|
end
|
403
496
|
when 'evaluate'
|
404
497
|
frame_id = req.dig('arguments', 'frameId')
|
498
|
+
context = req.dig('arguments', 'context')
|
499
|
+
|
405
500
|
if @frame_map[frame_id]
|
406
501
|
tid, fid = @frame_map[frame_id]
|
407
502
|
expr = req.dig('arguments', 'expression')
|
408
503
|
if tc = find_waiting_tc(tid)
|
409
|
-
tc << [:dap, :evaluate, req, fid, expr]
|
504
|
+
tc << [:dap, :evaluate, req, fid, expr, context]
|
410
505
|
else
|
411
506
|
fail_response req
|
412
507
|
end
|
@@ -416,11 +511,26 @@ module DEBUGGER__
|
|
416
511
|
when 'source'
|
417
512
|
ref = req.dig('arguments', 'sourceReference')
|
418
513
|
if src = @src_map[ref]
|
419
|
-
@ui.respond req, content: src.join
|
514
|
+
@ui.respond req, content: src.join("\n")
|
420
515
|
else
|
421
516
|
fail_response req, message: 'not found...'
|
422
517
|
end
|
423
518
|
return :retry
|
519
|
+
|
520
|
+
when 'completions'
|
521
|
+
frame_id = req.dig('arguments', 'frameId')
|
522
|
+
tid, fid = @frame_map[frame_id]
|
523
|
+
|
524
|
+
if tc = find_waiting_tc(tid)
|
525
|
+
text = req.dig('arguments', 'text')
|
526
|
+
line = req.dig('arguments', 'line')
|
527
|
+
if col = req.dig('arguments', 'column')
|
528
|
+
text = text.split(/\n/)[line.to_i - 1][0...(col.to_i - 1)]
|
529
|
+
end
|
530
|
+
tc << [:dap, :completions, req, fid, text]
|
531
|
+
else
|
532
|
+
fail_response req
|
533
|
+
end
|
424
534
|
else
|
425
535
|
raise "Unknown DAP request: #{req.inspect}"
|
426
536
|
end
|
@@ -458,8 +568,15 @@ module DEBUGGER__
|
|
458
568
|
register_vars result[:variables], tid
|
459
569
|
@ui.respond req, result
|
460
570
|
when :evaluate
|
461
|
-
|
462
|
-
|
571
|
+
message = result.delete :message
|
572
|
+
if message
|
573
|
+
@ui.respond req, success: false, message: message
|
574
|
+
else
|
575
|
+
tid = result.delete :tid
|
576
|
+
register_var result, tid
|
577
|
+
@ui.respond req, result
|
578
|
+
end
|
579
|
+
when :completions
|
463
580
|
@ui.respond req, result
|
464
581
|
else
|
465
582
|
raise "unsupported: #{args.inspect}"
|
@@ -491,9 +608,13 @@ module DEBUGGER__
|
|
491
608
|
case type
|
492
609
|
when :backtrace
|
493
610
|
event! :dap_result, :backtrace, req, {
|
494
|
-
stackFrames: @target_frames.map
|
611
|
+
stackFrames: @target_frames.map{|frame|
|
495
612
|
path = frame.realpath || frame.path
|
496
|
-
|
613
|
+
source_name = path ? File.basename(path) : frame.location.to_s
|
614
|
+
|
615
|
+
if !UI_DAP.local_fs || !(path && File.exist?(path))
|
616
|
+
ref = frame.file_lines
|
617
|
+
end
|
497
618
|
|
498
619
|
{
|
499
620
|
# id: ??? # filled by SESSION
|
@@ -501,7 +622,7 @@ module DEBUGGER__
|
|
501
622
|
line: frame.location.lineno,
|
502
623
|
column: 1,
|
503
624
|
source: {
|
504
|
-
name:
|
625
|
+
name: source_name,
|
505
626
|
path: path,
|
506
627
|
sourceReference: ref,
|
507
628
|
},
|
@@ -510,7 +631,7 @@ module DEBUGGER__
|
|
510
631
|
}
|
511
632
|
when :scopes
|
512
633
|
fid = args.shift
|
513
|
-
frame =
|
634
|
+
frame = get_frame(fid)
|
514
635
|
|
515
636
|
lnum =
|
516
637
|
if frame.binding
|
@@ -538,26 +659,12 @@ module DEBUGGER__
|
|
538
659
|
}]
|
539
660
|
when :scope
|
540
661
|
fid = args.shift
|
541
|
-
frame =
|
542
|
-
|
543
|
-
|
544
|
-
v = b.local_variable_get(name)
|
545
|
-
variable(name, v)
|
546
|
-
}
|
547
|
-
vars.unshift variable('%raised', frame.raised_exception) if frame.has_raised_exception
|
548
|
-
vars.unshift variable('%return', frame.return_value) if frame.has_return_value
|
549
|
-
vars.unshift variable('%self', b.receiver)
|
550
|
-
elsif lvars = frame.local_variables
|
551
|
-
vars = lvars.map{|var, val|
|
552
|
-
variable(var, val)
|
553
|
-
}
|
554
|
-
else
|
555
|
-
vars = [variable('%self', frame.self)]
|
556
|
-
vars.push variable('%raised', frame.raised_exception) if frame.has_raised_exception
|
557
|
-
vars.push variable('%return', frame.return_value) if frame.has_return_value
|
662
|
+
frame = get_frame(fid)
|
663
|
+
vars = collect_locals(frame).map do |var, val|
|
664
|
+
variable(var, val)
|
558
665
|
end
|
559
|
-
event! :dap_result, :scope, req, variables: vars, tid: self.id
|
560
666
|
|
667
|
+
event! :dap_result, :scope, req, variables: vars, tid: self.id
|
561
668
|
when :variable
|
562
669
|
vid = args.shift
|
563
670
|
obj = @var_map[vid]
|
@@ -575,7 +682,7 @@ module DEBUGGER__
|
|
575
682
|
case obj
|
576
683
|
when Hash
|
577
684
|
vars = obj.map{|k, v|
|
578
|
-
variable(DEBUGGER__.
|
685
|
+
variable(DEBUGGER__.safe_inspect(k), v,)
|
579
686
|
}
|
580
687
|
when Struct
|
581
688
|
vars = obj.members.map{|m|
|
@@ -607,32 +714,121 @@ module DEBUGGER__
|
|
607
714
|
event! :dap_result, :variable, req, variables: (vars || []), tid: self.id
|
608
715
|
|
609
716
|
when :evaluate
|
610
|
-
fid, expr = args
|
611
|
-
frame =
|
717
|
+
fid, expr, context = args
|
718
|
+
frame = get_frame(fid)
|
719
|
+
message = nil
|
612
720
|
|
613
|
-
if frame && (b = frame.
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
721
|
+
if frame && (b = frame.eval_binding)
|
722
|
+
special_local_variables frame do |name, var|
|
723
|
+
b.local_variable_set(name, var) if /\%/ !~ name
|
724
|
+
end
|
725
|
+
|
726
|
+
case context
|
727
|
+
when 'repl', 'watch'
|
728
|
+
begin
|
729
|
+
result = b.eval(expr.to_s, '(DEBUG CONSOLE)')
|
730
|
+
rescue Exception => e
|
731
|
+
result = e
|
732
|
+
end
|
733
|
+
|
734
|
+
when 'hover'
|
735
|
+
case expr
|
736
|
+
when /\A\@\S/
|
737
|
+
begin
|
738
|
+
result = b.receiver.instance_variable_get(expr)
|
739
|
+
rescue NameError
|
740
|
+
message = "Error: Not defined instance variable: #{expr.inspect}"
|
741
|
+
end
|
742
|
+
when /\A\$\S/
|
743
|
+
global_variables.each{|gvar|
|
744
|
+
if gvar.to_s == expr
|
745
|
+
result = eval(gvar.to_s)
|
746
|
+
break false
|
747
|
+
end
|
748
|
+
} and (message = "Error: Not defined global variable: #{expr.inspect}")
|
749
|
+
when /(\A((::[A-Z]|[A-Z])\w*)+)/
|
750
|
+
unless result = search_const(b, $1)
|
751
|
+
message = "Error: Not defined constants: #{expr.inspect}"
|
752
|
+
end
|
753
|
+
else
|
754
|
+
begin
|
755
|
+
result = b.local_variable_get(expr)
|
756
|
+
rescue NameError
|
757
|
+
# try to check method
|
758
|
+
if b.receiver.respond_to? expr, include_all: true
|
759
|
+
result = b.receiver.method(expr)
|
760
|
+
else
|
761
|
+
message = "Error: Can not evaluate: #{expr.inspect}"
|
762
|
+
end
|
763
|
+
end
|
764
|
+
end
|
765
|
+
else
|
766
|
+
message = "Error: unknown context: #{context}"
|
618
767
|
end
|
619
768
|
else
|
620
|
-
result = '
|
769
|
+
result = 'Error: Can not evaluate on this frame'
|
770
|
+
end
|
771
|
+
|
772
|
+
event! :dap_result, :evaluate, req, message: message, tid: self.id, **evaluate_result(result)
|
773
|
+
|
774
|
+
when :completions
|
775
|
+
fid, text = args
|
776
|
+
frame = get_frame(fid)
|
777
|
+
|
778
|
+
if (b = frame&.binding) && word = text&.split(/[\s\{]/)&.last
|
779
|
+
words = IRB::InputCompletor::retrieve_completion_data(word, bind: b).compact
|
621
780
|
end
|
622
|
-
|
781
|
+
|
782
|
+
event! :dap_result, :completions, req, targets: (words || []).map{|phrase|
|
783
|
+
if /\b([_a-zA-Z]\w*[!\?]?)\z/ =~ phrase
|
784
|
+
w = $1
|
785
|
+
else
|
786
|
+
w = phrase
|
787
|
+
end
|
788
|
+
|
789
|
+
begin
|
790
|
+
v = b.local_variable_get(w)
|
791
|
+
phrase += " (variable:#{DEBUGGER__.safe_inspect(v)})"
|
792
|
+
rescue NameError
|
793
|
+
end
|
794
|
+
|
795
|
+
{
|
796
|
+
label: phrase,
|
797
|
+
text: w,
|
798
|
+
}
|
799
|
+
}
|
800
|
+
|
623
801
|
else
|
624
802
|
raise "Unknown req: #{args.inspect}"
|
625
803
|
end
|
626
804
|
end
|
627
805
|
|
806
|
+
def search_const b, expr
|
807
|
+
cs = expr.delete_prefix('::').split('::')
|
808
|
+
[Object, *b.eval('Module.nesting')].reverse_each{|mod|
|
809
|
+
if cs.all?{|c|
|
810
|
+
if mod.const_defined?(c)
|
811
|
+
mod = mod.const_get(c)
|
812
|
+
else
|
813
|
+
false
|
814
|
+
end
|
815
|
+
}
|
816
|
+
# if-body
|
817
|
+
return mod
|
818
|
+
end
|
819
|
+
}
|
820
|
+
false
|
821
|
+
end
|
822
|
+
|
628
823
|
def evaluate_result r
|
629
824
|
v = variable nil, r
|
630
|
-
v.delete
|
631
|
-
v
|
825
|
+
v.delete :name
|
826
|
+
v.delete :value
|
827
|
+
v[:result] = DEBUGGER__.safe_inspect(r)
|
632
828
|
v
|
633
829
|
end
|
634
830
|
|
635
|
-
def variable_ name, obj, indexedVariables: 0, namedVariables: 0
|
831
|
+
def variable_ name, obj, indexedVariables: 0, namedVariables: 0
|
636
832
|
if indexedVariables > 0 || namedVariables > 0
|
637
833
|
vid = @var_map.size + 1
|
638
834
|
@var_map[vid] = obj
|
@@ -643,7 +839,7 @@ module DEBUGGER__
|
|
643
839
|
ivnum = obj.instance_variables.size
|
644
840
|
|
645
841
|
{ name: name,
|
646
|
-
value: DEBUGGER__.
|
842
|
+
value: DEBUGGER__.safe_inspect(obj),
|
647
843
|
type: obj.class.name || obj.class.to_s,
|
648
844
|
variablesReference: vid,
|
649
845
|
indexedVariables: indexedVariables,
|
@@ -658,7 +854,7 @@ module DEBUGGER__
|
|
658
854
|
when Hash
|
659
855
|
variable_ name, obj, namedVariables: obj.size
|
660
856
|
when String
|
661
|
-
variable_ name, obj,
|
857
|
+
variable_ name, obj, namedVariables: 3 # #to_str, #length, #encoding
|
662
858
|
when Struct
|
663
859
|
variable_ name, obj, namedVariables: obj.size
|
664
860
|
when Class, Module
|