Skip to content

Commit 99ab6e9

Browse files
authored
Add debugger variable scopes with messages and process info (#681)
* delete duplicated capability * add process messages as debugger variable scope * improve display of keyword variables * add process info as debugger variable scope
1 parent ba6252f commit 99ab6e9

File tree

5 files changed

+83
-10
lines changed

5 files changed

+83
-10
lines changed

apps/elixir_ls_debugger/lib/debugger/server.ex

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,9 @@ defmodule ElixirLS.Debugger.Server do
509509
{pid, %Frame{} = frame} ->
510510
{state, args_id} = ensure_var_id(state, pid, frame.args)
511511
{state, bindings_id} = ensure_var_id(state, pid, frame.bindings)
512+
{state, messages_id} = ensure_var_id(state, pid, frame.messages)
513+
process_info = Process.info(pid)
514+
{state, process_info_id} = ensure_var_id(state, pid, process_info)
512515

513516
vars_scope = %{
514517
"name" => "variables",
@@ -526,7 +529,27 @@ defmodule ElixirLS.Debugger.Server do
526529
"expensive" => false
527530
}
528531

529-
scopes = if Enum.count(frame.args) > 0, do: [vars_scope, args_scope], else: [vars_scope]
532+
messages_scope = %{
533+
"name" => "messages",
534+
"variablesReference" => messages_id,
535+
"namedVariables" => 0,
536+
"indexedVariables" => Enum.count(frame.messages),
537+
"expensive" => false
538+
}
539+
540+
process_info_scope = %{
541+
"name" => "process info",
542+
"variablesReference" => process_info_id,
543+
"namedVariables" => length(process_info),
544+
"indexedVariables" => 0,
545+
"expensive" => false
546+
}
547+
548+
scopes =
549+
[vars_scope, process_info_scope]
550+
|> Kernel.++(if Enum.count(frame.args) > 0, do: [args_scope], else: [])
551+
|> Kernel.++(if Enum.count(frame.messages) > 0, do: [messages_scope], else: [])
552+
530553
{state, scopes}
531554

532555
nil ->
@@ -1006,7 +1029,6 @@ defmodule ElixirLS.Debugger.Server do
10061029
"supportsConditionalBreakpoints" => true,
10071030
"supportsHitConditionalBreakpoints" => true,
10081031
"supportsLogPoints" => true,
1009-
"supportsEvaluateForHovers" => false,
10101032
"exceptionBreakpointFilters" => [],
10111033
"supportsStepBack" => false,
10121034
"supportsSetVariable" => false,

apps/elixir_ls_debugger/lib/debugger/stacktrace.ex

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ defmodule ElixirLS.Debugger.Stacktrace do
44
"""
55

66
defmodule Frame do
7-
defstruct [:level, :file, :module, :function, :args, :line, :bindings]
7+
defstruct [:level, :file, :module, :function, :args, :line, :bindings, :messages]
88

99
def name(%__MODULE__{} = frame) do
1010
"#{inspect(frame.module)}.#{frame.function}/#{Enum.count(frame.args)}"
@@ -17,14 +17,17 @@ defmodule ElixirLS.Debugger.Stacktrace do
1717
[{level, {module, function, args}} | backtrace_rest] =
1818
:int.meta(meta_pid, :backtrace, :all)
1919

20+
messages = :int.meta(meta_pid, :messages)
21+
2022
first_frame = %Frame{
2123
level: level,
2224
module: module,
2325
function: function,
2426
args: args,
2527
file: get_file(module),
2628
line: break_line(pid),
27-
bindings: get_bindings(meta_pid, level)
29+
bindings: get_bindings(meta_pid, level),
30+
messages: messages
2831
}
2932

3033
# If backtrace_rest is empty, calling stack_frames causes an exception
@@ -44,7 +47,8 @@ defmodule ElixirLS.Debugger.Stacktrace do
4447
args: args,
4548
file: get_file(mod),
4649
line: line,
47-
bindings: Enum.into(bindings, %{})
50+
bindings: Enum.into(bindings, %{}),
51+
messages: messages
4852
}
4953
end
5054
end

apps/elixir_ls_debugger/lib/debugger/variables.ex

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,31 @@ defmodule ElixirLS.Debugger.Variables do
77
def child_type(var) when is_map(var), do: :named
88
def child_type(var) when is_bitstring(var), do: :indexed
99
def child_type(var) when is_tuple(var), do: :indexed
10-
def child_type(var) when is_list(var), do: :indexed
10+
11+
def child_type(var) when is_list(var) do
12+
if Keyword.keyword?(var) do
13+
:named
14+
else
15+
:indexed
16+
end
17+
end
18+
1119
def child_type(_var), do: nil
1220

1321
def children(var, start, count) when is_list(var) do
1422
start = start || 0
1523
count = count || Enum.count(var)
1624

17-
var
18-
|> Enum.slice(start, count)
19-
|> with_index_as_name(start)
25+
sliced =
26+
var
27+
|> Enum.slice(start, count)
28+
29+
if Keyword.keyword?(var) do
30+
sliced
31+
else
32+
sliced
33+
|> with_index_as_name(start)
34+
end
2035
end
2136

2237
def children(var, start, count) when is_tuple(var) do
@@ -90,7 +105,14 @@ defmodule ElixirLS.Debugger.Variables do
90105
def type(var) when is_float(var), do: "float"
91106
def type(var) when is_function(var), do: "function"
92107
def type(var) when is_integer(var), do: "integer"
93-
def type(var) when is_list(var), do: "list"
108+
109+
def type(var) when is_list(var) do
110+
if Keyword.keyword?(var) and var != [] do
111+
"keyword"
112+
else
113+
"list"
114+
end
115+
end
94116

95117
def type(%name{}), do: "%#{inspect(name)}{}"
96118

apps/elixir_ls_debugger/test/debugger_test.exs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,13 @@ defmodule ElixirLS.Debugger.ServerTest do
171171
"namedVariables" => 1,
172172
"variablesReference" => vars_id
173173
},
174+
%{
175+
"expensive" => false,
176+
"indexedVariables" => 0,
177+
"name" => "process info",
178+
"namedVariables" => _,
179+
"variablesReference" => _
180+
},
174181
%{
175182
"expensive" => false,
176183
"indexedVariables" => 1,

apps/elixir_ls_debugger/test/variables_test.exs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ defmodule ElixirLS.Debugger.VariablesTest do
3939
assert Variables.type([1]) == "list"
4040
assert Variables.type('asd') == "list"
4141

42+
assert Variables.type(abc: 123) == "keyword"
43+
4244
assert Variables.type(%{}) == "map"
4345
assert Variables.type(%{asd: 123}) == "map"
4446
assert Variables.type(%{"asd" => 123}) == "map"
@@ -87,6 +89,8 @@ defmodule ElixirLS.Debugger.VariablesTest do
8789
assert Variables.num_children([1]) == 1
8890
assert Variables.num_children('asd') == 3
8991

92+
assert Variables.num_children(abc: 123) == 1
93+
9094
assert Variables.num_children(%{}) == 0
9195
assert Variables.num_children(%{asd: 123}) == 1
9296
assert Variables.num_children(%{"asd" => 123}) == 1
@@ -104,6 +108,20 @@ defmodule ElixirLS.Debugger.VariablesTest do
104108
assert Variables.children('asd', 0, 10) == [{"0", 97}, {"1", 115}, {"2", 100}]
105109
end
106110

111+
test "keyword" do
112+
assert Variables.children([abc: 123], 0, 10) == [abc: 123]
113+
114+
assert Variables.children([abc1: 121, abc2: 122, abc3: 123, abc4: 124], 0, 2) == [
115+
abc1: 121,
116+
abc2: 122
117+
]
118+
119+
assert Variables.children([abc1: 121, abc2: 122, abc3: 123, abc4: 124], 1, 2) == [
120+
abc2: 122,
121+
abc3: 123
122+
]
123+
end
124+
107125
test "tuple" do
108126
assert Variables.children({}, 0, 10) == []
109127
assert Variables.children({1}, 0, 10) == [{"0", 1}]

0 commit comments

Comments
 (0)