debug 1.0.0.beta2 → 1.0.0.beta7
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/.github/workflows/ruby.yml +34 -0
- data/.gitignore +3 -0
- data/CONTRIBUTING.md +336 -0
- data/Gemfile +2 -2
- data/README.md +190 -73
- data/TODO.md +27 -0
- data/bin/gentest +22 -0
- data/debug.gemspec +2 -0
- data/exe/rdbg +14 -11
- data/ext/debug/debug.c +10 -9
- data/lib/debug.rb +4 -1
- data/lib/debug/breakpoint.rb +110 -45
- data/lib/debug/client.rb +55 -13
- data/lib/debug/color.rb +76 -0
- data/lib/debug/config.rb +157 -33
- data/lib/debug/console.rb +26 -2
- data/lib/debug/frame_info.rb +145 -0
- data/lib/debug/open.rb +3 -0
- data/lib/debug/run.rb +4 -1
- data/lib/debug/server.rb +103 -50
- data/lib/debug/server_dap.rb +607 -0
- data/lib/debug/session.rb +534 -169
- data/lib/debug/source_repository.rb +64 -12
- data/lib/debug/thread_client.rb +211 -126
- data/lib/debug/version.rb +3 -1
- data/misc/README.md.erb +95 -47
- metadata +24 -3
@@ -1,27 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'color'
|
4
|
+
|
1
5
|
module DEBUGGER__
|
2
6
|
class SourceRepository
|
7
|
+
SrcInfo = Struct.new(:src, :colored)
|
8
|
+
|
3
9
|
def initialize
|
4
|
-
@files = {} # filename =>
|
10
|
+
@files = {} # filename => SrcInfo
|
5
11
|
end
|
6
12
|
|
7
13
|
def add iseq, src
|
8
|
-
path = iseq.absolute_path
|
9
|
-
|
14
|
+
if (path = iseq.absolute_path) && File.exist?(path)
|
15
|
+
add_path path
|
16
|
+
elsif src
|
17
|
+
add_iseq iseq, src
|
18
|
+
end
|
19
|
+
end
|
10
20
|
|
11
|
-
|
12
|
-
|
21
|
+
def all_iseq iseq, rs = []
|
22
|
+
rs << iseq
|
23
|
+
iseq.each_child{|ci|
|
24
|
+
all_iseq(ci, rs)
|
25
|
+
}
|
26
|
+
rs
|
27
|
+
end
|
28
|
+
|
29
|
+
private def add_iseq iseq, src
|
30
|
+
line = iseq.first_line
|
31
|
+
if line > 1
|
32
|
+
src = ("\n" * (line - 1)) + src
|
33
|
+
end
|
34
|
+
si = SrcInfo.new(src.lines)
|
35
|
+
|
36
|
+
all_iseq(iseq).each{|e|
|
37
|
+
e.instance_variable_set(:@debugger_si, si)
|
38
|
+
e.freeze
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
private def add_path path
|
43
|
+
begin
|
13
44
|
src = File.read(path)
|
14
|
-
|
15
|
-
path =
|
16
|
-
|
17
|
-
src = nil
|
45
|
+
src = src.gsub("\r\n", "\n") # CRLF -> LF
|
46
|
+
@files[path] = SrcInfo.new(src.lines)
|
47
|
+
rescue SystemCallError
|
18
48
|
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private def get_si iseq
|
52
|
+
return unless iseq
|
19
53
|
|
20
|
-
|
54
|
+
if iseq.instance_variable_defined?(:@debugger_si)
|
55
|
+
iseq.instance_variable_get(:@debugger_si)
|
56
|
+
elsif @files.has_key?(path = iseq.absolute_path)
|
57
|
+
@files[path]
|
58
|
+
elsif path
|
59
|
+
add_path(path)
|
60
|
+
end
|
21
61
|
end
|
22
62
|
|
23
|
-
def get
|
24
|
-
|
63
|
+
def get iseq
|
64
|
+
if si = get_si(iseq)
|
65
|
+
si.src
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
include Color
|
70
|
+
|
71
|
+
def get_colored iseq
|
72
|
+
if si = get_si(iseq)
|
73
|
+
si.colored || begin
|
74
|
+
si.colored = colorize_code(si.src.join).lines
|
75
|
+
end
|
76
|
+
end
|
25
77
|
end
|
26
78
|
end
|
27
79
|
end
|
data/lib/debug/thread_client.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'objspace'
|
2
4
|
require 'pp'
|
3
5
|
|
6
|
+
require_relative 'frame_info'
|
7
|
+
require_relative 'color'
|
8
|
+
|
4
9
|
module DEBUGGER__
|
5
10
|
class ThreadClient
|
6
11
|
def self.current
|
@@ -10,18 +15,73 @@ module DEBUGGER__
|
|
10
15
|
end
|
11
16
|
end
|
12
17
|
|
18
|
+
include Color
|
19
|
+
|
13
20
|
attr_reader :location, :thread, :mode, :id
|
14
21
|
|
22
|
+
def assemble_arguments(args)
|
23
|
+
args.map do |arg|
|
24
|
+
"#{colorize_cyan(arg[:name])}=#{arg[:value]}"
|
25
|
+
end.join(", ")
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_frame_formatter frame
|
29
|
+
call_identifier_str =
|
30
|
+
case frame.frame_type
|
31
|
+
when :block
|
32
|
+
level, block_loc, args = frame.block_identifier
|
33
|
+
|
34
|
+
if !args.empty?
|
35
|
+
args_str = " {|#{assemble_arguments(args)}|}"
|
36
|
+
end
|
37
|
+
|
38
|
+
"#{colorize_blue("block")}#{args_str} in #{colorize_blue(block_loc + level)}"
|
39
|
+
when :method
|
40
|
+
ci, args = frame.method_identifier
|
41
|
+
|
42
|
+
if !args.empty?
|
43
|
+
args_str = "(#{assemble_arguments(args)})"
|
44
|
+
end
|
45
|
+
|
46
|
+
"#{colorize_blue(ci)}#{args_str}"
|
47
|
+
when :c
|
48
|
+
colorize_blue(frame.c_identifier)
|
49
|
+
when :other
|
50
|
+
colorize_blue(frame.other_identifier)
|
51
|
+
end
|
52
|
+
|
53
|
+
location_str = colorize(frame.location_str, [:GREEN])
|
54
|
+
result = "#{call_identifier_str} at #{location_str}"
|
55
|
+
|
56
|
+
if return_str = frame.return_str
|
57
|
+
return_str = colorize(frame.return_str, [:MAGENTA, :BOLD])
|
58
|
+
result += " #=> #{return_str}"
|
59
|
+
end
|
60
|
+
|
61
|
+
result
|
62
|
+
end
|
63
|
+
|
15
64
|
def initialize id, q_evt, q_cmd, thr = Thread.current
|
16
65
|
@id = id
|
17
66
|
@thread = thr
|
67
|
+
@target_frames = nil
|
18
68
|
@q_evt = q_evt
|
19
69
|
@q_cmd = q_cmd
|
20
70
|
@step_tp = nil
|
21
71
|
@output = []
|
22
|
-
@
|
23
|
-
@
|
72
|
+
@frame_formatter = method(:default_frame_formatter)
|
73
|
+
@var_map = {} # { thread_local_var_id => obj } for DAP
|
24
74
|
set_mode nil
|
75
|
+
|
76
|
+
::DEBUGGER__.info("Thread \##{@id} is created.")
|
77
|
+
end
|
78
|
+
|
79
|
+
def name
|
80
|
+
"##{@id} #{@thread.name || @thread.backtrace.last}"
|
81
|
+
end
|
82
|
+
|
83
|
+
def close
|
84
|
+
@q_cmd.close
|
25
85
|
end
|
26
86
|
|
27
87
|
def inspect
|
@@ -43,8 +103,14 @@ module DEBUGGER__
|
|
43
103
|
@q_cmd << req
|
44
104
|
end
|
45
105
|
|
106
|
+
def generate_info
|
107
|
+
return unless current_frame
|
108
|
+
|
109
|
+
{ location: current_frame.location_str, line: current_frame.location.lineno }
|
110
|
+
end
|
111
|
+
|
46
112
|
def event! ev, *args
|
47
|
-
@q_evt << [self, @output, ev, *args]
|
113
|
+
@q_evt << [self, @output, ev, generate_info, *args]
|
48
114
|
@output = []
|
49
115
|
end
|
50
116
|
|
@@ -72,6 +138,11 @@ module DEBUGGER__
|
|
72
138
|
wait_next_action
|
73
139
|
end
|
74
140
|
|
141
|
+
def on_init name
|
142
|
+
event! :init, name
|
143
|
+
wait_next_action
|
144
|
+
end
|
145
|
+
|
75
146
|
def on_breakpoint tp, bp
|
76
147
|
on_suspend tp.event, tp, bp: bp
|
77
148
|
end
|
@@ -88,11 +159,16 @@ module DEBUGGER__
|
|
88
159
|
cf.has_return_value = true
|
89
160
|
cf.return_value = tp.return_value
|
90
161
|
end
|
162
|
+
|
163
|
+
if CatchBreakpoint === bp
|
164
|
+
cf.has_raised_exception = true
|
165
|
+
cf.raised_exception = bp.last_exc
|
166
|
+
end
|
91
167
|
end
|
92
168
|
|
93
169
|
if event != :pause
|
94
|
-
show_src max_lines:
|
95
|
-
show_frames
|
170
|
+
show_src max_lines: (::DEBUGGER__::CONFIG[:show_src_lines] || 10)
|
171
|
+
show_frames ::DEBUGGER__::CONFIG[:show_frames] || 2
|
96
172
|
|
97
173
|
if bp
|
98
174
|
event! :suspend, :breakpoint, bp.key
|
@@ -125,6 +201,8 @@ module DEBUGGER__
|
|
125
201
|
next if SESSION.break? tp.path, tp.lineno
|
126
202
|
next if !yield
|
127
203
|
next if tp.path.start_with?(__dir__)
|
204
|
+
next unless File.exist?(tp.path) if ::DEBUGGER__::CONFIG[:skip_nosrc]
|
205
|
+
|
128
206
|
tp.disable
|
129
207
|
on_suspend tp.event, tp
|
130
208
|
}
|
@@ -134,6 +212,8 @@ module DEBUGGER__
|
|
134
212
|
next if thread != Thread.current
|
135
213
|
next if SESSION.break? tp.path, tp.lineno
|
136
214
|
next if !yield
|
215
|
+
next unless File.exist?(tp.path) if ::DEBUGGER__::CONFIG[:skip_nosrc]
|
216
|
+
|
137
217
|
tp.disable
|
138
218
|
on_suspend tp.event, tp
|
139
219
|
}
|
@@ -149,23 +229,14 @@ module DEBUGGER__
|
|
149
229
|
end
|
150
230
|
end
|
151
231
|
|
152
|
-
def file_lines path
|
153
|
-
if (src_lines = SESSION.source(path))
|
154
|
-
src_lines
|
155
|
-
elsif File.exist?(path)
|
156
|
-
File.readlines(path)
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
232
|
def show_src(frame_index: @current_frame_index,
|
161
233
|
update_line: false,
|
162
234
|
max_lines: 10,
|
163
235
|
start_line: nil,
|
164
236
|
end_line: nil,
|
165
237
|
dir: +1)
|
166
|
-
#
|
167
238
|
if @target_frames && frame = @target_frames[frame_index]
|
168
|
-
if file_lines =
|
239
|
+
if file_lines = frame.file_lines
|
169
240
|
frame_line = frame.location.lineno - 1
|
170
241
|
|
171
242
|
lines = file_lines.map.with_index do |e, i|
|
@@ -197,18 +268,24 @@ module DEBUGGER__
|
|
197
268
|
frame.show_line = end_line
|
198
269
|
end
|
199
270
|
|
200
|
-
if start_line != end_line
|
201
|
-
puts "[#{start_line+1}, #{end_line}] in #{
|
271
|
+
if start_line != end_line && max_lines
|
272
|
+
puts "[#{start_line+1}, #{end_line}] in #{frame.pretty_path}" if !update_line && max_lines != 1
|
202
273
|
puts lines[start_line ... end_line]
|
203
274
|
end
|
275
|
+
else # no file lines
|
276
|
+
puts "# No sourcefile available for #{frame.path}"
|
204
277
|
end
|
205
278
|
end
|
279
|
+
rescue Exception => e
|
280
|
+
p e
|
281
|
+
pp e.backtrace
|
282
|
+
exit!
|
206
283
|
end
|
207
284
|
|
208
285
|
def show_by_editor path = nil
|
209
286
|
unless path
|
210
287
|
if @target_frames && frame = @target_frames[@current_frame_index]
|
211
|
-
path = frame.
|
288
|
+
path = frame.path
|
212
289
|
else
|
213
290
|
return # can't get path
|
214
291
|
end
|
@@ -227,16 +304,39 @@ module DEBUGGER__
|
|
227
304
|
end
|
228
305
|
end
|
229
306
|
|
307
|
+
def puts_variable_info label, obj
|
308
|
+
info = "#{colorize_cyan(label)} => #{colored_inspect(obj)}".lines
|
309
|
+
w = SESSION.width
|
310
|
+
max_inspect_lines = CONFIG[:show_inspect_lines] || 10
|
311
|
+
|
312
|
+
if (max_inspect_lines > 0 && (info.size > max_inspect_lines)) || info.any?{|l| l.size > w}
|
313
|
+
info = "#{colorize_cyan(label)} => #{colored_inspect(obj, no_color: true)}".lines
|
314
|
+
if max_inspect_lines > 0 && info.size > max_inspect_lines
|
315
|
+
info = info.first(max_inspect_lines - 2) +
|
316
|
+
["...(#{info.size - (max_inspect_lines - 1)} lines)\n" + info.last]
|
317
|
+
end
|
318
|
+
info.map!{|l|
|
319
|
+
l.length > w ? l[0..(w-4)] + '...' : l
|
320
|
+
}
|
321
|
+
end
|
322
|
+
|
323
|
+
puts info
|
324
|
+
end
|
325
|
+
|
230
326
|
def show_locals
|
231
327
|
if s = current_frame&.self
|
232
|
-
|
328
|
+
puts_variable_info '%self', s
|
233
329
|
end
|
234
330
|
if current_frame&.has_return_value
|
235
|
-
|
331
|
+
puts_variable_info '%return', current_frame.return_value
|
332
|
+
end
|
333
|
+
if current_frame&.has_raised_exception
|
334
|
+
puts_variable_info "%raised", current_frame.raised_exception
|
236
335
|
end
|
237
336
|
if b = current_frame&.binding
|
238
337
|
b.local_variables.each{|loc|
|
239
|
-
|
338
|
+
value = b.local_variable_get(loc)
|
339
|
+
puts_variable_info loc, value
|
240
340
|
}
|
241
341
|
end
|
242
342
|
end
|
@@ -244,22 +344,27 @@ module DEBUGGER__
|
|
244
344
|
def show_ivars
|
245
345
|
if s = current_frame&.self
|
246
346
|
s.instance_variables.each{|iv|
|
247
|
-
|
347
|
+
value = s.instance_variable_get(iv)
|
348
|
+
puts_variable_info iv, value
|
248
349
|
}
|
249
350
|
end
|
250
351
|
end
|
251
352
|
|
353
|
+
def instance_eval_for_cmethod frame_self, src
|
354
|
+
frame_self.instance_eval(src)
|
355
|
+
end
|
356
|
+
|
252
357
|
def frame_eval src, re_raise: false
|
253
358
|
begin
|
254
359
|
@success_last_eval = false
|
255
360
|
|
256
361
|
b = current_frame.binding
|
257
362
|
result = if b
|
258
|
-
f,
|
363
|
+
f, _l = b.source_location
|
259
364
|
b.eval(src, "(rdbg)/#{f}")
|
260
365
|
else
|
261
366
|
frame_self = current_frame.self
|
262
|
-
frame_self
|
367
|
+
instance_eval_for_cmethod(frame_self, src)
|
263
368
|
end
|
264
369
|
@success_last_eval = true
|
265
370
|
result
|
@@ -277,81 +382,37 @@ module DEBUGGER__
|
|
277
382
|
end
|
278
383
|
end
|
279
384
|
|
280
|
-
def
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
def short_inspect obj
|
302
|
-
str = obj.inspect
|
303
|
-
if str.length > SHORT_INSPECT_LENGTH
|
304
|
-
str[0...SHORT_INSPECT_LENGTH] + '...'
|
305
|
-
else
|
306
|
-
str
|
307
|
-
end
|
308
|
-
end
|
309
|
-
|
310
|
-
def frame_str i
|
311
|
-
buff = ''.dup
|
312
|
-
frame = @target_frames[i]
|
313
|
-
b = frame.binding
|
314
|
-
|
315
|
-
buff << (@current_frame_index == i ? '--> ' : ' ')
|
316
|
-
if b
|
317
|
-
buff << "##{i}\t#{frame.location}"
|
318
|
-
else
|
319
|
-
buff << "##{i}\t[C] #{frame.location}"
|
320
|
-
end
|
321
|
-
|
322
|
-
if b && (iseq = frame.iseq)
|
323
|
-
if iseq.type == :block
|
324
|
-
if (argc = iseq.argc) > 0
|
325
|
-
args = parameters_info b, iseq.locals[0...argc]
|
326
|
-
buff << " {|#{args}|}"
|
327
|
-
end
|
328
|
-
else
|
329
|
-
if (callee = b.eval('__callee__', __FILE__, __LINE__)) && (argc = iseq.argc) > 0
|
330
|
-
args = parameters_info b, iseq.locals[0...argc]
|
331
|
-
ksig = klass_sig frame
|
332
|
-
buff << " #{ksig}#{callee}(#{args})"
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
if frame.has_return_value
|
337
|
-
buff << " #=> #{short_inspect(frame.return_value)}"
|
338
|
-
end
|
339
|
-
else
|
340
|
-
# p frame.self
|
341
|
-
end
|
385
|
+
def frame_str(i, frame: @target_frames[i])
|
386
|
+
cur_str = (@current_frame_index == i ? '=>' : ' ')
|
387
|
+
prefix = "#{cur_str}##{i}"
|
388
|
+
frame_string = @frame_formatter.call(frame)
|
389
|
+
"#{prefix}\t#{frame_string}"
|
390
|
+
end
|
391
|
+
|
392
|
+
def show_frames max = nil, pattern = nil
|
393
|
+
if @target_frames && (max ||= @target_frames.size) > 0
|
394
|
+
frames = []
|
395
|
+
@target_frames.each_with_index{|f, i|
|
396
|
+
next if pattern && !(f.name.match?(pattern) || f.location_str.match?(pattern))
|
397
|
+
next if CONFIG[:skip_path] && CONFIG[:skip_path].any?{|pat|
|
398
|
+
case pat
|
399
|
+
when String
|
400
|
+
f.location_str.start_with?(pat)
|
401
|
+
when Regexp
|
402
|
+
f.location_str.match?(pat)
|
403
|
+
end
|
404
|
+
}
|
342
405
|
|
343
|
-
|
344
|
-
|
406
|
+
frames << [i, f]
|
407
|
+
}
|
345
408
|
|
346
|
-
|
347
|
-
if max > 0 && frames = @target_frames
|
348
|
-
size = @target_frames.size
|
349
|
-
max += 1 if size == max + 1
|
409
|
+
size = frames.size
|
350
410
|
max.times{|i|
|
351
|
-
break
|
352
|
-
|
411
|
+
break unless frames[i]
|
412
|
+
index, frame = frames[i]
|
413
|
+
puts frame_str(index, frame: frame)
|
353
414
|
}
|
354
|
-
puts "
|
415
|
+
puts " # and #{size - max} frames (use `bt' command for all frames)" if max < size
|
355
416
|
end
|
356
417
|
end
|
357
418
|
|
@@ -377,18 +438,22 @@ module DEBUGGER__
|
|
377
438
|
end
|
378
439
|
end
|
379
440
|
|
380
|
-
def
|
441
|
+
def make_breakpoint args
|
381
442
|
case args.first
|
382
443
|
when :method
|
383
|
-
klass_name, op, method_name, cond = args[1..]
|
384
|
-
bp = MethodBreakpoint.new(current_frame.binding, klass_name, op, method_name, cond)
|
444
|
+
klass_name, op, method_name, cond, cmd = args[1..]
|
445
|
+
bp = MethodBreakpoint.new(current_frame.binding, klass_name, op, method_name, cond, command: cmd)
|
385
446
|
begin
|
386
447
|
bp.enable
|
387
448
|
rescue Exception => e
|
388
449
|
puts e.message
|
389
450
|
::DEBUGGER__::METHOD_ADDED_TRACKER.enable
|
390
451
|
end
|
391
|
-
|
452
|
+
|
453
|
+
bp
|
454
|
+
when :watch
|
455
|
+
ivar, object, result = args[1..]
|
456
|
+
WatchIVarBreakpoint.new(ivar, object, result)
|
392
457
|
else
|
393
458
|
raise "unknown breakpoint: #{args}"
|
394
459
|
end
|
@@ -401,6 +466,8 @@ module DEBUGGER__
|
|
401
466
|
def wait_next_action
|
402
467
|
set_mode :wait_next_action
|
403
468
|
|
469
|
+
SESSION.check_forked
|
470
|
+
|
404
471
|
while cmds = @q_cmd.pop
|
405
472
|
# pp [self, cmds: cmds]
|
406
473
|
|
@@ -416,22 +483,30 @@ module DEBUGGER__
|
|
416
483
|
step_tp{true}
|
417
484
|
when :next
|
418
485
|
frame = @target_frames.first
|
419
|
-
path = frame.location.absolute_path || "!eval:#{frame.
|
486
|
+
path = frame.location.absolute_path || "!eval:#{frame.path}"
|
420
487
|
line = frame.location.lineno
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
next_line =
|
488
|
+
|
489
|
+
if frame.iseq
|
490
|
+
frame.iseq.traceable_lines_norec(lines = {})
|
491
|
+
next_line = lines.keys.bsearch{|e| e > line}
|
492
|
+
if !next_line && (last_line = frame.iseq.last_line) > line
|
493
|
+
next_line = last_line
|
494
|
+
end
|
425
495
|
end
|
496
|
+
|
426
497
|
depth = @target_frames.first.frame_depth
|
427
498
|
|
428
499
|
step_tp{
|
429
500
|
loc = caller_locations(2, 1).first
|
430
501
|
loc_path = loc.absolute_path || "!eval:#{loc.path}"
|
431
502
|
|
503
|
+
# same stack depth
|
504
|
+
(DEBUGGER__.frame_depth - 3 <= depth) ||
|
505
|
+
|
506
|
+
# different frame
|
432
507
|
(next_line && loc_path == path &&
|
433
|
-
|
434
|
-
|
508
|
+
(loc_lineno = loc.lineno) > line &&
|
509
|
+
loc_lineno <= next_line)
|
435
510
|
}
|
436
511
|
when :finish
|
437
512
|
depth = @target_frames.first.frame_depth
|
@@ -446,20 +521,16 @@ module DEBUGGER__
|
|
446
521
|
when :eval
|
447
522
|
eval_type, eval_src = *args
|
448
523
|
|
449
|
-
case eval_type
|
450
|
-
when :display, :try_display
|
451
|
-
else
|
452
|
-
result = frame_eval(eval_src)
|
453
|
-
end
|
454
524
|
result_type = nil
|
455
525
|
|
456
526
|
case eval_type
|
457
527
|
when :p
|
528
|
+
result = frame_eval(eval_src)
|
458
529
|
puts "=> " + result.inspect
|
459
530
|
when :pp
|
531
|
+
result = frame_eval(eval_src)
|
460
532
|
puts "=> "
|
461
|
-
|
462
|
-
puts out
|
533
|
+
puts color_pp(result, SESSION.width)
|
463
534
|
when :call
|
464
535
|
result = frame_eval(eval_src)
|
465
536
|
when :display, :try_display
|
@@ -474,14 +545,6 @@ module DEBUGGER__
|
|
474
545
|
|
475
546
|
result_type = eval_type
|
476
547
|
result = failed_results
|
477
|
-
when :watch
|
478
|
-
if @success_last_eval
|
479
|
-
puts "#{eval_src} = #{result}"
|
480
|
-
result = WatchExprBreakpoint.new(eval_src, result)
|
481
|
-
result_type = :watch
|
482
|
-
else
|
483
|
-
result = nil
|
484
|
-
end
|
485
548
|
else
|
486
549
|
raise "unknown error option: #{args.inspect}"
|
487
550
|
end
|
@@ -492,7 +555,7 @@ module DEBUGGER__
|
|
492
555
|
case type
|
493
556
|
when :up
|
494
557
|
if @current_frame_index + 1 < @target_frames.size
|
495
|
-
@current_frame_index += 1
|
558
|
+
@current_frame_index += 1
|
496
559
|
show_src max_lines: 1
|
497
560
|
show_frame(@current_frame_index)
|
498
561
|
end
|
@@ -522,7 +585,8 @@ module DEBUGGER__
|
|
522
585
|
|
523
586
|
case type
|
524
587
|
when :backtrace
|
525
|
-
|
588
|
+
max_lines, pattern = *args
|
589
|
+
show_frames max_lines, pattern
|
526
590
|
|
527
591
|
when :list
|
528
592
|
show_src(update_line: true, **(args.first || {}))
|
@@ -544,9 +608,30 @@ module DEBUGGER__
|
|
544
608
|
end
|
545
609
|
|
546
610
|
event! :result, nil
|
547
|
-
|
548
611
|
when :breakpoint
|
549
|
-
|
612
|
+
case args[0]
|
613
|
+
when :method
|
614
|
+
bp = make_breakpoint args
|
615
|
+
event! :result, :method_breakpoint, bp
|
616
|
+
when :watch
|
617
|
+
ivar = args[1]
|
618
|
+
result = frame_eval(ivar)
|
619
|
+
|
620
|
+
if @success_last_eval
|
621
|
+
object =
|
622
|
+
if b = current_frame.binding
|
623
|
+
b.receiver
|
624
|
+
else
|
625
|
+
current_frame.self
|
626
|
+
end
|
627
|
+
bp = make_breakpoint [:watch, ivar, object, result]
|
628
|
+
event! :result, :watch_breakpoint, bp
|
629
|
+
else
|
630
|
+
event! :result, nil
|
631
|
+
end
|
632
|
+
end
|
633
|
+
when :dap
|
634
|
+
process_dap args
|
550
635
|
else
|
551
636
|
raise [cmd, *args].inspect
|
552
637
|
end
|
@@ -555,7 +640,7 @@ module DEBUGGER__
|
|
555
640
|
rescue SystemExit
|
556
641
|
raise
|
557
642
|
rescue Exception => e
|
558
|
-
pp [__FILE__
|
643
|
+
pp ["DEBUGGER Exception: #{__FILE__}:#{__LINE__}", e, e.backtrace]
|
559
644
|
raise
|
560
645
|
ensure
|
561
646
|
set_mode nil
|