Skip to content

Commit 15625f5

Browse files
committed
Support functional setFunctionBreakpoints command
1 parent 4b2219b commit 15625f5

4 files changed

Lines changed: 75 additions & 5 deletions

File tree

lib/debug/server_dap.rb

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,6 @@ def process
249249
end
250250
}
251251
send_response req, breakpoints: (bps.map do |bp| {verified: true,} end)
252-
when 'setFunctionBreakpoints'
253-
send_response req
254252
when 'setExceptionBreakpoints'
255253
process_filter = ->(filter_id) {
256254
case filter_id
@@ -354,7 +352,8 @@ def process
354352
'variables',
355353
'evaluate',
356354
'source',
357-
'completions'
355+
'completions',
356+
'setFunctionBreakpoints'
358357
@q_msg << req
359358

360359
else
@@ -430,6 +429,8 @@ def fail_response req, **kw
430429

431430
def process_protocol_request req
432431
case req['command']
432+
when 'setFunctionBreakpoints'
433+
@tc << [:dap, :breakpoints, req]
433434
when 'stepBack'
434435
if @tc.recorder&.can_step_back?
435436
@tc << [:step, :back]
@@ -559,6 +560,17 @@ def dap_event args
559560
end
560561
}
561562
@ui.respond req, result
563+
when :breakpoints
564+
breakpoints = result[:breakpoints].map do |bp|
565+
if bp
566+
add_bp(bp)
567+
{ verified: true, message: bp.inspect }
568+
else
569+
{ verified: false, message: nil }
570+
end
571+
end
572+
573+
@ui.respond req, breakpoints: breakpoints
562574
when :scopes
563575
frame_id = req.dig('arguments', 'frameId')
564576
local_scope = result[:scopes].first
@@ -613,6 +625,17 @@ def process_dap args
613625
req = args.shift
614626

615627
case type
628+
when :breakpoints
629+
bps = req.dig("arguments", "breakpoints")
630+
SESSION.clear_method_breakpoints
631+
632+
breakpoints = bps.map do |bp|
633+
if bp["name"]&.match(Session::METHOD_SIGNATURE_REGEXP)
634+
make_breakpoint [:method, $1, $2, $3]
635+
end
636+
end
637+
638+
event! :dap_result, :breakpoints, req, { breakpoints: breakpoints }
616639
when :backtrace
617640
event! :dap_result, :backtrace, req, {
618641
stackFrames: @target_frames.map{|frame|

lib/debug/session.rb

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,8 @@ def parse_break arg
12821282
expr
12831283
end
12841284

1285+
METHOD_SIGNATURE_REGEXP = /\A(.+)([\.\#])(.+)\z/
1286+
12851287
def repl_add_breakpoint arg
12861288
expr = parse_break arg.strip
12871289
cond = expr[:if]
@@ -1293,7 +1295,7 @@ def repl_add_breakpoint arg
12931295
add_line_breakpoint @tc.location.path, $1.to_i, cond: cond, command: cmd
12941296
when /\A(.+)[:\s+](\d+)\z/
12951297
add_line_breakpoint $1, $2.to_i, cond: cond, command: cmd
1296-
when /\A(.+)([\.\#])(.+)\z/
1298+
when METHOD_SIGNATURE_REGEXP
12971299
@tc << [:breakpoint, :method, $1, $2, $3, cond, cmd, path]
12981300
return :noretry
12991301
when nil
@@ -1324,6 +1326,12 @@ def repl_add_watch_breakpoint arg
13241326
@tc << [:breakpoint, :watch, expr[:sig], cond, cmd, path]
13251327
end
13261328

1329+
def add_method_breakpoint(method_signature)
1330+
if method_signature.match(METHOD_SIGNATURE_REGEXP)
1331+
@tc << [:breakpoint, :method, $1, $2, $3]
1332+
end
1333+
end
1334+
13271335
def add_catch_breakpoint pat
13281336
bp = CatchBreakpoint.new(pat)
13291337
add_bp bp
@@ -1343,6 +1351,14 @@ def add_line_breakpoint file, line, **kw
13431351
@ui.puts e.message
13441352
end
13451353

1354+
def clear_method_breakpoints
1355+
@bps.delete_if do |k, bp|
1356+
if bp.is_a?(MethodBreakpoint)
1357+
bp.delete
1358+
end
1359+
end
1360+
end
1361+
13461362
def clear_line_breakpoints path
13471363
path = resolve_path(path)
13481364
@bps.delete_if do |k, bp|

test/protocol/break_test.rb

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class BreakTest1 < TestCase
1616
9| end
1717
RUBY
1818

19-
def test_break_stops_at_correct_place
19+
def test_set_breakpoints_sets_line_breakpoints
2020
run_protocol_scenario PROGRAM do
2121
req_add_breakpoint 5
2222
req_continue
@@ -42,6 +42,30 @@ def test_break_stops_at_correct_place
4242
req_terminate_debuggee
4343
end
4444
end
45+
46+
def test_set_function_breakpoints_sets_method_breakpoints
47+
run_protocol_scenario PROGRAM, cdp: false do
48+
res_set_function_breakpoints([{ name: "Foo::Bar.a" }])
49+
req_continue
50+
assert_line_num 4
51+
52+
assert_locals_result(
53+
[
54+
{ name: "%self", value: "Foo::Bar", type: "Class" }
55+
]
56+
)
57+
58+
req_continue
59+
end
60+
end
61+
62+
def test_set_function_breakpoints_unsets_method_breakpoints
63+
run_protocol_scenario PROGRAM, cdp: false do
64+
res_set_function_breakpoints([{ name: "Foo::Bar.a" }])
65+
res_set_function_breakpoints([])
66+
req_continue
67+
end
68+
end
4569
end
4670

4771
class BreakTest2 < TestCase

test/support/protocol_utils.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,13 @@ def req_set_exception_breakpoints
140140
end
141141
end
142142

143+
def res_set_function_breakpoints(breakpoints)
144+
case ENV['RUBY_DEBUG_TEST_UI']
145+
when 'vscode'
146+
send_dap_request 'setFunctionBreakpoints', breakpoints: breakpoints
147+
end
148+
end
149+
143150
def req_step_back
144151
case ENV['RUBY_DEBUG_TEST_UI']
145152
when 'vscode'

0 commit comments

Comments
 (0)