Skip to content

Commit 8b61c09

Browse files
lukaszsamsonscohen
andauthored
Return type of breakpoint that was hit as required by DAP (#850)
* Return type of breakpoint that was hit as required by DAP consistently set breakpoints in tests with absolute path as VSCode does add tests covering allThreadsContinued add tests covering stepIn, stepOut, next * Update apps/elixir_ls_debugger/lib/debugger/server.ex Co-authored-by: Steve Cohen <scohen@scohen.org> * keep function breakpoints in a map --------- Co-authored-by: Steve Cohen <scohen@scohen.org>
1 parent 6f2f071 commit 8b61c09

File tree

3 files changed

+345
-79
lines changed

3 files changed

+345
-79
lines changed

apps/elixir_ls_debugger/lib/debugger/server.ex

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ defmodule ElixirLS.Debugger.Server do
4848
next_id: 1,
4949
output: Output,
5050
breakpoints: %{},
51-
function_breakpoints: []
51+
function_breakpoints: %{}
5252

5353
defmodule PausedProcess do
5454
defstruct stack: nil,
@@ -137,18 +137,7 @@ defmodule ElixirLS.Debugger.Server do
137137
paused_process = %PausedProcess{stack: Stacktrace.get(pid), ref: ref}
138138
state = put_in(state.paused_processes[pid], paused_process)
139139

140-
reason =
141-
case event do
142-
:breakpoint_reached ->
143-
# Debugger Adapter Protocol requires us to return 'step' | 'breakpoint' | 'exception' | 'pause' | 'entry' | 'goto'
144-
# | 'function breakpoint' | 'data breakpoint' | 'instruction breakpoint'
145-
# but we can't tell what kind of a breakpoint was hit
146-
"breakpoint"
147-
148-
:paused ->
149-
"pause"
150-
end
151-
140+
reason = get_stop_reason(state, event, paused_process.stack)
152141
body = %{"reason" => reason, "threadId" => thread_id, "allThreadsStopped" => false}
153142
Output.send_event("stopped", body)
154143
state
@@ -272,6 +261,7 @@ defmodule ElixirLS.Debugger.Server do
272261
set_breakpoints_req(_, %{"path" => path}, breakpoints),
273262
state = %__MODULE__{}
274263
) do
264+
path = Path.absname(path)
275265
new_lines = for %{"line" => line} <- breakpoints, do: line
276266

277267
new_conditions =
@@ -332,7 +322,7 @@ defmodule ElixirLS.Debugger.Server do
332322
end
333323
end
334324

335-
current = state.function_breakpoints |> Map.new()
325+
current = state.function_breakpoints
336326

337327
results =
338328
for {{m, f, a}, {condition, hit_count}} <- parsed_mfas_conditions,
@@ -368,7 +358,7 @@ defmodule ElixirLS.Debugger.Server do
368358
{{m, f, a}, result}
369359
)
370360

371-
successful = for {mfa, {:ok, lines}} <- results, do: {mfa, lines}
361+
successful = for {mfa, {:ok, lines}} <- results, into: %{}, do: {mfa, lines}
372362

373363
state = %{
374364
state
@@ -1345,4 +1335,27 @@ defmodule ElixirLS.Debugger.Server do
13451335
ref = Process.send_after(self(), :update_threads, 3000)
13461336
%__MODULE__{state | update_threads_ref: ref}
13471337
end
1338+
1339+
# Debugger Adapter Protocol stop reasons 'step' | 'breakpoint' | 'exception' | 'pause' | 'entry' | 'goto'
1340+
# | 'function breakpoint' | 'data breakpoint' | 'instruction breakpoint'
1341+
defp get_stop_reason(_state, :paused, _frames), do: "pause"
1342+
defp get_stop_reason(_state, :breakpoint_reached, []), do: "breakpoint"
1343+
1344+
defp get_stop_reason(state = %__MODULE__{}, :breakpoint_reached, [first_frame = %Frame{} | _]) do
1345+
file_breakpoints = Map.get(state.breakpoints, first_frame.file, [])
1346+
1347+
frame_mfa = {first_frame.module, first_frame.function, length(first_frame.args)}
1348+
function_breakpoints = Map.get(state.function_breakpoints, frame_mfa, [])
1349+
1350+
cond do
1351+
{first_frame.module, first_frame.line} in file_breakpoints ->
1352+
"breakpoint"
1353+
1354+
first_frame.line in function_breakpoints ->
1355+
"function breakpoint"
1356+
1357+
true ->
1358+
"step"
1359+
end
1360+
end
13481361
end

0 commit comments

Comments
 (0)